Retain checkbox state in angular when the scope changes - angularjs

below is a code snippet:
<tr ng-repeat="data in ioStatusData">
<td><input type="checkbox"></td>
<td>{{data.IOStatusName}}</td>
<td>{{data.IOLabel}}</td>
<td>{{data.IOStatus}}</td>
<td>{{data.TestResult}}</td>
</tr>
scope.ioStatusData keeps updating every 5 secs.I want to retain checkbox state (checked or unchecked) even when scope.ioStatusData changes.

You are trying to check the row is selected or not ignoring the data. Define an object in your controller that store the row state like
$scope.rowState = {};
And change the checkbox model like
<input type="checkbox" ng-model="rowState['index_' + $index]" />
Actually ng-repeat create dynamically rowState object like rowState.index_0, rowState.index_1
Check the Demo

You need to have
<input type="checkbox" ng-model="myCheckboxIsChecked[$index]">
and in controller:
$scope.myCheckboxIsChecked = [];
And your checbox state will be there even if the values of your array are changing.

Related

Combine checkbox and radio's with multiple angular models

I'm building a configurator tool where people can configure their own kitchen and I need some help with the logics here.
Let's say people can select a sink:
When a checkbox is checked, a list appears with multiple sinks (radio buttons). By default, when the checkbox is checked, the first radio button should be checked as well.
I want several things to happen here:
1) When the checkbox is checked, the radio buttons should appear. The first radio button should be checked by default and the value of this json object should be stored in formData.sink.
2) The price of the selected sink should be saved in prices[x].price.
3) When the checkbox get unchecked, the value of prices[x].price should be set to 0 and the formData.sink object should be empty.
Here's my HTML. In my controller I don't have any functions yet.
<tr class="tr-border-top">
<td colspan="2"><input type="checkbox" ng-model="sink">Sink</td>
<td>{{ prices[5].price | currency:"€":0}},-</td>
</tr>
<tr ng-show="sink">
<td colspan="3">
<ul>
<li ng-repeat="node in nodes | filter:{type:'sink'}">
<label>
<input type="radio" name="sink" class="form-control" ng-model="formData.sink" ng-value="node" ng-init="$index==0?(formData.sink=node):''">
{{ node.title}}
</label>
</li>
</ul>
</td>
</tr>
Well, seems like you didn't try much yourself. I would go for adding ng-change and then call a function that sets the values as you want them
<input type="checkbox" ng-model="sink" data-ng-change="onSinkChanged(sink)">
$scope.onSinkChanged = function(sink) {
// your logic here
}
and in that function you can set the correct values and if its unchecked, reset the values to 0 or undefined. Try some of that yourself and if you get stuck specify your exact problem :)

adding watch for an editable row in angularjs

I am using xeditable for editing a table row in angular js. HTML Code is shown below.
<tr ng-repeat="expense in viewModel.expenses">
<td>{{expense.eid}}</td>
<td><span editable-text="expense.billAmt" e-ng-model="editForm.billAmt" e-name="billAmt" e-form="rowform">{{expense.billAmt}}</span></td>
<td><span ng-show="!rowform.$visible">{{expense.split}}</span><input type="text" ng-show="rowform.$visible" class="form-control input-sm" e-ng-model="editForm.split" ng-disabled="true" /></td>
I want to update the 'split' value in last column when the value in 'billAmt' changes. So I add a watch in angularjs but is not updating.
$scope.$watch('editForm.billAmt',function(newValue,oldValue) {
$scope.editForm.split=newValue/$scope.viewModel.members.length;
});
Is there any other way to add a watch while using xeditable?? How can I solve this?
I'd refrain from using $scope.$watch() and turn to a more efficient solution. You can use the e-ng-change directive to fire a function computing new value of $scope.editForm.split every time the billAmt value changes. It would look like this:
<tr ng-repeat="expense in viewModel.expenses">
<td>{{expense.eid}}</td>
<td><span editable-text="expense.billAmt" e-ng-model="editForm.billAmt" e-name="billAmt" e-form="rowform" e-ng-change="checkSplit();">{{expense.billAmt}}</span></td>
<td><span ng-show="!rowform.$visible">{{expense.split}}</span><input type="text" ng-show="rowform.$visible" class="form-control input-sm" e-ng-model="editForm.split" ng-disabled="true" /></td>
And in your controller add function checkSplit():
$scope.checkSplit = function(){
$scope.editForm.split = $scope.editForm.billAmt / $scope.viewModel.members.length;
}
The checkSplit() function is invoked explicitly in a response to a event of value change, whereas $scope.$watch() handler runs on every digest cycle, so you can technically save some performance too.

