AngularJS ng-checked isn't updating checkbox when model changed in javascript - angularjs

I have a filtered list of objects being repeated with ng-repeat with an input checkbox beside each item. When the list isn't filtered (as it is when the page is loaded) then I don't want the checkboxes checked. If the list is filtered I do want the checkboxes checked (the checkboxes form a treeview via CSS).
The checkbox has ng-checked="{{site.isChecked}}". When the list is filtered I am updating the isChecked variable on the objects within the filter javascript code, but this isn't updating the checkbox value. If the item is filtered out so it's removed from screen and then filtered back in again the updated isChecked value will come through to the screen.
The HTML is as follows:
<ul>
<li ng-repeat="site in sites | filterSites:searchBuildings">
<input type="checkbox" ng-checked="{{site.isChecked}}" id="item-f{{site.id}}" /><label for="item-f{{site.id}}">{{site.site}}</label>
<ul>
<li ng-repeat="building in site.filteredBuildings">
{{building.address}}
</li>
</ul>
</li> </ul>
The JS is:
var filtered = [];
searchBuildings = searchBuildings.toLowerCase();
angular.forEach(sites, function (site) {
var added = false;
var siteMatch = false;
site.isChecked = true;
if (site.site.toLowerCase().indexOf(searchBuildings) !== -1)
siteMatch = true;
angular.forEach(site.buildings, function (building) {
if (siteMatch == true || building.search.toLowerCase().indexOf(searchBuildings) !== -1) {
if (added == false) {
added = true;
filtered.push(site);
site.filteredBuildings = [];
}
site.filteredBuildings.push(building);
}
});
});
return filtered;
Sorry if the code isn't very pretty - I'm new to AngularJS and JS and still trying to work out how things link together.
Thanks

You should use ng-model there that would provide you two way binding. Checking and unchecking the value would update the value of site.isChecked
<input type="checkbox" ng-model="site.isChecked" id="item-f{{site.id}}"/>

Related

How to set a default value for AngularJS ng-repeat?

<li ng-repeat="item in quantityList track by $index" ng-model="isPageValid='true'">
<input value="item.quantity" ng-blur="validateQuantity(item)" ng-model="item.quantity">
</li>
I'm trying to set a default value for a status variable each time an ng-repeat loop occurs. I've tried ng-model, but that doesn't work. For instance,
I'd like to set isPageValid="true" before each time the ng-repeat loop runs. 'True' is will be the default value, and the validation function will test whether isPageValid should be set to 'false'.
I'd like the ng-repeat loop to run each time the ng-blur is exercised.
NOTE: I understand the way I'm using ng-model is incorrect, but this is just to illustrate the issue.
HTML:
<li ng-repeat="item in quantityList track by $index" ng-model="isPageValid='true'">
<input value="item.quantity" ng-blur="validateQuantity(item)" ng-model="item.quantity">
</li>
JS:
scope.validateQuantity = function(item){
var qty = item.quantity;
if(parseInt(qty) >=1 && parseInt(qty) <= 200){
item.isQuantityValid = true;
}else{
item.isQuantityValid = false;
scope.isPageValid = false;
}
}
The loop creates a list of input boxes. The objective is to create a global validation value called isPageValid which is 'false' if the validation by the JS fails for any input box. Note, when ng-blur is exercised, the JS validation runs and loop should re-run.
I believe ng-init could help...
<ul ng-init="isPageValid='true'">
<li ng-repeat="item in quantityList track by $index" >
<input ng-blur="validateQuantity(item)" ng-model="item.quantity">
</li>
</ul>
Note that it would be better practice to initialise isPageValid in the controller that is in the same scope as your validateQuantity function.
Here is an example of how you could initialise isPageValid in your controller and update the value after each call to validateQuantity...
In your controller:
scope.isPageValid = true;
function updatePageValid() {
scope.isPageValid = scope.quantityList.every(item => item.isQuantityValid);
}
scope.validateQuantity = function(item) {
var qty = parseInt(item.quantity);
item.isQuantityValid = (qty >= 1 && qty <= 200);
updatePageValid();
});

