I'd like to pass the properties of an object as attributes of a component.
For instance, in the example below, I'm passing the object as an attribute column of the dynamic-table-column component.
<tr>
{{#each column in table.columns}}
{{dynamic-table-column column=column}}
{{/each}}
</tr>
But could I do it if I wanted the properties of the column object to be passed as attributes to this component? React.js, for instance has a notation for this: {...props}.
Update
To clarify, I'll be more explicit about my current situation. Right now I have to repeat every attribute explicitly, as in:
<tr>
{{#each column in table.columns}}
{{dynamic-table-column
title=column.title
alignment=column.alignment
sortable=column.sortable
formatter=column.formatter}}
{{/each}}
</tr>
Besides being too verbose, this has a fundamental flaw: imagine if a new attribute is added to the component in the future. We'd have to go over every place where this component is used, and add the new attribute explicitly.
React's JSX on the other hand, has a syntax for this purpose:
<DynamicTableColumn {...column}/>
That will assign each property in the column object to the attribute in the component with that same name. So if in the future the column object carries a new property, a new attribute will be assigned to the component, without having to change the template explicitly.
I hope this will make things clearer.
This is not currently possible in Ember (Sep 2015).
Handlebars syntax does not support what we've called a "splat" operator, inspired by Ruby. There is a proposal with some support on their repo.
HTML-syntax components, <my-component arg={{prop}} /> have not yet landed in Ember. When they do there will be an opportunity to introduce a helper for splat, ala <my-component {{attrs someHash}} />, however there is no specific proposal to track for this right now.
Related
When rendering a list of items, React uses the index of each item as a default key, if none is supplied.
return <div>
{this.props.shows.map(show => <ShowComp title = {show.title}/>)}
</div>;
But why doesn't React use the JS object reference of each item instead? Seems to me like a much safer option, as it would not cause re-rendering of any of the items if the list order changes (as opposed to the index approach).
I'm relatively new to React, so I'm sure there's an underlying reason.
In Angular, ngFor (which renders a list of elements, similar to mapping object to React elements), it also has a trackBy configuration option (which is the equivalent of key in React). However, if it's not supplied, it uses the object references as an identifier, which seems more natural.
The reason why it's not using the reference of the object by default is all React's developpers choice.
Keep in mind it doesn't have to be unique across all the items, it has to be unique across the siblings of each item.
As shown here : https://reactjs.org/docs/reconciliation.html#keys
You could definitely use a not so unique key that's only unique across siblings.
Also, is using the reference of the object faster than most small integer found in unique ids ?
See twiddle here: https://ember-twiddle.com/2150099882893760cef237ff2bd22e85
Basically, in crit-service I create Ember Objects "Crits" and "Crit", and fill them with some data.
The crit-service is used by two different components, which basically do the same thing: display the Crits.
The problem is that the "change" buttons do not work. By debugging, I see that the values are changed, but the view is not updated. Why is this? Since Ember.Object is Observable, shouldn't setting a value notify the template? And most importantly, how can I get this to work?
P.S. I've seen a workaround by using Ember.A() instead of Objects. However, this would add boilerplate, as my data model is really objects and not arrays of key-value pairs.
This seems to be an issue with the {{#each-in}} helper which does not reload on changes. A quick fix is to use the {{get}} helper.
So instead of this:
{{#each-in obj as |key val|}}
{{key}}={{val}}
{{/each-in}}
Do this:
{{#each-in obj as |key|}}
{{key}}={{get obj key}}
{{/each-in}}
However, this will never work if you add additional properties.
here is a working twiddle with that solution.
Another solution that will always work is to call .rerender() on the component. This is save thanks to glimmer, which does only update the parts of the DOM that have changed. However, you would have to call it on your common root component of the two components, or on both components.
So I have this computed property inside my component.js: contexts: Ember.computed.oneWay('myService.contexts'),
And I am able to get the content from another action
openHelp(){
console.log(this.get('contexts'))
alert(this.get('contexts'))
}
}
But when I try to use the computed property in Handlebars ({{contexts}}) it's just blank.
I created an Ember Twiddle for this question: https://ember-twiddle.com/38de64d58dcf3298df6d4176f15cbc0e?openFiles=components.my-component-help.js%2Ctemplates.components.my-component-help.hbs
If I have an array foo: [ 'foo','bar'] and I do {{foo}} it outputs in handlebars. But if I make foo a computed property that gets [ 'foo','bar'] from and do {{foo}} I get nothing.
Here's the solution: https://ember-twiddle.com/e9c2ef05e27013a389e0b2bfdaec3d40?openFiles=services.my-service.js%2Ctemplates.components.my-component-help.hbs
There were two issues:
contexts is an array. When you console.log or alert it, those methods internally in some browsers JSON.stringify the object for you for your convenience. Ember will not do that. You need to format the array yourself or, as I did, each over it. For debugging purposes, feel free to use the log helper.
Computed properties on arrays are watching for array mutations through Ember's methods such as pushObject and removeObject. Simply using push or splice won't update the computed property.
Can't comment on the above answer which is correct because I don't have enough reputation, but I wanted to add a link to the documentation relating to Ember's observable methods for enumerables:
https://guides.emberjs.com/v2.5.0/object-model/enumerables/
Let's say I have this code
table(my-attr="value")
...complex component Jade...
and I would like render that my-attr base on property delivered into component. Since v-if works on whole element I cannot do something like
table(my-attr="value", v-if="myProp")
table(v-else)
because I would have to duplicate all the code inside table.
How can I achieve that?
You can use v-bind or interpolate the value directly with {{}}
// (sorry, no jade)
<table v-bind:attribute1="someMethod" attribute2="{{anotherMethod}}">
Now someMethod and anotherMethod should be data, computed properties, or methods of your component, and should return either the attribute's desired value or false. In the latter case, the attribute will not be added to the element at all.
Update: Note that interpolations in attributes have been removed in Vue 2
The idea is to be able to perform something similar to this:
{{ #each color in colors }}
<li class="{{if car.color==color 'selected' " > </li>
{{/each}}
I am aware of the fact that ember's policy is not to have logic in the templates, still, this (simple) problem is not answered to me, after a day's search.
Build a component, add the logic into a component as a computed property.
A really boring example: http://emberjs.jsbin.com/conijumego/1/edit
You can also use needs and an itemController.
Another boring example: http://emberjs.jsbin.com/taluwuquli/1/edit?html,js,output
Use classNameBindings on an Ember Component:
"If the bound property's value is a string, that value will be added
as a class name without modification"
Ember Component Docs
Working JSBin Demo
In the demo I am defining the value for the class name for the component within the template, but as you can see in the component js, the value could come from anywhere ie., Model data, an array declared in the component etc. No need for an item controller. That approach is being deprecated anyway. We are advised to stay away from controllers in order to have a clear upgrade path to Ember 2.0