Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Component Unification (angle brackets) #60

Closed
wants to merge 1 commit into from

Conversation

wycats
Copy link
Member

@wycats wycats commented May 25, 2015

@rwjblue
Copy link
Member

rwjblue commented May 25, 2015

I love the direction with this, but had a few questions while reading:

  • Whitelist API for using <some-thing-as-div></some-thing-as-div>: see [Angle Brackets] Co-exist with non-Ember web components and "x-foo" named elements ember.js#11269 for an example.
  • What happens to the existing JS-land API's for these things (attributeBindings, classNameBindings, etc)? Are they additive to the marked {{root}} element? Are they ignored in angle bracket invocation?
  • Does this mean that every component must have a layout? If not, would the existing JS API's take effect?
  • Interop with current curly brace invocation semantics:
    • How can component authors handle both cases since it is up to the caller to use the "right" way?
    • Will helper methods be available to know if a given component was invoked as angle brackets vs curlies?
    • What will happen if {{root} or {{splat-attrs}} is seen when invoked via curlies?

@wycats
Copy link
Member Author

wycats commented May 25, 2015

What happens to the existing JS-land API's for these things (attributeBindings, classNameBindings, etc)? Are they additive to the marked {{root}} element? Are they ignored in angle bracket invocation?

I think they would be an error when used with angle-bracket components.

Does this mean that every component must have a layout? If not, would the existing JS API's take effect?

If you want to describe anything about the component (tags, classes, attributes), a layout is much more expressive than the JS APIs, so "must have a layout" -> "doesn't need the JS APIs" 😉

Interop with current curly brace invocation semantics:

This is the stickiest question you raised and I don't have great answers yet. To flesh it out:

If I'm a component author and I want to be compatible with 1.12/1.13 curly bracket components, 2.1 curly brace invocation, and 2.1 angle bracket invocation, how do I do that?

I don't have a good solution in mind that supports doing all of the above in the same codebase; I kind of feel like you may need to maintain a separate branch for pre-2.0 components 😦

I'm open to anything though, and would love some brainstorming here.

@rwjblue
Copy link
Member

rwjblue commented May 25, 2015

I kind of feel like you may need to maintain a separate branch for pre-2.0 components

The main issue isn't with maintaining branches for supporting different Ember versions (that may just be a fact of life in some cases), but for maintaining branches for supporting the two different invocation styles within the same Ember version.

@stefanpenner
Copy link
Member

Another point we likely need to investigate is what happens with double curly components today, that contain a slash. {{users/my-form}} is valid today, but does not translate nicely to DOM. We could transition / to : which does translate. But that assumes we don't want to use : for something else.

Also what's the order of precedence between native WebComponents and ember component lookup. I suspect ember components should take a higher precedence. But what is the strategy when a collision occurs? What tagName is used? I suspect these collisions will be frustrating to debug if we do not message and provide escape hatches.

A finally point is the proposed scoped helper/component yielding + dot syntax. As the dot form is valid, it may be an WebComponents (unless they are more limited then document.createElement)

<my-form as |f|>
  <f.input>
</my-from>

How are theoretical collisions with <f.input dealt with?

I suspect the dot versions of tags will not be used, as css rules against them get pretty gnarly

@igorT
Copy link
Member

igorT commented May 25, 2015

Does the class get overridden or do they concat when shadowed? It seems like concatting the classes would be very useful for customizing styling of the component, without having to copy all the original styles.

@jonathanKingston
Copy link
Contributor

I'm struggling to see the motivation to unifying 'element' components with 'fragment' components.

For me this adds further risks that large changes will come to the component stack when keeping them conceptually separate (perhaps unifying the code base under the hood) will alleviate the risk for change later. Separating a unified concept seems harder than unifying in my opinion.

I like the idea of:

  • Components using custom tags by default
  • Their templates not requiring the top level tag, which is specified in the template
  • The tag is injected into the DOM with the properties the template specified it with

This would remove the need for all the bindings as:

{{!-- application.hbs --}}
<my-component class="thing" other-attr="thing" />
{{!-- my-component.hbs --}}
<div>
  {{other-attr}}
</div>

Renders:

<my-component class="thing" other-attr="thing">
  <div>
    thing
  </div>
</my-component>

Partials or fragments could mop up the rest as they currently do.

This roughly relates to my attrTypes RFC too: #35 which is designed to help filter attributes passed into the component template (So template authors have to conform to a specified API). This mapping could also be responsible for attributes that don't really make much sense being visible to the DOM like actions (unless a textual alternative could be used instead like a uuid which might help with debugging).

@jonathanKingston
Copy link
Contributor

Also is it worth waiting for the slots syntax to calm down a little as I think this would likely solve the other issues here too.

For an easier migration could there be a property I could set on the components JavaScript to disable the replacement? All my components extend from a base level component so it would make a simple transition to disable this (However I would prefer the separation of fragment/partial style components to normal ones).

@wycats
Copy link
Member Author

wycats commented May 26, 2015

the slots syntax

which syntax do you have in mind?

@wycats
Copy link
Member Author

wycats commented May 26, 2015

Does the class get overridden or do they concat when shadowed?

They concat. It would make sense to concat styles too.

@jgwhite
Copy link
Contributor

jgwhite commented May 26, 2015

This shadowing only applies to attributes provided as strings in original invocation. This means that an invoker of a component can avoid shadowing any attribute by writing name={{"Yehuda"}} rather than name="Yehuda".

  • The resulting rule is very simple, and gives total control over shadowing, by default, to the invoker:

Any attribute specified as a string will be shadowed onto the root element, if one exists.

I may have missed something, but with this rule how would one bind a dynamic property to an attribute?

i.e.

<x-foo aria-label={{someComputedLabel}} />

@wycats
Copy link
Member Author

wycats commented May 26, 2015

@jgwhite simple:

<x-foo aria-label="{{someComputedLabel}}" />

@jgwhite
Copy link
Contributor

jgwhite commented May 26, 2015

@wycats ah, let me check I’ve got this straight:

foo={{bar}} ---> this.attrs.foo = bar
foo="{{bar}}" ---> this.element.foo = bar

@wycats
Copy link
Member Author

wycats commented May 26, 2015

@jgwhite both cases would assign to attrs, but string attrs would also setAttribute.

@jgwhite
Copy link
Contributor

jgwhite commented May 26, 2015

Okay cool, that makes sense. Another thing I’m not 100% clear on from the RFC:

If I want the in-DOM result of invoking:

<x-foo>Bar baz</x-foo>

to be:

<x-foo><span>Bar baz</span></x-foo>

What should x-foo.hbs look like?

@wycats
Copy link
Member Author

wycats commented May 26, 2015

@jgwhite

<x-foo><span>Bar baz</span></x-foo>

@jgwhite
Copy link
Contributor

jgwhite commented May 26, 2015

@wycats and if I wanted to recursively invoke <x-foo /> ?

@wycats
Copy link
Member Author

wycats commented May 26, 2015

@jgwhite recursive invocations always require control flow so they wont be at the top of the template.

@jgwhite
Copy link
Contributor

jgwhite commented May 26, 2015

@wycats this is making more and more sense as I reason it through.

My initial concern was that in templates like this:

{{! x-foo.hbs}}

<x-foo>
  {{yield}}
  {{#if somePredicate}}
    <x-foo>Some consequent</x-foo>
  {{/if}}
</x-foo>

The difference in behaviour between the root <x-foo> and inner <x-foo> would cause confusion. Looking at it now however, the abstraction seems solid.

@wycats
Copy link
Member Author

wycats commented May 26, 2015

@jgwhite yeah I worked through it a bunch and came to the conclusion that any plausible recursion case requires some kind of control flow in order to avoid stack overflow.

You can think of the outermost tag as the component's signature, and any inner tags as recursive calls. @tomdale thinks we should make this the default conventional approach for templates that don't explicitly require a special tag for some reason.

@jgwhite
Copy link
Contributor

jgwhite commented May 26, 2015

You can think of the outermost tag as the component's signature, and any inner tags as recursive calls.

Yeah, that’s very clear and very declarative.

@tomdale thinks we should make this the default conventional approach for templates that don't explicitly require a special tag for some reason.

Could you elaborate on this point? Do you mean that a conventional component template wouldn’t have an explicit signature element?

@jonathanKingston
Copy link
Contributor

@wycats the slots syntax as is being pushed for Shadow DOM:
https://lists.w3.org/Archives/Public/public-webapps/2015AprJun/0187.html

This appears to be what will land in browsers and I think will solve a lot of the same use cases this is solving.


I understand the merit of the duplicate tag within the template of the DOM, however personally that is a whole lot of components that need changing for something that improve only the 'partial' kind. This improvement isn't (as far as I am aware) ever going to be native to HTML. Much like services are essentially just Ember.Objects wouldn't it be safer to leave the concepts distinct but perhaps share the same code bases?

@wycats
Copy link
Member Author

wycats commented May 27, 2015

@jonathanKingston I'll reply to this more later, but fwiw, I don't think trying to map Ember's semantics very closely to hypothetical web components semantics is a winning strategy.

Web Components are still at a very early stage, and I personally think React's experience (and Ember 1.x's, for that matter), bears more heavily on the problem space than a future WC spec. If Ember and React both land on something inexpressible in WC, and it works out smashingly, that would be a good opportunity to attempt to persuade the standards process to make it expressible.

@jonathanKingston
Copy link
Contributor

@wycats My issue isn't in driving the standards development at all with extend the web forward principles. However collapsing both concepts into one before they are complete seems a little premature.

Also as far as I was aware there was consensus from major browsers on this syntax.

tomdale added a commit to emberjs/ember.js that referenced this pull request Jun 6, 2015
emberjs/rfcs#60

This commit implements the proposed semantics for angle-bracket
components. The TLDR is that a component’s template represents its
“outerHTML” rather than its “innerHTML”, which makes it easier to
configure the element itself using templating constructs.

Some salient points:

1. If there is a single root element, the attributes from the invocation
   are copied onto the root element.
2. The invocation’s attributes “win out” over the attributes from the
   root element in the component’s layout.
3. Classes are merged. If the invocation says `class=“a”` and the root
   element says `class=“b”`, the result is `class=“a b”`. The rationale
   is that when you say `class=“a”`, you are really saying “add the `a`
   class to this element”.

A few sticky issues:

1. If the root element for the `my-foo` component is `<my-foo>`, we
   insert an element with tag name of `my-foo`. While this is intuitive,
   note that in all other cases, `<my-foo>` represents an invocation of
   the component. In the root position, that makes no sense, since it
   would inevitably produce a stack overflow.
   a. This “identity element” case makes it idiomatic to reflect the
      name of the component onto the DOM.
   b. Unfortunately, when we compile a template, we do not yet know
      what component that template is used for, and, indeed, whether it
      is even a template for a component at all.
   c. To capture the semantic differences, we do a bit of analysis at
      compile time (to determine *candidates* for top-level elements),
      and use runtime information (component invocation style and
      the name of the component looked up in the container) to
      disambiguate between a component’s element and an invocation of
      another component.
2. If the root element for the `my-foo` component is a regular HTML
   element, we use the `attachAttributes` functionality of HTMLBars to
   attach the attributes that the component was invoked with onto the
   root element.
3. In general, it is important that changes to attributes do not result
   in a change to the identity of the element that they are contained
   in. To achieve this, we reused much of the infrastructure built in
   `buildComponentTemplate`.

The consequence of (1) and (2) above is that the semantics are always
“a component’s layout represents its outerHTML”, even though the
implementation is quite different depending on whether the root element
is the same-named component or not.
@ef4
Copy link
Contributor

ef4 commented Jun 12, 2015

@stefanpenner: most of your list of objections I actually see as features.

event listeners are dubious

Event listeners on the Component class are fundamentally dubious now that we have the component's own element in the template. You can avoid having two APIs for the same thing and just use {{action}} (or the newer alternatives, like on-click=) on the component's top-level element. This has the benefit of being 100% unambiguous, no matter how many top-level elements are in the template.

consumers of the component must realize the component may not be compatible with: tagName, id, class...

I think moving away from those APIs is positive. When somebody wants a particular tag, it is better to let them just write the tag. So instead of:

<some-component tagName="tr" class="tall" />

You can lift the top element out into the caller's context, and implement the component as a fragment:

<tr class="tall">
  <some-component />
</tr>

The reality of the DOM as it works today is that it is not arbitrarily flexible. There are plenty of contexts with strict rules, and plenty of ways to break existing layouts just because you wanted to add a new layer of abstraction.

Components are a unit of abstraction that does need to be arbitrarily flexible. They are the function calls in your template. Splitting a big function into smaller functions should not force you to change the output of the function, but that is exactly what happens if components and DOM are forced to be one-to-one.

I am also unsympathetic to the web components argument. Ember Components are a superset of web components. We already do much that they don't. But we are still completely interoperable, and you can choose to implement a component in Polymer, and it will work fine with Ember.

@jamesarosen
Copy link

most of your list of objections I actually see as features...

@ef4 this post of yours really turned me around on this RFC

@stefanpenner
Copy link
Member

i like the way this discussion is going! My concerns keep getting widled down, but the remaining are becoming well defined. Lets see where this leads.

event listeners are dubious
Event listeners on the Component class are fundamentally dubious now that we have the component's own element in the template. You can avoid having two APIs for the same thing and just use {{action}} (or the newer alternatives, like on-click=) on the component's top-level element. This has the benefit of being 100% unambiguous, no matter how many top-level elements are in the template.

I totally agree, also as event-listeners are already contextual, a video tags canplaythrough is not expected to work on a div, so I see no problem.

consumers of the component must realize the component may not be compatible with: tagName, id, class...
I think moving away from those APIs is positive. When somebody wants a particular tag, it is better to let them just write the tag. So instead of:

You can lift the top element out into the caller's context, and implement the component as a fragment:

I have un-intentionally lumped together tagName and class (legitimate DOM attrs). I wish for us to separate these two, as I also believe tagName usage to be an anti-pattern and your lifting example to be best practices.

So lets continue to refine these thoughts, but lets focus on the example I provided.

Given:

<div class="{{mode}}">
  <maybe-fragment-maybe-not hidden=isPresenting />
  <video></video>
</div>

The lifting strategy, results in defensive structural wrapping.

<div class="{{mode}}">
  <span hidden=isPresenting >
    <maybe-fragment-maybe-not />
  </span>
  <video></video>
</div>

note: hidden is just one example, another would be the accessibility improving aria- labels.

It feels wrong, that applying accessibility hints results in potentially breaking defensive structural wrapping

Now, after investigation of the components implementation (or via trial & error) a developer may infer that the defensive wrapping is unneeded. Unfortunately Overtime this inference may not continue to stand true as the single-root may transition to multi-root.

The transition from single-root to multi root (or back) should be considered poor practice, but the potential does have a non negligible cost.

Finally, and what I believe to be the root of my concerns. We have two concepts, range and element, although related they both expose very different and incompatible capabilities. All while occupying the same syntax.

<div class="{{mode}}">
  {{fragment-thing}}
  <video></video>
</div>
<div class="{{mode}}">
  <not-a-fragment />
  <video></video>
</div>

aside: I wonder if today < is the new hotness, now everything looks better as an <.

@ef4
Copy link
Contributor

ef4 commented Jun 13, 2015

I like keeping curlies for fragments and angles for components so that the invocation is unambiguous, but it has practical upgrade challenges. We would need a way for the curlies to opt in to one-way binding and own-element-in-template.

@stefanpenner
Copy link
Member

but it has practical upgrade challenges. We would need a way for the curlies to opt in to one-way binding and own-element-in-template.

I absolutely agree, @tomdale also voiced this concern.

One idea, was to introduce (until we can fully re-claim {{) {{fragment .... This is obviously an unfortunate interim step, but it feels like a worthwhile short term cost.

@jmurphyau
Copy link

Is there any way to opt in to one way bindings and no attr proxying in curly {{components}}?

I'm finding myself writing (readonly prop) and would love being able to disable attr proxying to the component object.

I know angle brackets will opt in to this but they aren't available yet.. Aside from getting the functionality sooner, would there be any other benefit in having these options available in curlys?

If this isn't currently possible and seems like something reasonable I may make an attempt at a PR..? Turning off attr proxying doesn't seem too difficult but will need to look into readonly by default rather than mut ...

tomdale added a commit to emberjs/ember.js that referenced this pull request Jul 6, 2015
emberjs/rfcs#60

This commit implements the proposed semantics for angle-bracket
components. The TLDR is that a component’s template represents its
“outerHTML” rather than its “innerHTML”, which makes it easier to
configure the element itself using templating constructs.

Some salient points:

1. If there is a single root element, the attributes from the invocation
   are copied onto the root element.
2. The invocation’s attributes “win out” over the attributes from the
   root element in the component’s layout.
3. Classes are merged. If the invocation says `class=“a”` and the root
   element says `class=“b”`, the result is `class=“a b”`. The rationale
   is that when you say `class=“a”`, you are really saying “add the `a`
   class to this element”.

A few sticky issues:

1. If the root element for the `my-foo` component is `<my-foo>`, we
   insert an element with tag name of `my-foo`. While this is intuitive,
   note that in all other cases, `<my-foo>` represents an invocation of
   the component. In the root position, that makes no sense, since it
   would inevitably produce a stack overflow.
   a. This “identity element” case makes it idiomatic to reflect the
      name of the component onto the DOM.
   b. Unfortunately, when we compile a template, we do not yet know
      what component that template is used for, and, indeed, whether it
      is even a template for a component at all.
   c. To capture the semantic differences, we do a bit of analysis at
      compile time (to determine *candidates* for top-level elements),
      and use runtime information (component invocation style and
      the name of the component looked up in the container) to
      disambiguate between a component’s element and an invocation of
      another component.
2. If the root element for the `my-foo` component is a regular HTML
   element, we use the `attachAttributes` functionality of HTMLBars to
   attach the attributes that the component was invoked with onto the
   root element.
3. In general, it is important that changes to attributes do not result
   in a change to the identity of the element that they are contained
   in. To achieve this, we reused much of the infrastructure built in
   `buildComponentTemplate`.

The consequence of (1) and (2) above is that the semantics are always
“a component’s layout represents its outerHTML”, even though the
implementation is quite different depending on whether the root element
is the same-named component or not.
tomdale added a commit to emberjs/ember.js that referenced this pull request Jul 8, 2015
emberjs/rfcs#60

This commit implements the proposed semantics for angle-bracket
components. The TLDR is that a component’s template represents its
“outerHTML” rather than its “innerHTML”, which makes it easier to
configure the element itself using templating constructs.

Some salient points:

1. If there is a single root element, the attributes from the invocation
   are copied onto the root element.
2. The invocation’s attributes “win out” over the attributes from the
   root element in the component’s layout.
3. Classes are merged. If the invocation says `class=“a”` and the root
   element says `class=“b”`, the result is `class=“a b”`. The rationale
   is that when you say `class=“a”`, you are really saying “add the `a`
   class to this element”.

A few sticky issues:

1. If the root element for the `my-foo` component is `<my-foo>`, we
   insert an element with tag name of `my-foo`. While this is intuitive,
   note that in all other cases, `<my-foo>` represents an invocation of
   the component. In the root position, that makes no sense, since it
   would inevitably produce a stack overflow.
   a. This “identity element” case makes it idiomatic to reflect the
      name of the component onto the DOM.
   b. Unfortunately, when we compile a template, we do not yet know
      what component that template is used for, and, indeed, whether it
      is even a template for a component at all.
   c. To capture the semantic differences, we do a bit of analysis at
      compile time (to determine *candidates* for top-level elements),
      and use runtime information (component invocation style and
      the name of the component looked up in the container) to
      disambiguate between a component’s element and an invocation of
      another component.
2. If the root element for the `my-foo` component is a regular HTML
   element, we use the `attachAttributes` functionality of HTMLBars to
   attach the attributes that the component was invoked with onto the
   root element.
3. In general, it is important that changes to attributes do not result
   in a change to the identity of the element that they are contained
   in. To achieve this, we reused much of the infrastructure built in
   `buildComponentTemplate`.

The consequence of (1) and (2) above is that the semantics are always
“a component’s layout represents its outerHTML”, even though the
implementation is quite different depending on whether the root element
is the same-named component or not.
machty pushed a commit to machty/ember.js that referenced this pull request Jul 8, 2015
emberjs/rfcs#60

This commit implements the proposed semantics for angle-bracket
components. The TLDR is that a component’s template represents its
“outerHTML” rather than its “innerHTML”, which makes it easier to
configure the element itself using templating constructs.

Some salient points:

1. If there is a single root element, the attributes from the invocation
   are copied onto the root element.
2. The invocation’s attributes “win out” over the attributes from the
   root element in the component’s layout.
3. Classes are merged. If the invocation says `class=“a”` and the root
   element says `class=“b”`, the result is `class=“a b”`. The rationale
   is that when you say `class=“a”`, you are really saying “add the `a`
   class to this element”.

A few sticky issues:

1. If the root element for the `my-foo` component is `<my-foo>`, we
   insert an element with tag name of `my-foo`. While this is intuitive,
   note that in all other cases, `<my-foo>` represents an invocation of
   the component. In the root position, that makes no sense, since it
   would inevitably produce a stack overflow.
   a. This “identity element” case makes it idiomatic to reflect the
      name of the component onto the DOM.
   b. Unfortunately, when we compile a template, we do not yet know
      what component that template is used for, and, indeed, whether it
      is even a template for a component at all.
   c. To capture the semantic differences, we do a bit of analysis at
      compile time (to determine *candidates* for top-level elements),
      and use runtime information (component invocation style and
      the name of the component looked up in the container) to
      disambiguate between a component’s element and an invocation of
      another component.
2. If the root element for the `my-foo` component is a regular HTML
   element, we use the `attachAttributes` functionality of HTMLBars to
   attach the attributes that the component was invoked with onto the
   root element.
3. In general, it is important that changes to attributes do not result
   in a change to the identity of the element that they are contained
   in. To achieve this, we reused much of the infrastructure built in
   `buildComponentTemplate`.

The consequence of (1) and (2) above is that the semantics are always
“a component’s layout represents its outerHTML”, even though the
implementation is quite different depending on whether the root element
is the same-named component or not.
@ohnnyj
Copy link

ohnnyj commented Jul 14, 2015

Tried adding a comment to emberjs/ember.js@9e5f072 but no response so thought I would repost here, apologies if this is not the right forum.

Trying to use this new implementation but running into an issue (using emberjs/ember.js@04dd84c).

I have a component template:

<my-component>
  <div class="container"></div>
</my-component>

and use it in a route/top level template:

<my-component model={{model}} />

From the description mentioned in the above commit I would expect that I would end up with a tag in the html but instead I get the error mentioned in emberjs/ember.js@9e5f072.

If I remove the <my-component> from my component template no error but not the markup I would like. Maybe I am misunderstanding the correct way to do this.

And, BTW, this is probably an invalid usage pattern but changing the <my-component> to {{my-component}} in the component template results in a stack overflow.

@chadhietala
Copy link
Contributor

I believe there should be a build time warning or failure if you are using mutative APIs on attrs in angle bracket components. In React props can be mutated as well but their is tooling around this suggests that you should not mutate props.

The example below shows mutating both arrays and objects. Arrays are clearly worst that mutating objects as object properties are not propagated. The program becomes hard to reason about if the attrs can be mutated as they are passed along, we should do our utmost to shorten the conceptual gap between the static program and the dynamic process 😉.

http://emberjs.jsbin.com/xahidifube

@tomdale
Copy link
Member

tomdale commented Jul 18, 2015

@chadhietala Setting up property descriptors on attrs would be slow but is probably worth it in development mode.

@stefanpenner
Copy link
Member

@chadhietala Setting up property descriptors on attrs would be slow but is probably worth it in development mode.

in theory we can make attrs the instance of a class with those descriptors on the proto. So that would only be expensive the first time the class is derived. I suspect in practice this will be few, it would not longer be per snapshot or per component instance.

@tomdale
Copy link
Member

tomdale commented Jul 19, 2015

@stefanpenner The problem is that attrs aren't known on a per-component basis; they're known per-invocation. So e.g. I may have a component {{my-component}} that sometimes I invoke as {{my-component foo="bar"}} and sometimes as {{my-component bar="baz"}}. The {{component}} helper introduces even more complexity here.

Your proposal would require us to cache the class with descriptors on a per-invocation basis, which is not impossible but we don't have any infrastructure for it currently, as best I can tell. Maybe our friends on the Chrome team will hurry up and implement Proxy and then these concerns would be moot, anyway. ;)

@stefanpenner
Copy link
Member

@stefanpenner The problem is that attrs aren't known on a per-component basis; they're known per-invocation.

yup, but this is both statically known at compile time and there are also less invocation sites then component instances. I suspect we can incur the penalty once per unique signature call-site even at runtime. (although build time deferral is also likely option).

(not saying this is the solution we must take, just saying i believe it can be done without a noticeable performance problem)

@chadhietala
Copy link
Contributor

Like I mentioned, I believe tooling can be the happy path. In general I don't really believe in the notion of "in dev it's slower". I would rather have consistent performance characteristics regardless of environment.

@mitchlloyd
Copy link

Very minor cocern here but with ye olde components, passing in an attr was an effective way to write tests for components that use services.

this.render("{{my-component session=sessionStub}}");

Any thoughts on whether angle bracket components mean the end of this pattern? This may be another reason that we need a well-paved path for stubbing services.

@rwjblue
Copy link
Member

rwjblue commented Aug 22, 2015

@mitchlloyd - I think emberjs/ember-test-helpers#96 is a much better pattern for this (and works with ember-qunit@0.4.10+).

@workmanw
Copy link
Contributor

While working to upgrade our app to 2.0 and plan for some future updates, one question came up relating to this.attrs, how will default values be configured? Right now it's very easy to provide sensible defaults for components by declaring them on the component class, but with this.attrs will that be possible?

As a use case, we often provide default values labels for many components, but allow them to be overridden.

I'm not even sure if this is the right place to ask this since this.attrs isn't exactly component unification. I just wanted to be sure to raise the concern of default values. If that concern belongs on another RFC or as an issue I'd be happy to raise it their.

@mitchlloyd
Copy link

@rwjblue Thanks for the heads up!

@mmun
Copy link
Member

mmun commented Aug 23, 2015

@workmanw You can just do

this.foo = 'foo' in this.attrs ? this.attrs.foo : yourDefault;

in whatever hook makes sense to you.

@workmanw
Copy link
Contributor

@mmun Okay yea, I was also thinking I could build a computed macro for this use case too. Something like:

function attrsDefault(key, defaultValue) {
   return Ember.computed('attrs.'+key, function() {
     return (key in this.attrs) ? this.attrs[key] : defaultValue;
   });
}

Ember.Component.extend({
 foo: attrsDefault('foo', 'bar')
});

But I wasn't sure if this would be unadvised or potentially result in a naming conflict for a period of time.

@mmun
Copy link
Member

mmun commented Aug 23, 2015

@workmanw That's definitely something I'm hoping someone experiments with in an addon so we can gather consensus on how useful it is.

@tim-evans
Copy link

How would angle bracket components work with inverses?

For example, I'd write a {{toggle-button}} with an {{else}} to separate the enabled and disabled state. How would I write this with Ember.GlimmerComponent?

@rwjblue
Copy link
Member

rwjblue commented Apr 14, 2016

The conversation in this RFC has been great! I think at this point this RFC doesn't reflect current lines of thinking, and either a rewrite or a new RFC will be needed when we are ready to start progessing forward here.

I propose that we close this PR...

@rwjblue
Copy link
Member

rwjblue commented Apr 15, 2016

Thanks for everyone's hard work here. We have made a ton of progress, and are in the middle of integrating the updated glimmer engine that is required to start working on angle bracket components again.

I'm going to close this for now while we continue pushing forward on the known path. We should reopen (or entertain a new RFC) when ready to work on angle bracket components again.

@rwjblue rwjblue closed this Apr 15, 2016
@rwjblue rwjblue deleted the angle-bracket-components branch April 15, 2016 21:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.