nested Filter json Using Checkboxes with AngularJS

I had a Json data I need to create a nested filter search in angular. If you guys can help me since I am new to this I tried but I find difficulty.
I dont have your css but at high level it should be like THIS and for multilevel filter refer THIS
On click of checkbox i am adding filter category to one of my array using addToFilter function.
HTML
<input type="checkbox" ng-checked="item.checked" ng-model="item.checked" ng-click="addToFilter(item.node.category)"/> {{ item.node.category }}
HTML
code filter:categoryFilter will filter records from array according to selected category.
<div ng-repeat="item in nodes | filter:categoryFilter | orderBy:'node.location' | groupBy:['node.location'] ">
<h2 ng-show="item.group_by_CHANGED">{{item.node.location}}</h2>
<ul>
<li>{{item.node.title}}</li>
</ul></div>
JS
This js code is to add selected category from array when checked and remove when unchecked.
$scope.filtersApplied =[];
$scope.addToFilter = function(category)
{
var i = $.inArray(category.trim(), $scope.filtersApplied);
console.log(category);
if (i > -1) {
$scope.filtersApplied.splice(i, 1);
} else {
$scope.filtersApplied.push(category.trim());
}
}
$scope.categoryFilter = function(node) {
if ($scope.filtersApplied.length > 0) {
if ($.inArray(node.node.category.trim(), $scope.filtersApplied) < 0)
return;
}
return node;
}
** Please ignore my grouping code. I just want to simulate what you shown in image.
Updated SAMPLE with CSS

TR element triggers checkbox via ng-click, but ng-change on checkbox will not fire

I have successfully created functionality to check a hidden checkbox on the ng-click of the row that the checkbox exists in that is generated with an ng-repeat. However, I also have functionality that adds that item to a separate array when the checkbox is checked using the ng-change directive.
My code works perfectly if I un-hide the element and check the checkbox directly, but if I use the ng-click directive on the TR, the checkbox gets checked (visibly) but the array isn't updated. If I then click on it again, it remains checked and the item is added to the new array.
This isn't an issue where the ng-click is taking two clicks to fire. Here is my markup:
<tr ng-cloak ng-repeat="item in mostRecent | orderBy:sortType:sortReverse | filter: query" class="hovered" ng-class="{'hide':showReports && item.status == 'Not Started' || showReports && item.status == 'inProgress','rep-checked': bool}" ng-click="bool = !bool">
<td class="hidden"><div class="checkbox">
<label class="checkbox">
<input type="checkbox" ng-change="sync(bool, item)" ng-model="bool" ng-checked="isChecked(item)">
</label>
</div></td>
and the js:
$scope.isChecked = function(id) {
var match = false;
for(var i=0 ; i < $scope.selectionData.length; i++) {
if($scope.selectionData[i].id == id){
match = true;
}
}
return match;
};
// Create a new array from the selected data
$scope.selectionData = [];
var selectionData = $scope.selectionData;
var result = selectionData.filter(function(e){ return e.id == id; });
$scope.sync = function(bool, item){
if ($scope.selectionData) {
$scope.selectionData.push(item);
}
else {
$scope.selectionData.splice(item);
}
console.log('check' + $scope.selectionData);
};
After some deeper research, I found that the ng-click function on the input isn't registering because the ng-click function of the tr element isn't actually emulating a click event on the input. I added a dynamic ID and replaced the ng-click function with a javascript function of
getElementById('checkboxID').click();
And it worked as expected.

using AND operator in Angular

