Reset check boxes after form submission - ember.js

I've created a simple form to add items to my database. Each item hasMany skills so I've set up a #each to iterate over each skill and add checkbox into the form. I'm doing this by using a render helper in my form because a different controller contains the skills. So I have this in my items/new template:
{{render 'skills'}}
And then my skills template looks like this:
<script type="text/x-handlebars" data-template-name="skills">
<div class="form-group">
{{#each skill in model itemController="skillCheckbox"}}
<div class="checkbox">
<label>
{{input type="checkbox" checked=selected}}
{{skill.name}}
</label>
</div>
{{/each}}
</div>
</script>
My itemController is like this:
App.SkillCheckboxController = Ember.ObjectController.extend({
needs:['itemsNew'],
selected:function() {
var skill = this.get('content');
var skills = this.get('controllers.itemsNew.model.skills');
return skills.contains(skill);
}.property('controllers.itemsNew.model.skills'),
selectedChanged:function() {
var skill = this.get('content');
var controller = this.get('controllers.itemsNew.model.skills');
if(this.get('selected')) {
controller.addObject(skill);
} else {
controller.removeObject(skill);
}
}.observes('selected')
});
Everything works fine and the new item is submitted to server properly. The problem is that I'm going to be entering in a lot of items so I have the form setup to automatically reset after a new item is saved. I do this by created a new record and setting it as the model:
actions:{
save:function() {
var self = this;
var model = this.get('model');
var promise = model.save();
promise.then(function(){
var newModel = self.store.createRecord('item');
self.set('model',newModel);
});
}
}
All the other form fields reset as normal, except for the skill checkboxes and I can't figure out why. I've tried adding the itemsNew model to the observer or removing the skills from the model manually, but it doesn't update in the browser.
Any ideas on why this isn't working or suggestions on how to do it better/correctly? Any help would be appreciated. Thanks!

You're breaking the computed property when people click the check box. Computed properties are just that, a computed property. It's a property that's derived based on the other properties (and generally just a getter). It isn't a property that's derived on other properties, then you set it, and then it decides to start being a computed property again.
That's essentially what's happening here, you're overwriting the computed property with just a value (true/false).
That being said, you'll want to try another approach, where selected is just a property, and another property set's it to start (and when they click it of course).
App.SkillCheckboxController = Ember.ObjectController.extend({
needs:['itemsNew'],
selected:false,
initialSetup: function(){
var skill = this.get('content'),
skills = this.get('controllers.itemsNew.model.skills');
this.set('selected', skills.contains(skill));
}.observes('model', 'controllers.itemsNew.model.skills')
});

Related

EmberJS : How to dynamically reload model and template (after an action, ex 'button pressed')

EmberJS version 1.11.3
I have a button that when pressed, sends an Ajax query to my server and returns some data. I would like to refresh the view under this button with the new data each time.
Here's the simplified handlebar template :
<script type="text/x-handlebars" data-template-name='query'>
<form class="form-vertical" {{action "sendQuery" model}}>
<div class="control-group">
{{input value=this.totoQuery type="text" placeholder="Enter an SQL query...."}}
</div>
<button type="submit" class="btn">Send ! </button>
</form>
</script>
Here's the controller for that template:
App.QueryController = Ember.Controller.extend({
totoQuery: '',
actions: {
sendQuery: function(model, route) {
var promise = asyncAjax(queryservice + '?query=' + this.totoQuery);
promise.success(function(data) {
model=data.entries;
})
}
}
})
The Ajax call works fine and the model defined in the route too ( i tested with a dummy model ). However when i try to update the model with :
model=data.entries; //The template does not update with it!!! The template still displays the data from the dummy model.
I can't modify it with this.set('model',data) because "Undefined function!! this.set"..
My dummy model :
App.QueryRoute = Ember.Route.extend({
model: function() {
return [{
'title': 'A book title like Harry Potter of Fifty Sha... nvm.. '
}];
}
});
Any advice is greatly appreciated!!!
PS: I've been spending way too much time on this :(
You can get the model inside controller action in the following way:
sendQuery: function() {
var self = this,
totoQuery = this.get('totoQuery');
var promise = asyncAjax(queryservice + '?query=' + totoQuery);
promise.done(function(data) {
$.each(data.entries, function (index, entry){
self.get('model').pushObject(entry);
});
})
}
And you do not need to pass model as parameter in action. You can do something like this:
<form class="form-vertical" {{action "sendQuery"}}>
The controller automatically inherit the model property. And one thing is, getting model property using this.totoQuery will be deprecated in Ember. Instead use model.totoQuery.
If you are struggling too much, you can also render something from your controller instead of the model directly from the route, that way you can update the variable from controller and would change easily.
App.QueryController = Ember.Controller.extend({
queryResponse: [],
totoQuery: '',
actions: {
sendQuery: function(model, route) {
var self = this;
var promise = asyncAjax(queryservice + '?query=' + this.totoQuery);
promise.success(function(data) {
//model=data.entries;
self.set('queryResponse', data.entries);
})
}
})
And in your template you can render it directly
<ul>
{{#each item in controller.queryResponse}}
<li>item.name</li>
{{/each}}
</ul>

Bind Checkbox Settings to Array Content in EmberJS

I have a group of checkboxes in an EmberJS app. I would like to maintain a property in the controller that corresponds to the checked boxes (e.g. contains a string entry with the id of each box that is checked). This property should update itself as boxes are checked or unchecked. What is the best way to do this?
Computed property would do
F.e.
App.MyController = Em.ObjectController.extend({
checkboxValues : [Em.Object.create({id:1, check:false}), Em.Object.create({id:2, check:true})],
checkedIds : function() {
return this.get('checkboxValues').filterBy('check').mapBy('id').join(',');
}.property('checkboxValues.#each.check')
});
//template
{{#each checkboxValues}}
{{id}} {{input type="checkbox" name="checkbox" checkedBinding="check"}}
{{/each}}
{{checkedIds}}

Ember.js How to properly filter a model in a component

I have the following auto complete component:
Initial idea from EmberCasts: Building an Autocomplete Widget Part 1
App.AutoCompleteComponent = Ember.Component.extend({
searchText: null,
searchResults: function() {
var model = this.get('model');
var searchText = this.get('searchText');
console.log(this.get('model')); // shows array
if (searchText){
console.log('searching for: ' + searchText); // shows up in console with searchText
var regex = new RegExp(searchText, 'i');
model = model.filterBy('name', function(name) {
console.log(name); // never got reached
return name.match(regex);
});
}
return model;
}.property('searchText')
});
My template:
{{auto-complete model=controllers.categories}}
<script type="text/x-handlebars"s data-template-name="components/auto-complete">
{{input type="text" value=searchText placeholder="Search..."}}
<ul>
{{#each searchResults}}
<li>{{this}}</li>
{{/each}}
</ul>
</script>
The problem is, that no model item get returned. At the initial state of the program all my categories are shown - I will fix that soon. But it shows me that the auto-complete component does work. The model does get returned at first.
I think the FilterBy does not what I expect it should do.
I have tried to change the FilterBy part to this and search exactly for the name:
model = model.filterBy('name', searchText);
But that did also not work. Any ideas?
you're second approach is the correct one with filterBy, if you want to pass a function you would use filter.
model = model.filterBy('name', searchText);
I bet name doesn't exist on your models, or something along those lines. If you need more help show us an example of the categories model.
http://emberjs.jsbin.com/oTIxAjI/1/edit
You'll want to use filter
http://emberjs.jsbin.com/oTIxAjI/4/edit

EmberJS: Property Scopes in an ArrayController?

this is probably a grossly simple question to answer, so I apologize if I am cluttering this forum in advance.
I am displaying a list of items that share the same model and controller.
I made these items editable via a <button {{ action 'edit' }}> next to each item which toggles a boolean value of a property "isEditable" in the controller.
However clicking this button causes all items in the list to become editable because they all share the controller property "isEditable". The desired effect is to make a single item editable at a time instead of all items at once.
A simplified version of my template looks like this:
{{#if isEditing}}
<p>{{input type="text" value=title}}</p>
<button {{action 'doneEditing'}}>Done</button>
{{else}}
<span class="title">{{title}}</span>
<button {{action 'edit'}}><span class="edit"</span></button>
{{/if}}
and the controller looks like this
App.ItemController = Ember.ArrayController.extend({
isEditing : false,
actions : {
edit : function(){
this.set('isEditing', true);
},
doneEditing : function(){
this.set('isEditing', false);
},
}
});
Anybody know how to accomplish this? Is it because each item shares the "isEditable" property? If so, how do I get around this? I don't want to put this into the model because it's purely a display thing, even though I know I can get it to work doing that.
Thanks :)
By default the controller lookup within an {{#each}} block will be the controller of the template where the {{#each}} was used. If each item needs to be presented by a custom controller (to hold it's own state for example) you can provide a itemController option which references a controller by lookup name. Each item in the loop will be then wrapped in an instance of this controller and the item itself will be set to the content property of that controller.
So, I assume you are displaying the list of items using the {{#each}} helper. Therefore you can specify an itemController in the {{#each}} helper to hold the isEditable state on a per item basis. This would look something like this:
{{#each item in controller itemController="item"}}
...
{{/each}}
Moreover you should define the defined itemController of type Ember.ObjectController like:
App.ItemController = Ember.ObjectController.extend({
isEditing : false,
actions : {
edit : function(){
this.set('isEditing', true);
},
doneEditing : function(){
this.set('isEditing', false);
},
}
});
And for the list you should then have an App.ItemsController of type Ember.ArrayController:
App.ItemsController = Ember.ArrayController.extend({});
See here for more info on the mentioned itemController support for the {{#each}} helper: http://emberjs.com/api/classes/Ember.Handlebars.helpers.html#method_each
Hope it helps.

How to build a form with access to text input values on submit with ember.js

I'm using the latest pre 1.0 of ember.js and wanted to get away from using the deprecated button for simple forms.
I have something that works but I don't feel like this is the correct way to wire up a view that has both a text input and a button that needs access to that text.
Here is the basic view
{{#view PersonApp.AddPersonView}}
{{view Ember.TextField valueBinding="username"}}
{{#with this as username}}
<input type="submit" value="add" {{action addPerson username}}/>
{{/with}}
{{/view}}
Here is the view
PersonApp.AddPersonView = Ember.View.extend({
username: null,
addPerson: function(event) {
var username = event.context.username;
if (username) {
PersonApp.personController.addPerson(username);
this.set('username', ''); //this does not currently work
}
}
});
The only other issue I'm having is that I don't have access to username the usual way. ie - this.get('username') but in addition I can't clear the textbox value (even though it's shown above).
I'm looking to build a modern version of this gist (previous version of ember) https://gist.github.com/1477225
I see three issues here (perhaps there are more). First, username will not be a field in the event.context, but will actually be the event context. Secondly, I believe you need to specify view.username in the valueBinding, otherwise the controller is the default home of the property (I believe). Then, to set it to initial state you need to set it to null. Third, the target of your action will be the router, so you need to specify the view as the target.
This should work:
{{#view PersonApp.AddPersonView}}
{{view Ember.TextField valueBinding="view.username"}}
{{#with this as username}}
<input type="submit" value="add" {{action addPerson username target="this"}}/>
{{/with}}
{{/view}}
PersonApp.AddPersonView = Ember.View.extend({
username: null
addPerson: function(event) {
var username = event.context;
if (username) {
this.get('controller').addPerson(username);
this.set('username', null);
}
}
});
Also, a better way of creating a new person would be to create a blank person model, bind the controller and view to that, and then save the record, afterwards setting the binding back to null.
You can do the validation and then pass data right now, even with Gidrius' code. The only thing you need to do is write the validation code in the submit handling method. Or, 'cause we`re talking client-side validation anyway, you can do it on field value change or blur, which will give the user almost instant feedback on what he is doing.
I still couldn't get something like this.get('username') to work but I ended up with the following
{{#view PersonApp.AddPersonForm}}
{{view Ember.TextField valueBinding="username"}}
<input type="submit" value="add" {{action addPerson this}}/>
{{/view}}
PersonApp.AddPersonForm = Ember.View.extend({
addPerson: function(event) {
var username = event.context.username;
if (username) {
PersonApp.personController.addPerson(username);
event.context.set('username', '');
}
}
});
probably a bit too late, but might be helpful to someone else.
Usually form field value will be bind to controller or model, so all you need is to have is a submit function in the controller so whenever function will be called you will have access to the fields via bindings.
Here is how it all could look like, assuming you are using latest pre.4 ember
Updated
// DOM part
<form {{action submitForm on="submit"}}>
{{view Ember.TextField valueBinding="username"}}
<button type="submit">add</button>
</form>
And here is a controller
PersonApp.PersonController = Ember.ArrayController({
username: '',
submitForm: function() {
var u = this.get('username'); // saving value to variable
this.set('username',''); // sets username to ''
console.log(u); // will output saved username
}
});