How to handle ember checkbox binding - ember.js

I am new with ember and I have a question about checkbox binding.
Here is my js && hbs :
CompletedToday(id){
var today = new Date().toISOString().slice(0, 10);
this.get('DS').findRecord('menu',id).then((recs) => {
recs.get('completedDates').pushObject(today);
recs.save();
});
},
{{#each menu}}
{{input type="checkbox" checked=this.checkCompleteToday click=(action "CompletedToday" menu.id)}}
{{/each}}
Menu is a model has a attribute called Completed date, which is a array contains a list of dates(YYYY-MM-DD), there should be a constructor function to check if it’s completed TODAY, if it is completed, make the checkbox of that menu as checked. If not, user can check the specific checkbox I don’t know how to handle this actually, do i need to create another attribute for menu?
Any suggestion would be appreciated

First you need a computed property that returns true or false if TODAY is in the model.
you should create in your component a computed property like:
checked = computed('model', function() {
// pseudocode bellow
return (TODAY in array)
})
Now, if it is unchecked (TODAY not in array), you should be able to insert in array.
In you hbs:
{{input type="checkbox" checked=checked click=(action "CompletedToday" menu.id)}}
(you shouldn't use "this" to reference the property)
If "CompletedToday" is in your component actions, it should work.
I hope this helps

Related

Ember Checkbox -- Accessing model property from different controller

I have a checkbox on a modal popup and need it to be checked based on the value on an unrelated model. The model is Team and the property I need to access is called syncAccount (boolean), so the input helper would likely look something like this:
{{input type="checkbox" name="syncAccount" checked=team.syncAccount }}
How can I access or bind to team.syncAccount from the modal? I have a ModalImportController, but no associated route. Is there some way in this controller I can assign a property that looks up or binds to the value of syncAccount for the current team (and is updated as they toggle it)?
Similarly, I need toggling the checkbox to send an update request for this field. Will this need to be an ajax request, or is there some way to set the model used by the checkbox to point to a team so that I can call #model.save()?
To get access to a property from another controller you first need to include that via needs like so:
App.ModalImportController = Ember.ArrayController.extend({
needs: "team",
teamController: Ember.computed.alias("controllers.team"),
});
then you would have access to it's properties like so:
// still in ModalImportController
syncAccount: function() {
return this.get('teamController.syncAccount');
}.property('teamController.syncAccount')
I haven't tested it now, but that's the way I did it in a slightly different setup.
source:
[http://guides.emberjs.com/v1.13.0/controllers/dependencies-between-controllers/][1]
For toggeling to send an update request I use:
syncAccount: Ember.computed('model.syncAccount', {
get: function() {
return this.get('model.syncAccount');
},
set: function(key, value) {
this.set('model.syncAccount', value);
// do all you need to do via AJAX here
return value;
}
})
note, that you also GET the value from here, so change your input-helper to:
{{input type="checkbox" name="syncAccount" value=syncAccount }}

Ember Select not firing on Change

I know this is a common problem, but I can't get an Ember.Select view to fire on its value changing. I'd either like to update the selectedInvitation based on the selection in the drop down, or call an action that will perform this behavior.
I've tried variations on Binding Action in Ember.Select and haven't had any luck.
models/uservisit.js
Models.Invitation = DS.Model.extend({
sameSeriesOpenInvitations: DS.hasMany('uservisit', {
async: true
})
});
controllers/user/invitations_controller.coffee
Visitdays.InvitationsController = Ember.ArrayController.extend
selectedInvitationObserver: (->
debugger
if #get('selectedInvitation')
#get('selectedInvitation')._data.event
).observes('selectedInvitation')
actions:
setSelectedInvitation: (invitation) ->
debugger
if invitation
#set 'selectedInvitation', invitation
invitations.emblem
.input-group.full-width
= view Em.Select contentBinding=selectedInvitation.sameSeriesOpenInvitations optionValuePath="content" optionLabelPath="content.event.startTimeFormatted" value="selectedInvitation" class="form-control"
Thanks to #ahmed.hoban who got me in the right direction. I didn't need an action or anything. Since I wanted to deal with the object and not just the id, I really only needed to change the Ember.Select view's selection attribute to the object I wanted to observe change:
.input-group.full-width
= view Em.Select content=selectedInvitation.sameSeriesInvitations optionValuePath="content.id" optionLabelPath="content.visit.startTimeFormatted" selection=selectedInvitation class="form-control"

Programmatically setting computed property of an itemController

I have a template with the following code:
{{#each types itemController='type'}}
<div class='col checkbox'>
<label>
{{input type='checkbox' checked=isSelected disabled=notAllowed}}
<span {{bind-attr class='isSelected'}}>{{name}}</span>
</label>
</div>
{{/each}}
types is set in setupController:
this.store.find('type').then(function(types){
controller.set('types', types);
});`
//Having 2 other models here that I am setting and having an itemController for, exactly in the same fashion as types.
for the ArrayController which has the itemController.
NOTE: To clarify, I am using and setting 3 different models, which work pretty much in the same way as type, that makes this a bit more complicated.
Then the itemController itself:
App.TagController = Ember.ObjectController.extend({
isSelected: function(key, value){
//bunch of code that does some stuff and returns true or false depending on value
}.property()
});
App.TypeController = App.TagController.extend();
Now the problem: I have a resetbutton that should deselect all checkboxes and remove the span classes.
I would have thought about using an action (in the ArrayController) that sets all the isSelected properties to false, but I don't seem to be able to find a way to access and manually set that itemController computed property.
One thing I tried in the ArrayController is the following:
actions: {
resetFilters: function(){
this.get('types').forEach(function(type) {
console.log(type.get('isSelected'));
//type.set('isSelected', false);
});
}
}
But unfortunately this returns undefined. And using jQuery manually to remove the class and uncheck the checkbox seems to work the first instance, but the problem is, the computed property doesn't get updated and that messes things up.
Any idea how I can achieve what I want?
If anything is unclear let me know and I will do my best to clarify.
Thank you.
You are setting controller.types, this will not work with itemController. You should always be setting an array controller's content property.
The following should work:
controller.set('content', this.store.find('type'));
Then to set the isSelected:
controller.setEach('isSelected', false);
This assumes that controller is an instance of an ArrayController that has an itemController set in it's definition, e.g.
App.TypesController = Em.ArrayController.extend({itemController: 'type'});
store.find returns a PromiseArray, so it should be resolved first. You can set the types as follows in setupController:
this.store.find('type').then(function(types){
controller.set('types', types);
});
Or you can resolve types in the reset:
this.get('types').then(function(types) {
types.forEach(function(type) {
console.log(type.get('isSelected'));
});
});
I would recommend the first one though.

Reset check boxes after form submission

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')
});

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}}