I have the following HTML
<input type="checkbox" id="cbxSelectAllPreventive"/> <label>Select All</label>
<ul style="list-style: none;">
<li ng-repeat="test in lists.Tests">
</li>
</ul>
Test is an array of complex objects having isSelected property.
I want to use the checkbox as SelectAll functionality.
To do this , I need to supply ng-model to the checkbox, I can supply it as a method which checks in each of the tests and returns true/false. Is there any way to do this inline, without writing a method ?
I only see a way to do it using a function on ng-change
<input type="checkbox" id="cbxSelectAllPreventive"
ng-model="checked" ng-change="setAll(checked)"/>
...
$scope.setAll = function(isSelected){
$scope.lists.Tests.map(function(el){
el.isSelected = isSelected;
})
}
Working fiddle
EDIT:
For complete two-way connection between items' selection and check box the code will be a bit more complicated.
We will use an extra variable in $scope to reflect the label of check box. Don't forget to init the variable at controller creation
<label for="cbxSelectAllPreventive">{{selectLabel}}</label>
...
$scope.selectLabel = 'Select All';
setAll function should take care of setting this variable.
$scope.setAll = function(isSelected){
$scope.selectLabel = isSelected ? 'Deselect All' : 'Select All';
$scope.lists.Tests.map(function(el){
el.isSelected = isSelected;
})
}
And finally you definitely will have an option to select/deselect individual items. For this case you have to $watch your list. Mind the third parameter true which does deep comparison otherwise it won't "notice" changes inside objects.
$scope.$watch('lists.Tests', function(){
var text = $scope.lists.Tests.map(function(el){ return el.isSelected; }).join();
console.log(text);
var allSelected = $scope.lists.Tests.every(function(el){ return el.isSelected;});
var noneSelected = $scope.lists.Tests.every(function(el){ return !el.isSelected;});
if(noneSelected){
$scope.selectLabel = 'Select All';
$scope.checked = false;
}else if(allSelected){
$scope.selectLabel = 'Deselect All';
$scope.checked = true;
}
if(!noneSelected && !allSelected) {
$scope.selectLabel = 'Undetermined';
// here set the check box to undetermined (third) state
}
}, true);
Updated fiddle
Did you try ng-checkbox is should do exaclty what

AngularJS ng-repeat filter, function over object property

I am looking for a way to check for each movie if the movie has the category which is selected. Movies is an array which contains objects, those objects have some properties, like you can see in the code below. The categories property is a array of categories where the movie is in. Now there is a variable selectedCategories where the current selected category is stored in.
I don't want to use custom filters, because I think it has te be possible with this one, I just can't quite get it. In the javascript function there can't be changed too much either.
If the return of hasSelectedCategory is true, then it has to execute the block, if false not.
Thanks in advance.
//in the javascript file
scope.hasSelectedCategory = function(categories){
var hasCategory = false;
if (categories.indexOf(scope.selectedCategory) !== -1){
hasCategory = true;
}
return hasCategory;
};
//in the html file
<div class="movieListItem {{listItemView}}" ng-repeat="movie in movies | filter:{hasSelectedCategory(categories): true}">
<h4>{{movie.title}}</h4>
<a href="http://www.youtube.com/embed/{{movie.youtubeId}}?rel=0&autoplay=1">
<img ng-src="{{findPosterSource(movie)}}" class="poster"> </a>
<p ng-hide="listItemView === 'grid'">
{{movie.description}}
</p>
<div class="categories" >
<span ng-repeat="category in movie.categories"> <a ng-href="#">{{category}}</a> </span>
</div>
</div>
You have to use the filter like this:
ng-repeat="movie in movies | filter:hasSelectedCategory"
The hasSelectedCategory function will be invoked for each movie in the movies list. In order to filter by selected categories you can use a function like this:
$scope.hasSelectedCategory = function(movie) {
var hasCategory = false;
angular.forEach($scope.selectedCategories, function(selectedCategory) {
if (!hasCategory && movie.categories.indexOf(selectedCategory) !== -1) {
hasCategory = true;
}
});
return hasCategory;
};
Demo (plunker)

Resources