-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Access Component Properties From Template #4985
Comments
I like the idea of exposing a component keyword. Here is a use case where I am using it. |
+1 for exposing I'd really like this to become a thing. Could you open a PR or start a thread on discuss? |
@stefanpenner what are your thoughts on this? short version: expose |
I'm not sure I understand well, but it seems to me that simply the |
@sly7-7 - Yes, |
I've been 👎 on this in the past. @machty and I (and probably others) have spent crazy amounts of time thinking through the two interrelated problems: component composition and component isolation. Component composition (basically "how do you compose a component by combining other, smaller components" is the upcoming holy grail for web apps and something I've been hoping Ember would lead on for years. It's ostensibly the goal of view-only libraries like https://github.com/facebook/react and https://github.com/polymer. I think we've actually fallen behind or just plain gotten this stuff wrong. Although it's not terribly difficult to write components with complex behaviors in Ember it's still painfully hard to author components modularly (i.e. with internal pieces can be configured and replaced for customization). Contributing to this problem is poor component isolation. Our description of components is basically a lie. Blockless components don't have access to the context of where they get used but block components do, which opens up questions like "ok, but in that block how do I change contexts back to the component?" Ask @rpflorence and he'll tell you if you find yourself using templates in components it's because you're missing some abstraction I suspect we'll either need to extend Handlebars with sugar around these use cases (which is what block args would help do) or put templates down, back away slowly, and admit that they're useful for non-isolated, controller backed display but an anti-pattern for data isolated display. As an aside: default two-way data binding is the other big way that component isolation is broken. Data mutation from inside the component leaks back out into the context where it was used without your control. It's incredibly convenient (and demos well!) but can such a source of pain when you don't want it. |
@trek I read this as a vote for increased isolation. Would you prefer removing access to the surrounding scope for 'blockful' components (to increase isolation)? If so, a I'm not arguing against here. Although I haven't given it much thought isolation for components seems desirable, and removing access to outer context for component templates might be a good idea. I'm just trying to understand if you consider the template to be part of the 'isolation cell' or not. |
If you removed surrounding scope access (which I don't think we can do because of helper/components like I don't think anyone has really nailed the scope problem. I've seen Angular's Ember has the additional complication of a four desired lookup locations (and action targets) when you use a block-template component inside a controller backed template:
application.hbs (1) {{foo}}<- the controller
(2) {{view.bar}} <- the controller's paired view
{{#my-thing thing=foo}}
(1) {{foo}} <- controller
(2) {{view.bar}} <- the controller's paired view
(4) {{component.propertyBasedOnThing}} <- component
{{/my-thing}} components/my-thing.hbs (3) {{thing}} <- component
{{yield}} It's totally reasonable to want access to each of them, so I'm not 👎 on |
This thread is meaningless in React. Components are just functions where normal JavaScript scope applies. Props and state separate what the outside world gave you and what you are managing yourself. Data flows down, you wouldn't ever be asking a child for its state from the owner. You would have your own piece of state and pass that down to a child as a prop, and if the child needed to change it you'd also pass it a handler, receive the new value, and then set state again. |
I'm not sure I understand the use-case here. If you need a component's property in a yielded template from the controller, then pass in a controller property to the component and use it. If both the controller and the component care about the property then that's exactly what these bound properties are for, right? I am in a controller template
{{#x-foo}}
{{component.bar}}
{{/x-foo}}
That seems bad if the outside world can be reaching in,
instead, just give it what you want
{{#x-foo bar=controllerBar}}
{{controllerBar}}
{{/x-foo}}
Curious what is wrong with this ... |
@rpflorence
|
@rjackson @trek Just as a note, Anyway, I think I have a similar use case, trying to implement a modal component, with header, body, footer sub-components, where I wanted to factorize some actions in the root component, and call them from the subcomponents (for example, the close action is on the modal, but could be send either from a button in the header, and from a button in the footer). I just watched @rpflorence's video, and I realize I am maybe developing the component in the wrong way. Will try to implement differently, like ic-tabs, and will see if it smells better. |
@sly7-7 the example I posted earlier is another use case. A button-group-component where children toggle the "open" property. Like you stated it works in release but not in master. release: http://jsbin.com/giyah/1/edit I am wondering if I am going off in the wrong direction? I could pass the "open" property in from the controller but I feel that is over doing it, especially with multiple button groups. |
Yes, it seems the behavior has changed. It is breaking some of our components. On Ember 1.6.1:
On Ember 1.7.0 and master:
Is this a bug or a yet undocumented breaking change? |
I have heard that in the future you will be able to explicitly specify properties that are available in the block template. For now, the workaround if you really need it is to use |
@manuelmitasch it was a bug fix, the block is supposed to be isolated from component, thus the view keyword isn't supposed to be the component view in that case. We are working a new feature to yield args to the block. |
@alexspeller I wouldn't count on that continuing to work. |
This is the direction we are currently looking at in regards to this issue emberjs/rfcs#3 |
@krisselden: Thanks for the clarification! This means there is currently no reliable way to access properties of a component from within a block? The only real solution for now is to use a view instead of a component, right? |
@manuelmitasch though it's a hack, perhaps |
@sandstrom: Thanks, this looks good. |
Having recently updated to 1.7, we also found some of our components we built stopped working. It was rare that we needed to access a component from within a yield, but it did happen and was advantageous to do so. We could convert the existing components to views, but we lose the ability to specify specific actions and have actions within the view (without extending that ability onto the view). One example we used was with a file upload component that took care of all the of uploading a file within the component. An overview can be seen here. https://gist.github.com/aaronbhansen/8ae4fb14f5dd82aeed27 If the block format will still allow you to access the component and call out actions to the component, then that will work as a solution. In the meantime, we can implement // ALTERNATIVE 2 above, but it would be nice to have a way to access the component from within a yield, until handlebars is updated to allow block statements. |
@rwjblue, which is the current workaround to access the component inside a yielded block content? Is this currently possible? This jsbin demonstrates the use case and example http://emberjs.jsbin.com/japipe/1/edit
components/some-random.handlebars
|
@ppcano AFAIK you still need to use //ALTERNATIVE 2 from above. I have update your jsbin with a working example. http://emberjs.jsbin.com/gavuhu/1/edit I have also updated the
|
@ppcano also, there is ongoing discussion in emberjs/rfcs#3 which, according to krisselden's comment above, will probably be used to solve this issue. |
@rpflorence what about this: I am in a controller template
{{#x-panel}}
{{#x-panel-header}}
Something interesting
{{#if component.isOpen}}
<i class='arrow-down'>
{{else}
<i class='arrow-up'>
{{/if}}
{{/x-panel-header}}
{{/x-panel}} The What do you think? Is there a better way to do this? |
I think I'd just do this:
|
What about when you have multiple panels though |
Yeah, that sounds terrible. I don't find |
You could always specify the context with "with"
Alternativey, labels within the component statements themselves?
|
Oh, is that using alternative 2 above? private apis right? |
@emberjs/owners is this something we should pursue? |
The block params RFC is likely the way forward here. |
Closing in favor of emberjs/rfcs#3. |
Good day. How can block params help in case when I need component ref itself? E.g.
So, Thanks. |
make the {{yield this}} |
@rwjblue I just tried this and it doesn't seem to work for me. I have a component as follows: {{results.length}} results found:
{{#each results as |result|}}
{{#if template}}
{{yield this}}
{{else}}
{{!-- Some default template just for prototyping --}}
{{/if}}
{{else}}
0 results found. Just try another query.
{{/each}} {{!-- Will be called from different controllers with different model and templates --}}
{{#search-results results=model}}
{{#link-to 'topics.topic' result}}{{result.text}}{{/link-to}}
{{/search-results}} Which does not work on one of the latest ember master. Is this supposed to work now? If so how? |
Ah, I found this http://www.slideshare.net/mixonic/new-component-patterns-in-emberjs and git it working as follows (for reference): Component: {{results.length}} results found:
{{#each results as |result|}}
<h4>
{{#if template}}
{{yield result}}
{{else}}
{{!-- Default template --}}
{{/if}}
</h4>
{{else}}
0 results found. Just try another query.
{{/each}} {{#search-results results=model as |result|}}
{{#link-to 'topics.topic' result}}{{result.text}}{{/link-to}}
{{/search-results}} |
What do I do if I want to use a component action inside of the component block-helper?
This doesn't currently work. |
ui-sidebar.hbs {{#ui-sidebar}}
{{yield (hash myClick=(action "componentToggleSideBarAction")) }}
{{/ui-sidebar}} ui-sidebar.js actions: {
componentToggleSideBarAction() {
// code
}
} This is how you use it {{#ui-sidebar as |uiSideBar|}}
<a onclick={{action uiSideBar.myClick}}> Click me to toggle </a>
{{/ui-sidebar}} Tested on ember version: v2.3 |
It's sometimes useful to access properties of components from within its template.
Either by exposing the component itself, and otherwise by exposing explicit block params. Two examples are below.
Suggestions and ideas are much appreciated!
wycats mentions this in a related issue, so it seems relevant to reprint that here:
The text was updated successfully, but these errors were encountered: