using Actions inside the input helper - ember.js

Using the action helper works fine inside a DOM element:
<input value="123" {{action "someAction" on="click"}}
But then let's say you are using the input helper to generate your input field:
{{input value=123}}
And you want to stick the very same action onto this input helper..
The docs say:
" To dispatch an action on specific events, such as enter or key-press, use the following
{{input value=123 key-press="updateFirstName"}} "
And yet..
This code does nothing:
{{input type="text" value=123 click="someAction"}}
I also tried this:
{{input type="text" value=123 action="someAction" on="click"}}
I'm slowly going insane. Can someone point me to the correct way of using actions inside the Ember input helper?
Thanks!

{{input value=123 key-press="updateFirstName"}}
The above code will work fine. make sure updateFirstName is in the required context like if its in template then it should be present in controller or if its in component then it should be present in component.js file.
For click handler, you can try like the below.
{{input value=appName click=(action "onClick")}}
You can have look at this twiddle.

Related

How to use a component from within a component in Ember

G'day all,
I'm trying to wrap a component with another to provide a simplified editing wrapper.
The component is to conditionally show either a label or a select component that allows the user to pick the right value.
I want to wrap the power-select component, and pass it's values through to the sub-component, so the page template component reference looks like this:
{{cm-select
title="Country ##"
options=countries
selected=selectedCountry
searchField="name"
action="selectCountry"
}}
"countries" is an array of country objects, and selectedCountry is one of those country objects.
The component template has the following:
<td>{{title}}</td>
<td>
{{#if edit}}
{{#power-select
options=options
selected=selected
searchField=searchField
as |object|}}
{{object.name}}
{{/power-select}}
{{else}}
<small>{{modelElement}}</small>
{{/if}}
</td>
Unfortunately the power-select component renders with an empty list of options.
I thought wrapping those parameters in handlebars might do the trick, but it seems that handlebars in handlebars isn't a valid syntax.
Does anyone have any ideas?
Thanks,
Andy
That should work, I created a twiddle for you, demonstrating your use case. You'll see I updated the your cm-select template to this:
{{title}} |
<button {{action 'toggleEdit'}}>Toggle Edit</button>
<br/>
{{#if edit}}
Search for a Item via {{searchField}}
<br/>
{{power-select
options=options
selected=selected
searchField=searchField
onSelect=(action "itemSelected")
}}
{{else}}
{{search-list
options=options
searchField=searchField
onSelect=(action "itemSelected")
}}
{{/if}}
Where you iterated over options for power-select in the cm-select component, I moved that down into the power-select template. It's better to try and encapsulate some functionality there, instead of having everything in cm-select. I wasn't sure what you had in mind with {{modelElement}} so I just demonstrate what it would look like, using two different components in cm-select.

where would I define this helper in Ember for handling site search functionality

I am just starting out with Ember and am curious if I had a template like the following:
<script type="text/x-handlebars">
<input type='text' id='myVal' /><button {{action "searchInventory"}} class='search_inventory'>search inventory</button>
{{outlet}}
</script>
Where would I define the searchInventory helper? It seems like it might be in some global controller that might forward it to a search results route; I have an InventoryItemController but how can I hook up the searchInventory action to this? What would be the Ember way to set this up?
Can I tell ember when invoking the action to use that controller like:
{{action "searchInventory" controller:"InventoryItem" }}
thx
I don't know how you have structured your app, but assuming you have a controller for the template above, you should define the action on that controller within an 'actions' hash. Also, you should use the
{{input}}
handlebars helper instead of using the input tag. If you do that, you can have a property on the controller for this template, say 'searchTerm' for which you can provide a valueBinding, like this:
{{input type="text" valueBinding="controller.searchTerm"}}
This will bind the input the user types into the input element to the searchTerm property on the controller. Hope this helps.

action on enter in ember

Is there anyway for this text input
<input type="text" aria-controls="existing-user-table" placeholder="Search">
to trigger an action on the controller when the user hits enter?
I don't like to enclose it in a form tag or create a button, just that input textfield.
Use the {{input}} helper - if you include an action parameter it will trigger that action on the controller when the user hits enter. So:
{{input action="myAction" aria-controls="existing-user-table" placeholder="Search"}}
The input helper api docs do not mention this capability, but the helper just wraps Ember.TextField
Also it is possible to trigger the action on keyPress instead of enter by specifying the onEvent property:
{{input action="myAction" onEvent="keypress" aria-controls="existing-user-table" placeholder="Search"}}
The input helper has an insert-newline action that will trigger when the user hits the enter key.
{{input type='text' aria-controls='existing-user-table' placeholder='Search' insert-newline='myAction'}}
Text Input Helpers
Insert Newline docs
From Ember v1.13.0 the action on input helper is depricated we should use useenter or key-press instead of action
Refer Ember Docs
{{input value=someValue enter='someAction'}}
this will trigger the mentioned action when the user press enter on the text input

ember.js does not {{bindAttr}} the <label> For attibute to the correct inputField.elementId in a collection

I'm trying to link a label to an input field using the {{bindAttr}} and the input field's [viewName].elementId. It works on a single entry view, but not when there are several records being displayed: it just links the label to the last input field in the collection. (This used to work in a previous iteration using an older ember library but now it doesnt.) I've created a fiddle but the gist of it is:
{{#each controller}}
<fieldset>
<label {{bindAttr for="view.tbFullName.elementId"}}>Full Name</label>
{{view App.DetailTextField viewName="tbFullName" placeholder="Full Name" valueBinding="fullName" readonly="readonly"}}
</fieldset>
{{/each}}
I thought maybe I could create a collectionView and create a calculated property for viewName which would generate a unique ID for each item in the collection, sort of mentioned in answer to another problem here. But that is getting WAY too complicated - just so that I can have the input field highlight itself if the user clicks on the corresponding label.
Any help appreciated.
Create a wrapper Ember.View around the label and input field. Let's call it App.FieldView:
App.FieldView = Ember.View.extend({
tagName: 'fieldset'
});
Then in your template:
{{#each controller}}
{{#view App.FieldView}}
<label {{bindAttr for="view.tbFullName.elementId"}}>Full Name</label>
{{view App.DetailTextField viewName="tbFullName" placeholder="Full Name" valueBinding="fullName" readonly="readonly"}}
{{/view}}
{{/each}}
Fiddle: http://jsfiddle.net/NQKvy/26/
Panagiotis Panagi, has answered the question correctly. I'll just add why this is happening, ie:- linking to the incorrect view.
The view property inside a template refers to the Ember View wrapping the html markup. This property however has different value depending on the context it is in.
This value is dependent on the view block it placed in. By default the template itself corresponds to a view in this case, ListOfPeopleTemplateView.
So when you are binding to view.tbFullName.elementId, you are actually binding to an {instance of ListOfPeopleTemplateView}.tbFullName.elementId. And when the loop finishes the only tbFullName visible is the last one.
Panagiotis Panagi's solution is to wrap the label inside another view, so the value of view changes to within that block, and hence points to the correct tbFullName
Finally an even easier way to achieve the same result is to wrap the textfield inside the label. Then you do not need the label for binding at all.
<label>Full Name
{{view App.DetailTextField viewName="tbFullName" placeholder="Full Name" valueBinding="fullName" readonly="readonly"}}
</label>
See this jsfiddle
Forms are somewhat tricky I must admit if you want to do things right. But there are is an ember add-on that comes to the rescue, for example easyForm.
Have a look it might helps you solving exact the problems you are facing, like the ones on having unique labels for your form fields etc.
Hope it helps.

How do I create a reusable partial for duplicate markup in ember.js?

Given this chunk of HTML:
<div id="email_field" class="control-group">
<label class="control-label" for="account.email">Email</label>
<div id="email_input" class="controls">
<input id="account.email" name="account.email" type="text" placeholder="jpublic#example.com">
<span class="help-block">We just need a valid email address.</span>
</div>
</div>
How do I turn this into a re-usable partial for whatever attribute I want? IE: email, password, password confirmation, etc.
I would assume some sort of view hierarchy but I'm not quite sure.
EDIT: After further exploration I've knocked out {{view}} and {{render}} and figured out exactly what I need:
I want to:
1. Use a specific view (InputView)
2. Use a specific controller (Preferably similarly named: InputController) ({{view}} doesn't do this I think)
3. Be able to use this multiple times ({{render}} can't do this)
4. Be able to pass in values ({{render}} can't do this)
Example:
<!-- templates/application.hbs -->
{{foo "input" name="Email" id="account.email" placeholder="jpublic#email.com"}}
// controllers/input.js
Application.InputController = Ember.ObjectController.extend({
type: "text"
});
// views/input.js
Application.InputView = Ember.View.extend({
templateName: "form/input"
});
<!-- templates/form/input.hbs -->
<input {{bindAttr id="id" name="name" type="type" placeholder="placeholder"}}>
I would create a view that takes all the parameters that are variable. Such as:
{{view App.FormEntity
name="email"
placeholder="My placeholder..."
help="We just need a valid email address."
valueBinding="value"
}}
From there you could extract the label, the various class names, and then use Ember.TextField to bind the value to.
Once you have all of those arguments passed into the view, it should be nice and easy to create the markup using a mixture of bindAttrs, a couple of computed properties, and Ember helpers (such as the Ember.TextField).
I am new to Emberjs and looking for pretty much the same thing, but couldn't you also simply use http://emberjs.com/guides/templates/writing-helpers/ for that?
I will try it myself, so can give more updates if that works out.
Update:
Ok, I got it to work. I created a new Helpers folder with FormgeneratorHelper.js and the following code:
Ember.Handlebars.registerBoundHelper('control-group', function (options) {
var name = options.hash.test.capitalize();
console.log(name);
return new Handlebars.SafeString('<div class="control-group"> \
<label class="control-label" for="input' + name + '">' + name + '</label> \
<div class="controls"> \
<input type="text" id="input' + name + '" placeholder="' + name + '" /> \
</div> \
</div>');
});
An then, no matter in which template you can do:
{{control-group test="email"}}
I really like the idea of using helpers, but if you are using plain Javascript (as opposed to CoffeScript) and have more than one line of code, then it gets a bit ugly unfortunately. But will probably still use that method.
How do I turn this into a re-usable partial for whatever attribute I want? IE: email, password, password confirmation, etc.
What you want is the experimental {{control}} helper. The control helper is currently under development and is considered experimental. To enable it, set ENV.EXPERIMENTAL_CONTROL_HELPER = true before requiring Ember.
I want to:
1. Use a specific view (InputView)
2. Use a specific controller (Preferably similarly named: InputController) ({{view}} doesn't do this I think)
Out-of-box the control helper expects to be passed a template name. That template name is used to lookup a matching view and controller. So for example:
App.InputView = Ember.View.extend()
App.InputController = Ember.Controller.extend()
{{control input}}
See:
A control renders a template with a new instance of the named controller and view
A control's controller and view are lookuped up via template name
Be able to use this multiple times ({{render}} can't do this)
A control can be used multiple times
Be able to pass in values ({{render}} can't do this)
Like the {{view}} helper, {{control}} will accept arbitrary name/value pairs. So as in your example, one could manually pass options to the control helper. Like the {{view}} helper these options become properties on the view instance:
<!-- templates/form/input.hbs -->
<label class="control-label" {{bindAttr for="view.inputId"}}>
{{view.label}}
</label>
<div class="controls">
<input {{bindAttr id="view.inputId" name="view.name" type="type" placeholder="view.placeholder"}}>
<span class="help-block">{{view.help}}</span>
</div>
// controllers/form_input.js
App.FormInputController = Ember.ObjectController.extend({
type: "text"
});
// views/form_input.js
App.FormInputView = Ember.View.extend({
classNames: ["control-group"]
});
<!-- templates/application.hbs -->
{{control "form/input"
inputId="account.email"
name="email"
label="Email"
placeholder="jpublic#email.com"
help="We just need a valid email address."
}}
See this jsbin for working example
Also keep in mind that A control can specify a model to use in its template - with this in place we can bind properties to model data. Also if a controller's model changes, its child controllers are destroyed so the control will reset as expected if the model is swapped out.