I want to get the value of the textarea to use inside my route. I tried using the method below, but the alert shows 'undefined' for that value. How would I go about getting the value of the textarea from the route? I am running the latest version of ember-cli.
Template
{{textarea type="text" value='name'}}
<button {{action 'submit'}} >Send</button>
Route
actions: {
submit: function() { alert(this.get('name'));
} }
You have to pass a variable through action submit, which is bound to textarea value. Usually such a variable is defined in controller (or in wrapper component).
//template
{{textarea type="text" value=name}}
<button {{action 'submit' name}} >Send</button>
//controller
name: 'defaultName'
//route
actions: {
submit: function(val) {
alert(val);
}
}
Working jsbin here
Related
In my app I've defined this component:
// components/buy-functions.js
export default Ember.Mixin.create({
actions: {
openModal: function() {
$('#buyModal').openModal();
}
}
});
then in the route's template:
<h5>Buy form</h5>
{{#buy-functions}}
<div class="btn" {{action "openModal"}}>Buy</div>
{{/buy-functions}}
(the component does not have a template)
But when i click the button I get the error "nothing handled the "openModal" action...
Can someone explain what I'm doing wrong here?
You need to send your action to route
openModal: function(modalName) {
this.sendAction('openModal',modalName);
}
}
change your button to
<div class="btn" {{action "openModal" 'myModal'}}>Buy</div>
and then in your route
openModal: function(modalName) {
//do whatever you want
}
But another way would be:
let's change your component to
// components/buy-functions.js
export default Ember.Component.extend({
actions: {
openModal: function() {
$('#buyModal').openModal();
}
}
});
then create your component template
// tempaltes/components/buy-functions.hbs
<div class="btn" {{action "openModal"}}>Buy</div>
and then in your route template only use your component name
{{buy-functions}}
I wrote these codes on the fly. hope it works for you.
There is an add-on (ember-route-action-helper) that provides a helper (route-action) for just this very use case.
There's a blog about it.
If I define a checkbox as follows:
{{input type="checkbox" name="email" checked=controller.isEmailChecked}} Email
In the callback controller.isEmailedChecked, defined as:
isEmailChecked: function(key, value) {
...
}
How do I get the value of name ("email")?
My controller is responsible for displaying multiple checkboxes so I do not want to have to write lines like this:
{{input type="checkbox" name="x" checked=controller.isXChecked}} X
{{input type="checkbox" name="y" checked=controller.isYChecked}} Y
Only to be doing:
ixXChecked: function(key, value) {
// Set or Get
this.set('x', value);
this.get('x');
}
ixYChecked: function(key, value) {
// Set or Get
this.set('y', value);
this.get('y');
}
Can someone point me to the docs please.
Edit: Same applies to actions on Buttons:
<button {{action 'toggleSetting'}}>
</button>
How would I get the name of the element in the toggleSetting callback?
Thanks a lot,
Thanks albertjan but this is more simple:
{{view Ember.Checkbox checkedBinding=someModelProperty}}
It updates the someModelProperty when clicked, and it also sets the correct value initially.
You can pass a parameter to a action like this: {{action "post" "test"}} where the second test can also be a variable. {{action "post" mail}}
As for the checkboxes I'd solve that with an item controller:
{{#each thing in things itemController='thing'}}
{{input type="checkbox" checked=onChecked}}
{{/each}}
and your controller would looks something like:
App.ThingController = Ember.Controller.extend({
needs: ['parent'] //where parent is the name of your other controller.
action: {
isChecked: function() {
this.get('contollers.parent')
.send('checkboxChecked', this.get('model.name'));
}
}
});
Or you can add a component, lets call it named-checkbox. And that would look something like this:
Template (app/templates/components/named-checkbox.hbs):
{{input name=name type="checkbox" checked=onChecked}}
{{yield}}
Component (app/components/named-checkbox.js):
import Ember from 'ember';
import layout from '../templates/components/named-checkbox';
export default Ember.Component.extend({
layout: layout,
name: "",
action: {
onChecked: function() {
this.sendAction(this.get('action'), this.get('name'));
}
}
});
Then you can use it like this:
{{named-component name="email" action=isChecked}}
This will result in the isChecked action being called on the controller with the name as it's attribute:
actions: {
isChecked: function(name) {
this.set('name', !this.get('name'))
}
}
I want to display an input field, and immediately autofocus it upon clicking a button. Im still new to Ember so i am not sure this is the correct approach, but I tried to wrap as an ember component
template
{{#if showCalendarForm}}
{{new-calendar focus-out='hideNewCalendar' insert-newline='createCalendar'}}
{{else}}
<button class="btn btn-sm btn-primary" {{action "showNewCalendar"}}>New</button>
{{/if}}
new-calendar component handlebars:
<div class="input-group">
{{input
class = 'form-control'
id = 'newCalendar'
type = 'text'
placeholder = 'New calendar'
value = calendarName
action = 'createCalendar'
}}
</div>
new-calendar component js
import Ember from 'ember';
export default Ember.Component.extend({
didInsertElement: function() {
this.$().focus();
}
});
When I click the button, the text field is displayed, but autofocus and hitting enter doesnt work
The way the jQuery is written, you are trying to set focus on the <div class="input-group">, try this instead:
didInsertElement: function() {
this.$('input').focus();
}
Another way to do this would be to extend the Ember.TextField:
export default Ember.TextField.extend({
becomeFocused: function() {
this.$().focus();
}.on('didInsertElement')
});
Then, in your new-calendar template, use this component:
{{focus-input
class = 'form-control'
id = 'newCalendar'
type = 'text'
placeholder = 'New calendar'
value = calendarName
action = 'createCalendar'
}}
This way you can reuse the focus-input component wherever you need to.
As for hitting enter to create the calendar, I think you want to listen for the keyPress event, check to see if it's the enter key, and then send the action rather than trying to use insert-newline='createCalendar'.
//in FocusInputComponent
keyPress: function(e) {
// Return key.
if (e.keyCode === 13) {
this.sendAction();
}
}
Try wrapping your focus call in an Ember.run and schedule it to be run in the after render queue like this:
didInsertElement: function()
{
Ember.run.scheduleOnce('afterRender', this, function() {
this.$().focus();
});
}
this blog post has helped me a lot in understanding ember's lifecycle hooks:
http://madhatted.com/2013/6/8/lifecycle-hooks-in-ember-js-views
On the handlebars template, I'd like to pre-populate an input field with the value. That I can do by putting value=object.property. Then the user should update the value, and when they click the button activating the action, the value should submit to the Component.
The problem is that no value is getting submitted, not the pre-populated value, or the new value. When I console.log what is getting submitted to the component, the input from the text field is "undefined" and the input from the number field is "NaN".
This is my handlebars template:
{{input type="text" value=object.name valueBinding='newName'}}
{{view App.NumberField min='1' value=object.count valueBinding='newCount'}}
<button {{action updateObjectDetails object}}>Save</button>
The related component it is submitting to:
App.ObjectsDetailsComponent = Ember.Component.extend({
actions: {
updateObjectDetails: function(object){
object.set("name", this.get('newName'))
object.set("party_size", parseInt(this.get('newCount')))
object.save();
}
}
});
Is there a way to populate the input field with the correct value AND have it submit with the action?
Ah, got it. The thing is to not try to use the valueBindings, like you might when creating a new object, but to use the actual value, because the actual value is changing. So in the component, it's object.get('name'), not this.get('newName').
Therefore the handlebars should be like this:
{{input type="text" value=object.name}}
{{view App.NumberField min='1' value=object.count}}
<button {{action updateObjectDetails object}}>Save</button>
And the component like this:
App.ObjectsDetailsComponent = Ember.Component.extend({
actions: {
updateObjectDetails: function(object){
object.set("name", object.get('name'))
object.set("party_size", parseInt(object.get('count')))
object.save();
}
}
});
I'm new to Ember and am finding some of their concepts a bit opaque. I have a app that manages inventory for a company. There is a screen that lists the entirety of their inventory and allows them to edit each inventory item. The text fields are disabled by default and I want to have an 'edit item' button that will set disabled / true to disabled / false. I have created the following which renders out correctly:
Inv.InventoryitemsRoute = Ember.Route.extend({
model: function(params) {
return Ember.$.getJSON("/arc/v1/api/inventory_items/" + params.location_id);
}
<script type="text/x-handlebars" data-template-name="inventoryitems">
{{#each}}
<div class='row'>
<p>{{input type="text" value=header disabled="true"}}</p>
<p>{{input type="text" value=detail disabled="true"}}</p>
<button {{action "editInventoryItem" data-id=id}}>edit item</button>
<button {{action "saveInventoryItem" data-id=id}}>save item</button>
</div>
{{/each}}
</script>
So this renders in the UI fine but I am not sure how to access the specific model to change the text input from disabled/true to disabled/false. If I were just doing this as normal jQuery, I would add the id value of that specific model and place an id in the text input so that I could set the textfield. Based upon reading through docs, it seems like I would want a controller - would I want an ArrayController for this model instance or could Ember figure that out on its own?
I'm thinking I want to do something like the following but alerting the id give me undefined:
Inv.InventoryitemsController=Ember.ArrayController.extend({
isEditing: false,
actions: {
editInventoryItem: function(){
var model = this.get('model');
/*
^^^^
should this be a reference to that specific instance of a single model or the list of models provided by the InventoryitemsRoute
*/
alert('you want to edit this:' + model.id); // <-undefined
}
}
});
In the Ember docs, they use a playlist example (here: http://emberjs.com/guides/controllers/representing-multiple-models-with-arraycontroller/) like this:
App.SongsRoute = Ember.Route.extend({
setupController: function(controller, playlist) {
controller.set('model', playlist.get('songs'));
}
});
But this example is a bit confusing (for a couple of reasons) but in this particular case - how would I map their concept of playlist to me trying to edit a single inventory item?
<script type="text/x-handlebars" data-template-name="inventoryitems">
{{#each}}
<div class='row'>
<p>{{input type="text" value=header disabled="true"}}</p>
<p>{{input type="text" value=detail disabled="true"}}</p>
<button {{action "editInventoryItem" this}}>edit item</button>
<button {{action "saveInventoryItem" this}}>save item</button>
</div>
{{/each}}
</script>
and
actions: {
editInventoryItem: function(object){
alert('you want to edit this:' + object.id);
}
}
Is what you need. But let me explain in a bit more detail:
First of all, terminology: Your "model" is the entire object tied to your controller. When you call this.get('model') on an action within an array controller, you will receive the entire model, in this case an array of inventory items.
The {{#each}} handlebars tag iterates through a selected array (by default it uses your entire model as the selected array). While within the {{#each}} block helper, you can reference the specific object you are currently on by saying this. You could also name the iteration object instead of relying on a this declaration by typing {{#each thing in model}}, within which each object would be referenced as thing.
Lastly, your actions are capable of taking inputs. You can declare these inputs simply by giving the variable name after the action name. Above, I demonstrated this with {{action "saveInventoryItem" this}} which will pass this to the action saveInventoryItem. You also need to add an input parameter to that action in order for it to be accepted.
Ok, that's because as you said, you're just starting with Ember. I would probably do this:
<script type="text/x-handlebars" data-template-name="inventoryitems">
{{#each}}
<div class='row'>
<p>{{input type="text" value=header disabled=headerEnabled}}</p>
<p>{{input type="text" value=detail disabled=detailEnabled}}</p>
<button {{action "editInventoryItem"}}>edit item</button>
<button {{action "saveInventoryItem"}}>save item</button>
</div>
{{/each}}
</script>
with this, you need to define a headerEnabled property in the InventoryitemController(Note that it is singular, not the one that contains all the items), and the same for detailEnabled, and the actions, you can define them also either in the same controller or in the route:
App.InventoryitemController = Ember.ObjectController.extend({
headerEnabled: false,
detailEnabled: false,
actions: {
editInventoryItem: function() {
this.set('headerEnabled', true);
this.set('detailEnabled', true);
}
}
});
that's just an example how you can access the data, in case the same property will enable both text fields, then you only need one, instead of the two that I put . In case the 'each' loop doesn't pick up the right controller, just specify itemController.