Assigning ng-model to checkboxes generated by ng-repeat

I have set up a json containing a list of countries with an ID and Country code attached:
It looks like this:
$scope.countries = [
{"name":"Afghanistan","id":"AFG","country-code":"004"},
{"name":"Åland Islands","id":"ALA","country-code":"248"},
{"name":"Albania","id":"ALB","country-code":"008"},
{"name":"Algeria","id":"DZA","country-code":"012"}
]
I then use the ng-repeat directive to create checkbox inputs for every country.
<div ng-repeat="country in countries">
<label><input type="checkbox" ng-model="{{country.id}}" ng-true-value="'{{country.name}}'" ng-false-value="''">{{country.name}}</label>
</div>
However when I run the code I only get the following to display:
Location
checkbox here {{country.name}}
If I remove the ng-model part of the repeat my checkboxes generate fine but I need a unique ng-model to be attached to every checkbox
ng-model="{{country.id}}"
How would I go about attaching a unique ng-model value?
This answer (Generate ng-model inside ng-repeat) does not provide a unique ng-model value
I will suggest you, use:
<div ng-repeat="country in countries">
<label><input type="checkbox" ng-model="myCountry.selected[country.id]" ng-true-value="'{{country.name}}'" ng-false-value="''">{{country.name}}</label>
</div>
{{myCountry.selected}}
JS:
$scope.myCountry = {
selected:{}
};

Is this the angular way to keep track of checked items?

I have achieved what I want, which is to create an array of all checked items in angular. I plan to use these in another function.
My solution feels a bit awkward, is there a better way to do this?
<input
ng-repeat="task in $store.taskarr track by $index"
ng-change="checked(check,$index,task)"
ng-model="check"
type="checkbox"
/>
$scope.checked = function(check,count,task){
if(check){
$scope.$store.checkedItems[count] = task;
}else{
delete $scope.$store.checkedItems[count];
}
}
I liked this as it's using less code:
<input
ng-repeat="task in $store.taskarr track by $index"
ng-change="check ? ($store.checkedItems[$index] = task) :
($store.checkedItems[$index] = undefined)"
ng-model="check"
type="checkbox"
/>
You can use a combination of a service that tracks the state of selected items and an attribute directive you can attach to the checkbox.
The data can be modeled as an object that maps IDs to whether or not an item is checked.
The directive controller can handle the responsibility of updating the service so your parent controllers don't have to care about that part, but you can still get the selection state from anywhere in your app.

Bind JSON object to radio button in angularjs

So I am trying to bind radio buttons to objects. I have spent like an hour trying to figure this up and at last admit defeat. Here's what I got:
<table>
<tr ng-repeat="theCustomer in customers">
<td>
<input type="radio" ng-model="currentCustomer" value="theCustomer" id="{{theCustomer.id}}" ng-change="currentCustomer = theCustomer">
<label for="{{theCustomer.id}}">{{theCustomer.name}}</label>
</td>
</tr>
</table>
The angular stuff:
bankApp.controller("BankController", function ($scope, CustomerRepository)
{
$scope.customers = [];
$scope.currentCustomer = {};
$scope.createCustomer = function () {
CustomerRepository.save($scope.customer, function (customer) {
$scope.customers.push(customer);
$scope.customer = {};
});
};
});
Currently, when I try and click on a radio button nothing happens, it doesn't even get checked. I'm sure there's got to be a really simple solution to this. The end goal is to have currentCustomer hold the customer reflected in the radio selection.
<input type="radio" ng-model="$parent.currentCustomer" name="foo" ng-value="theCustomer" id="{{theCustomer.id}}">{{theCustomer.name}}</td>
The key here is the ng-value="theCustomer. This is how angular knows which object is selected. The html value only knows string values and cannot map to objects.
If you insert the above code, the radio will reflect the model, even if it is changed programatically. Also, you can't forget the $parent in the ng-model because the ng-repeat creates a new scope.
Apparently, getting a radio group to work inside an ng-repeat can be a bit tricky. The issue is with the ng-repeat creating its own child scope. One solution is to bind the model to the $parent. This thread gives an example.
I also created a working fiddle that more closely resembles your example.
In essence, I think your html is the only point that needs reworking:
<table>
<tr ng-repeat="theCustomer in customers">
<td><input type="radio" ng-model="$parent.currentCustomer" name="foo" value="{{theCustomer}}" id="{{theCustomer.id}}">{{theCustomer.name}}</td>
</tr>
</table>
It is because of the scope inheritance, you can read more about the problem here.
One solution that I use in such a case, is to bind the object to an object property instead of a primitive value like ng-model="form.currentCustomer".
Demo: Plunker

Resources