Programmatically unchecking checkbox does not update angular model - javascript

I am using the following code to programmatically uncheck a checkbox:
$('#someid').removeAttr('checked');
Here is the checkbox that is bound to an Angular model:
<input id="someid" ng-model="model.property" type="checkbox" value="true">
I can see that the checkbox is indeed unchecking. Why is the Angular model property not also updating (changing from true to false) and how can I obtain this desired behavior? I can update the model and have the checkbox update no problem.

If you are using Angular, it's expected that you don't manipulate the DOM this way.
You have to change the angular model variable, and let Angular make the DOM changes.
Study the ToDo List example at
angularjs.org
Tip: I think you really don't need jQuery anymore!
The Angular code you need:
$scope.model.property = false;

Your use of jQuery is breaking anglers binding to the DOM. If you need to uncheck something change the value on the model that is bound to the checkbox:
$scope.model = { isChecked: true };
bound to:
<input type="checkbox" ng-model="model.isChecked">
to "uncheck":
$scope.model.isChecked = false;
No need for jQuery.

Related

How to two-way bind a checkbox using Angular?

I currently have an accordion with a bunch of options in the form of checkboxes. The user can select the checkboxes as expected however, I want to already have some of those checkboxes checked depending on certain conditions. The issue is sometimes that is determined after the page has loaded. Below are simplified examples to demonstrate my code (my code is for work and would not be able to share due to confidentiality issues).
My HTML looks like this:
<div class="row">
<div "ngFor="let value of filteredPeople" >
<div>
<input type="checkbox" (click)="selectPeople(value)" [checked]="checkedPeople.get(value)">
{{ value }}
</div>
</div>
</div
My Javascript:
public checkPeople() {
this.selectedPeople.forEach(element => {
this.checkedPeople.set(element, true);
});
}
To explain some variables and methods:
Variables:
filterPeople - a string array of all possible people
checkedPeople - a map with a KVP of string (the people) and boolean (whether or not their checkbox is checked)
selectedPeople - a string array of people whose checkboxes I want already checked
Methods:
selectPeople - checks the corresponding checkbox when user clicks on it
checkPeople - a method called when I want the specific checkboxes checked (these specific checkboxes change based on other factors so I cannot hard code it)
For some reason my checkPeople method does not seem to select the expected checkboxes, I am not sure why but I have a feeling it is to do with the fact that I have used "[checked]" in the HTML and that it should be something else. Can someone clarify the issue for me and help me identify a fix? (Note: as the title suggests, I am using Angular)
Edit:
I have just debugged my code and added breakpoints, the checkedPeople map has the correct mapping of people to true for each of the elements in selectedPeople which shows that the checkPeople method is working as expected. Therefore the issue must be with the [checked] attribute if I'm not mistaken. I cannot see why it wouldn't work though.
You should use [ngModel]="checkedPeople.get(value)"
instead of [checked]="checkedPeople.get(value)"
to initialize the checkbox and
(change)="checkUncheckPeople(value, $event)"
to update the value when you check or uncheck it, where
checkUncheckPeople(value, e) {
this.checkedPeople.set(value, e.target.value);
}
So, in conclusion, your HTML input element will be:
<input
type="checkbox"
[ngModel]="checkedPeople.get(value)"
(change)="checkUncheckPeople(value, $event)"
/>
If you choose to use an object instead of a map then you can also directly use
[(ngModel)]="checkedPeople[value]"
to two-way bind the variable

Knockout.js: Set radio button value onload

Please see my fiddle here
I have a couple of radio buttons and depending if one of them is selected I want a text box to then show. I have been able to achieve this using knockout.
What I want to happen is when the page loads, if the value of the "Timesheet" radio button is checked I want the text box to show. But I've been unable to work out how to do this. Thanks is advance.
See below my knockout code:
function K2ConsultantApprovalViewModel() {
var self = this;
self.timeSheetSelected = ko.observable("");
}
ko.applyBindings(new K2ConsultantApprovalViewModel());
If the checked binding is applied to a radio button, it will set the element to be checked when the parameter value equals that of the radio button element's value attribute. So you need to slightly change your way of thinking and create a "payment type" observable that stores the chosen payment type, rather than the boolean "is timesheet selected?" observable that you have now. You can then initially give this observable the value "Timesheet", and that will be what is selected on page load. It also makes it trivial to show or hide any other elements based on the current selection.
function K2ConsultantApprovalViewModel() {
var self = this;
self.paymentType = ko.observable("Timesheet");
}
ko.applyBindings(new K2ConsultantApprovalViewModel());
And binding would look like this:
<input id="DisbursementsOrTimeSheet_ChoiceField0" type="radio" name="DisbursementsOrTimeSheetChoice" value="Disbursements" data-bind="checked: paymentType">
Update Fiddle here.
Update
I would not recommend this since it's a backwards way of working, but if the initial value of your checked binding has to come from the input element itself, you could create a small binding handler that is executed before the checked binding.
ko.bindingHandlers['initChecked'] = {
init: function (element, valueAccessor, allBindings) {
var checked = valueAccessor();
if (element.checked) {
checked(element.value);
}
}
};
Then bind like this:
<input id="DisbursementsOrTimeSheet_ChoiceField1" type="radio" name="DisbursementsOrTimeSheetChoice" value="Timesheet" data-bind="initChecked: paymentType, checked: paymentType" checked="checked">
It will work (proof). But the proper way to do this would be to get the data in the view model and, as someone well put it in the comments, cut out the middle man.

