I am trying to do something like this:
<a href="#/{{unbound goto}}" {{bind-attr class=":menu-entry-text :nowrap active:selected-menu-entry-text"}} {{bind-attr id="active:active-nav:inactive-nav"}} {{bind-attr data-goto="goto"}}>
But only the first attribute (class) gets set: id and data-goto are not defined. Is it possible to set several attributes with bind-attr in the same element? How?
Yes you can bind several attributes at once by either using multiple bind-attr helpers like in your example, or just putting all the attributes in a single bind-attr helper. You have an issue in your example though, which is why things aren't working as expected.
The "value if true" form that you're using for the class attribute cannot be applied to other types of attributes. All other attributes must be bound to a dynamic property on the controller. For example, if you had a controller that looked like this:
App.MyController = Ember.ObjectController.extend({
myId: function() {
if (this.get("active") === true) {
"active-nav"
} else {
"inactive-nav"
}
}.property("active")
});
Then you would bind that like so:
<a href="#/{{unbound goto}}" {{bind-attr id="myID"}}>
Just a side note on that example, it's probably a code smell if you have a dynamic ID for an HTML element. IDs are supposed to uniquely identify a single element and I wouldn't expect them to change. It seems like a class would be a better fit for this use case.
Related
Let's say I have a model called "Article" with only one property called "title"...
I could write hanblebars to edit the article property like this:
<span>Title</span><span>{{input value=title}}</span>
And Ember/handlebars magically binds the value of that input box to the "title" property value.
No problem there. But I am working on a project in which I will need to generate the handlebars code dynamically, based on a model definition model.
For example, I will not know there is a property called "title", but would have instead to loop into a "modelFields" list in the model definition model.
So, the handlebars will be something like this:
Looking at the code below:
{{#each modelField in modelFields}}
<span>modelField.displayName</span><span>{{input value=modelField.propertyName}}</span>
{{/each}}
The result HTML for the "title" property will be:
<span>Title</span><span><input value="title"></span>
Now here is my question, is there a way to have the value coming dynamically from propertyName (title, in this example) to be handled by ember as a binding property title, instead of a string title?
To clarify, is there a way for the result of this:
{{#each modelField in modelFields}}
<span>modelField.displayName</span><span>{{input value=modelField.propertyName}}</span>
{{/each}}
to be treated as this (title is a binding property):
<span>Title</span><span>{{input value=title}}</span>
instead of this (title is a string):
<span>Title</span><span><input value="title"></span>
?
I tried with views,components, with no luck.
I've found answer in another post that help me find the solution. The post is:
Ember.js: TextField with dynamic binding
Although, for my purposes, I had to tweak his/her solution a little bit:
Ember.Handlebars.helper('dataTextField', function (key, options) {
options.hash.valueBinding = 'controller.' + key;
return Ember.Handlebars.helpers.input.apply(this, [options]);
});
and in the template I call:
{{#each modelField in modelFields}}
<span>{{modelField.displayName}}</span>
<span>
{{dataTextField modelField.name}}
</span>
{{/each}}
I'm wanting to do something that I suspect is quite easy but for some reason can't figure out how to get my head around it:
{{#each item in myArray}}
{{ui-input value=storeMe[#index]}}
{{/each}}
In the above case I'd be iterating through a numeric array of things and I want to store values of a UI component using the same numeric index.
Similarly it would be nice to be able to do the following:
{{#each item in myArrayOfObjects}}
{{ui-input value=storeMe[item.id]}}
{{/each}}
Where the storage device -- storeMe -- is a dictionary whose keys are determined by the id property of each item in array of objects.
In my particular use-case, I am asking the user to input a strategy for measuring body fat. I use a select box for that:
<div class="clearfix downer">
{{x-selectize
options=measurementStrategies
labelField="name"
placeholder="measurement strategy"
valueObject=measurementPoints
}}
</div>
By binding to the "valueObject" above I get back a simple array of measurement points which are relevant for the user chosen strategy (e.g., chest, thigh, lower back, etc.). I then iterate through these measurement points and want to have a value stored for each one:
<div class="downer">
{{#each point in measurementPoints}}
<div class="clearfix">
{{ui-number-input value=model.measurements[point]}}
</div>
{{/each}}
This doesn't work, of course, because apparently I can't bind to an offset property (aka, measurements[point]).
In many cases this type of problem doesn't matter because if I want to manipulate the structure I'm iterating over then the each loop provides the indirection. The problem comes when the storage property is hanging off of a different base than that which you are iterating over. So in my case, if I were actually manipulating point or a property hanging off of point this would be easy because point is an offset of measurementPoints but in my case I'm iterating measurementPoints and saving values to model.measurements.
That’s too much logic for Handlebars. You could create a computed property instead that pairs each item with each value in storeMe, so you can access them as pairs.
You could probably accomplish this with a custom helper, but it seems like a mess to me.
Here’s a rudimentary example, lacking detail on your problem domain:
storeMeItemsByIndex: function() {
var storeMe = this.get('storeMe');
return this.get('myArray').map(function(item, index) {
return storeMe[index];
});
}.property('myArray', 'storeMe'),
storeMeItemsById: function() {
var storeMe = this.get('storeMe');
return this.get('myArray').map(function(item) {
return storeMe[item.id];
});
}
Those would fit your example template code. However, you wouldn’t have access to both the value from storeMe and the item at the same time. If you want that, you could just construct object pairs:
storeMeItemsByIndex: function() {
var storeMe = this.get('storeMe');
return this.get('myArray').map(function(item, index) {
return {item: item, value: storeMe[index]};
});
}.property('myArray', 'storeMe'),
Or something like that.
With your more specific example, you could do something like this:
measurementPointsWithValues: function() {
var measurements = this.get('model.measurements');
return this.get('measurementPoints').map(function(point, index) {
return {point: point, value: measurements.itemAt(index)};
};
}
Then you’d use it in your template like this:
{{#each pointAndValue in measurementPointsWithValues}}
{{! some use of pointAndValue.point, probably}}
{{ui-number-input value=pointAndValue.value}}
{{/each}}
It’s clunky, but it works. I don’t know the details of your object model, but you may benefit from some intermediate objects.
I have an endpoint that returns a list of artists (json data).
And an endpoint that returns a specific property given an id.
What I would like to do is to iterate through all the artists and display one or more properties in the template to the user but the property should only be fetched from the API if it is bound in the template.
In my ArtistsRoute, I set the model to be all those artists fetched by calling getJSON...
I want, somehow to be able to fetch a property for an artist and display it (through binding).
The Properties map could be stored in the ArtistController maybe.
I could not find a good example for this. Any help is appreciated!
Template example:
Name is on the artist object itself, but the Properties object has been created manually. So in the ArtistController it could be initialized to empty:
Properties = {}
And then it sets Propertes['ShortName'] = to the fetched value.
<ul>
{{#each}}
<li>
{{Name}}
{{Properties.ShortName}}
<img {{bind-attr src=Properties.MainImage}} />
</li>
{{/each}}
</ul>
Should I use a function instead as a property or a Handlebars helper? Like:
{{Property this 'ShortName'}}
where 'this' is the ArtistController and 'ShortName' is the property to fetched. The property id can be calculated through the ArtistController and propertyName.
function(tag, propertyName) {
Ember.$.getJSON('/Properties/' + tag.Id + '_' + propertyName).then(function(response) {
var propertyValueToBind = response.Value; // This is the value I want to display in the template.
});
}
Then the Property function has to know when to rerender the template (once the property has been fetched from the API).
Firstly you'll want to generally avoid properties that are uppercase. They are usually considered global properties, and not in scope.
Ember lazy loads computed properties by default, so adding that functionality to a computed property would be an excellent way to go.
someProperty: function(){
var promise = Ember.$.getJSON('/Properties/buildupurl');
return Ember.ObjectProxy.extend(Ember.PromiseProxyMixin).create({
promise: promise
});
}.property()
Then in your template someProperty would be accessed like this
{{someProperty.value}}
And would be asynchronously populated.
Example: http://emberjs.jsbin.com/OxIDiVU/769/edit
I want to create a component which needs to generate dynamics links. I tried passing the link data as an array, but this does not work.
var user1 = get("store").find("user", 1);
var data = {link: ["users.show", user1], title: "User1"};
{{#link-to data.link}}{{data.title}}{{/link-to}}
This should be equal to
{{#link-to "users.show" 1}}{{data.title}}{{/link-to}}
How to generate fully dynamic links from a variable?
You can specify an array as params argument into a link-to helper. Similar to nickiaconis' answer answer, but with just the default {{link-to}} helper:
{{#link-to params=data.link}}{{data.title}}{{/link-to}}
...will render something like:
User1
(tested with Ember 2.3.0)
Ember 1.13.x
The LinkComponent, which is what the link-to helper creates for you, is exposed as -link-to. I've created an example of its use here: http://emberjs.jsbin.com/rinukefuqe/2/edit?html,js,output
{{#-link-to params=(unbound link) hasBlock="true"}}
{{title}}
{{/-link-to}}
The params attribute is what the link-to helper normally bundles your positional parameters onto, although you must use the unbound helper here because the LinkComponent expects params to be an array rather than a value binding object. Additionally, the determination of use as block or inline component is not built into components yet, so you must pass hasBlock="true" unless you include the link text as the first parameter in your array.
Ember ≤ 1.12.x
Although it is not done already, you can manually expose the LinkView component, which is the equivalent of the new LinkComponent.
App.XLinkToComponent = Ember.LinkView.extend();
Then use it like:
{{#x-link-to params=link}}
{{title}}
{{/x-link-to}}
Using unbound and hasBlock="true" are not necessary as the internal logic of LinkView differs from LinkComponent.
I think that isn't possible to pass an array, but you can pass each argument directlly, like the following:
route
var user1 = this.store.find('user', 1);
var data = { data: { link: "users.show", model: user1, title: "User1" } };
return data;
template
{{#link-to data.link data.model.id}}{{data.title}}{{/link-to}}
I hope it helps
Within my Ember app, I have an object model, called Item, with a property 'price', which holds a float value, such as 20.5. When I use the property in a template {{price}}, I would like for it to be formatted to look like so: $20.50.
This object is not the model that is tied to the controller at the route, but rather an element in an Ember Array, called items, which is a property of the model at the route. So I have something like this in my template:
{{#each item in items}}
{{item.price}}
{{/each}}
The problem seems pretty simple, but I can't really find a solution. The idea is that I do not want to change the name of the property to get it to look the way I want, since I could make a computed property that formats the price property, but then I would have to use a new name in the templates.
What you could do is write your own custom handlebars helper.
For your use case it would look something like this:
Ember.Handlebars.registerBoundHelper('formatNumber', function(value) {
return "$" + value.toFixed(2);
});
And then use it in your templates this way:
{{#each item in items}}
{{formatNumber item.price}}
{{/each}}
Please see here for a working jsbin.
Hope it helps.