Pass multiple args in Ember JS prop - ember.js

I have a function that lives in a component and I want to pass multiple arguments to it from the parent. I realise I can pass them individually but I'd like to pass them as one arg if possible.
I'd like this to work but the syntax in actionArgs isnt correct
<MyComponent #actionName={{myAction}} #actionArgs={{myValue, myOptions}} />
<button {{on "click" (action #actionName #actionArgs)}}></button>
I've tried wrapping in parenthesis but that didnt work either.

Amazingly this can be done by passing in the fn arguments with the fn helper
<MyComponent #actionName={{fn myAction myValue myOptions}} />
<button {{on "click" (action #actionName)}}></button>

Related

How to mutate an array's value in "each" helper in Ember JS (Octane)

I have an array of strings passed as an argument to a component, inside the component I am using "each" helper to render each string in a text input. I tried the following approach.
MainComponent.hbs
<Component #model={{model}}/>
//Eg: model.list = ["Jack", "Sparrow"];
Component.hbs
<div>
{{#each this.args.model.list as |name|}}
<div>
<PaperInput #value={{ name }}
#placeholder="Enter a Name"
#onChange={{action (mut name)}}/>
</div>
{{/each}}
</div>
I am running into the error "Uncaught (in promise) Error: Assertion Failed: You can only pass a path to mut". Would really appreciate if anyone can let me know What's going wrong here.
The value that are derived from helpers (each in your case) cannot be mutated using mut helper as the helpers usually don't pass down or hold the values to change the original property.
For instance,
It makes sense if we are mutating a value as below where capitalize is a helper:
<button {{action (mut name) (capitalize name)}}>
Capitalize
</button>
however, below snippet does't fit right as helper returns the value one way!
<button {{action (mut (capitalize name)) name}}>
Capitalize
</button>
the same thing is going on with the each helper and the looped through value cannot be mutated! This code comment might be useful for further digging.
You can change your snippet to handle the onChange in the backing component class instead:
<div>
{{#each this.args.model.list as |name index|}}
<div>
<PaperInput #value={{ name }}
#placeholder="Enter a Name"
#onChange={{this.changeName index}}/>
</div>
{{/each}}
</div>
// component.js
changeName(index, nameToBeUpdated) {
// change the name here...
}
Figured it out. Posting the full implementation for the benefit of others. I passed down the index value to component's action as suggested in Gokul's answer but ran into another problem. There was no straight forward method to change the array's value. So I used the Mutable Array's replace method do that. That again caused another problem, every time I entered a character in the text input it was chaning the array value and re rendering the list which took the focus out of the input. So in "each" helper I had to set key="#index" which tells the helper to rerender only if there is a array index change, not the value.
Component.js
#action
updateName( index, name ) {
this.args.model.list.replace(index, 1, [name]);
}
MainComponent.hbs
<Component #model={{model}}/>
Component.hbs
{{#each this.args.model.list key="#index" as |name index|}}
<div>
<PaperInput #value={{ name }}
#placeholder="Enter a Name"
#onChange={{action this.updateName index}}/>
</div>
{{/each}}

bind helper like get & mut? How to bind input to dynamically specified property?

I can use the input helper to toggle a boolean property of an item like so:
{{input type="checkbox" checked=item.isSelected}}
If I want a template that displays a property of an item, but the property name is passed in dynamically, I can use the get helper.
{{get item propertyName}}
Can I combine the two approaches to bind the checkboxes checked attribute to a dynamically specified property?
{{input type="checkbox" checked=(?bind? item propertyName)}}
At the moment I am using the workaround below, but it seems inelegant to me (wrongly so?).
{{input type="checkbox"
checked=(get item propertyName)
action=(toggle propertyName item) on="change"}}
Yes. You can combine get and mut helper. {{get}} helper can also respect mutable values itself . sample Ember-Twiddle
{{input type="checkbox" checked=(mut (get item propertyName))}}
Get Helper reference: http://emberjs.com/api/classes/Ember.Templates.helpers.html#method_get

How to pass object to handlebars helper

Using handlebars-1.1.2 and old emberjs 1.5.1.
I've code:
{{#each queue in appController.queues_services_array}}
<label for="{{GetObjectId queue}}">{{queue.title}}</label></div>
{{/each}}
and helper:
Handlebars.registerHelper('GetObjectId', function(value) {
return value.id;
});
The problem is that data given to helper is just string "queue", not an object. I wonder how can I pass object "queue" to helper.
You can use the bind-attr helper to bind your value to a specific attribute:
<label {{bind-attr for=queue.id}}>{{queue.title}}</label>
Or alternatively if you do not expect the value to change it is possible to use the unbound helper, which yields some improved performance:
<label for="{{unbound queue.id}}">{{queue.title}}</label>
The best thing you could do would be to update to a newer version of Ember so you could make use of the newer syntax which allows you to use regular Handlebars:
<label for="{{queue.id}}">{{queue.title}}</label>
Assuming you have the time and budget.

Sane way to concat string and variable in Handlebars.js helper argument?

I'm trying to build a simple modal component in Ember, but it seems the "logic-less" of Handlebars is too illogical for me. Is there any sane way to achieve a result somewhat this?
<h2>Nice block about {{title}}</h2>
<a href="#" data-toggle="modal" id="add-item-{{title}}"> {{!this works}}
{{#my-modal modal-id="add-item-{{title}}" header='New {{title}}'}} {{! those don't}}
<p>My body blabla</p>
{{/my-modal}}
Currently I end up by getting my modal id being "add-item-{{title}}", literally, as well as the modal title.
And... no, for now I'm not considering passing the "title" as a new param and using it in the modal. The modal header in another template might not be "New {{title}}" but "are you sure?" or "details about {{title}}".
What you're looking for the is the concat helper. Using it, your second example would become:
{{#my-modal modal-id=(concat 'add-item-' title) header=(concat 'New ' title)}}
<p>My body blabla</p>
{{/my-modal}}
I got here looking for a concat helper in handlebars.js. In case it's useful to someone landing here looking for the same, handlebars-helpers has an append helper built-in.
{{> my-modal modal-id=(append "add-item-" title) header=(append "New " title)}}
https://github.com/helpers/handlebars-helpers
Yep, passing in the title is how I do it. If you need to add something to the title that's more than just model.title, then stuff a computed property on your controller (es6 string interpolation syntax):
controller
modalHeader: function() {
return `New ${this.get('model.title')}`;
}.property('model.title')
template
{{#my-modal header=modalHeader}}
<p>My body blabla</p>
{{/my-modal}}
As for the id, you can do some fun stuff in the component to override it, see this codepen, but I don't know how it messes with ember. Why do you want to set an id for a modal anyway?

how can i unbind an emberjs handlebar helper

I have a custom handlebar helper:
Handlebars.registerHelper('foo', function(key) {
return (key + ' bar');
});
and in my html I have:
{{foo beer}}
the result is
<div id="ember127" class="ember-view">beer bar</div>
how can I make my own handlebar helper act like the ember {{unbound beer}} and just produce "beer bar" without any additional markup ?
So I think you might be confused on how the helpers, templates, and Ember views work exactly. The markup you created is expected and is the exact markup you'd get with a working unbound helper.
Ember.Handlebars templates are always placed within an Ember view object (as you have above). Something that a normal bound helper would produce would be:
<div id="ember127" class="ember-view">
<script id="metamorph-1-start" type="text/x-placeholder"></script>
beer bar
<script id="metamorph-1-end" type="text/x-placeholder"></script>
</div>
Now if you want to surround your string with some other tag than a div (lets say an anchor tag or something), then you'd need to create a view, set it's template and tag name, then append that view.
Take a look at this jsFiddle and take a look at the results pane in your inspector for some examples of what I'm talking about. Hope that clears things up for you.
Ember has a helper called unbound that lets you wrap another helper. You can thus turn your bound (automatically) foo helper into an unbound one like so
{{unbound foo beer}}