Ember action preventing checkbox value from setting

In my ember application I would like to render a set of checkboxes dynamically via a loop and disable any unselected checkboxes if 2 of the checkboxes have been checked.
I am having problems with setting a value to 'true' when a checkbox is selected that has a change action. For the following example checkbox.value does not get set when the checkbox is selected.
{{ input type="checkbox" disabled=checkbox.disabled checked=checkbox.value change=(action "disableCheckboxes" val)}} {{checkbox.label}}
However when I remove the action it does get set:
{{ input type="checkbox" disabled=checkbox.disabled checked=checkbox.value}} {{checkbox.label}}
Full example on JSFiddle
How can I set the value while still running the action? Or is the a better way to disable the unchecked checkbox when 2 have already been selected?
Well, first you can use an action. Checkout this ember-twiddle.
But I would recommend to directly bind your value to your target object. See here.
The idea is basically to wrap your array and calculate the isDisabled in the wrapping:
boxes:[{id:1,value:true},{id:2},{id:3}],
boxArr: Ember.computed('boxes.#each.value', {
get() {
let disableOthers = Ember.get(this, 'boxes').filterBy('value', true).get('length') >= 2;
return Ember.get(this, 'boxes').map(origin => {
return {
origin,
disabled: disableOthers && !origin.value,
};
});
}
}),
Then you can just use it in your template:
{{#each boxArr as |box|}}
{{input type="checkbox" disabled=box.disabled checked=box.origin.value}} {{box.origin.id}}
{{/each}}
A third way to archive is with a helper. You can just have a computed property saying if all checkboxes with value=false should be disabled, and then use an and and not helper to set disabled=(and disableFalseCheckboxes (not box.value). Checkout ember-truth-helpers for that.

ko binding for checkbox: change 'checked' attr from code not change the observable field

I have checkbox at html that is binding to observable-field (field of breeze entity).
<input id="chk1" type="checkbox" data-bind="checked: data().isBirthday"/>
The binding works well from the tow sides:
When I write at code:
data().isBirthday(true);
the checkbox become checked.
and when I write at code
data().isBirthday(false);
the checkbox become unchecked.
And when I choose the checkbox by clicking with mouse - the observable field gets value of true. (Or when I unchecked by mouse - it gets value of false).
sometime, I need to change the checked attribute of the checkbox by code, specifically by retrive checkbox with jquery.
(I cannot do it by the observable field becouse of any reasons).
I do:
var control = $('#chk1')[0];
control.checked = false;
but this not change the value of the binded observable-field. It continue holding true value.
I tried to triiger the change event:
$(control).change()
It didn't help.
So, what should I do?
Here is an example:
https://jsfiddle.net/kevinvanlierde/72972fwt/4/
Can we see the html code?
Try $('#chk1').prop("checked", false);

Checked state not getting populated in viewmodel when set programatically

I believe this question is similar to this one but as far as could see in the rules, if there is no answer and it is not the same scenario, I'm allowed to ask.
I've simplified my real scenario with the following, basically, the checkbox is getting checked through some unaccessible code which doesn't get the view model of knockout.js to detect. Is there a work around?
HMTL:
<input id="myCheckbox" type="checkbox" data-bind="checked: myValue" />
<div data-bind="text: myValue"></div>
javascript:
var viewModel = {
myValue: ko.observable(false)
};
ko.applyBindings(viewModel);
setTimeout(function() {
$("#myCheckbox").attr("checked", "checked");
}, 1000);
When a checkbox is modified using the setAttribute function or the checked property, as jqGrid does, it doesn't trigger the click event that Knockout's checked binding uses; neither does it trigger a change event. To be able to detect these changes, you have different options depending on the browser/version: MutationObserver, DOMAttrModified, and/or onpropertychange.
But I'd suggest avoiding those solutions and using what jqGrid gives you: either the jqGridSelectRow event or the onSelectRow callback. You might want to check out the Knockout-jqGridBinding plugin that should give you a good starting point. It includes a selectedItems option that lets you bind an observable array to jqGrid's selected items (using the onSelectRow callback internally).
EDIT:
To re-iterate, I suggest you don't try to solve the problem by watching the checkboxes. But if that's the way you want to go, there's a jQuery plugin, attrchange that provides cross-browser support for this.
Resources:
Knockout-jqGridBinding: https://github.com/CraigCav/Knockout-jqGridBinding
attrchange: http://meetselva.github.io/attrchange/
The answer to which you linked explained that Knockout needs to be alerted of the change through a usual event, such as "click". Here is the idea posted there by Rustam:
function update(){
var $cb = $(':checkbox');
var cb = $cb[0];
// change value directly on element
cb.checked = !cb.checked;
// propagate changes to KO
$cb.triggerHandler('click');
}
setTimeout(update, 1000);
Of course the method more native to KO would be to change the observable on the model, like so:
var update = function() {
viewModel.myValue(!viewModel.myValue)
};
I was not able to fix this on my code in which Foundation was taking control of the checkbox. I ended up binding a click event which then checked on the checkbox to see if it was checked (we only had 1 checkbox that we were trying to keep track of). I then updated the observable from that click event based on whether it was checked or not.
No way around this that I know of.

Categories

Resources