using AND operator in Angular - angularjs

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

Related

Remove empty option in the select using ng-model

I am new to angular js. In my code user changes the value of radio buttons. And depending on the value of the selected radio button, a piece of code is loaded from the ng-switch
HTML:
<body ng-app="">
<div ng-repeat="button in modes">
<label>
<input type="radio" ng-model="data.mode" value="{{button.value}}" ng-click="clearObjectIdModal()" name="e_modes">
{button.label}}
</label>
</div>
<div ng-switch on="data.mode">
<div ng-switch-when="client">
<label for="e_selected_object_item_id">Select Client name: </label>
<select id="e_selected_object_item_id" name="e_selected_object_item_id" ng-model="currentDataItem.object_id" required>
<option ng-repeat="item in customersListArr" value="{{ item.id }}">{{ item.Name }}</option>
</select>
</div>
<div ng-switch-when="agent">
// This part is similar to the previous one
</div>
</div>
</body>
Controller part:
$scope.data = {};
$scope.setFile = function () {
if ($scope.data.mode == 'client')
return 'client';
else if ($scope.data.mode == 'agent')
return 'agent';
$scope.modes = [{
value: 'client',
label: 'Client'
},{
value: 'agent',
label: 'Agent'
}];
$scope.currentDataItem = data; // data is preloaded from inputs in form
There is also a ng-click="clearObjectIdModal()" that clears the model when switching radio buttons:
$scope.clearObjectIdModal = function() {
$scope.currentDataItem = "";
}
The problem is that every time when the radio button is switched to the select value, which dynamically changes, the value of the first option in it becomes equal to undefined. Because in the array from where these options are built there is no such object_id (This is the id that is not there, so an empty field is drawn).
That is, there are all works. But the first option in the select(after switching to another radio button) is rendered as an empty string.
There are thoughts, how it can be fixed?
I'm not sure if I understand you problem correctly but I would suggest a few improvements.
change your setFile function to as follows
$scope.setFile = function (){return $scope.data.mode;}
I also do not see the closing brackets for your function in your code. Besides if your function will only return the data.mode then why need the function?
I would suggest initialize your data object properly like:
$scope.data = {mode:'client'};
Change your clearObjectIdModal function as:
$scope.clearObjectIdModal = function(mode)
{
$scope.currentDataItem = "";
$scope.data.mode=mode;
}
and in your HTML use it as ng-click="clearObjectIdModal(button.mode)"
So in function clearObjectIdModal() I wrote:
$scope.clearObjectIdModal = function() {
if ($scope.e_data["mode"] == 'client') {
if ($scope.customersListArr.length > 0) {
$scope.currentDataItem.object_id = $scope.customersListArr[0]['id'];
}
}
else if ($scope.e_data["mode"] == 'agent') {
if ($scope.agentsListArr.length > 0) {
$scope.currentDataItem.object_id = $scope.agentsListArr[0]['id'];
}
}
}
And after this when I change radio buttons the first option in current select(which every time is changed) will be not empty.
Also the problem with an additional empty option is possible to solve when you add a title as the first item in the list:
<option value="" disabled>Select</option>

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.

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

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

How to update ng-class based on ng-change?

I have an ng-repeat that creates several widgets, each with it's own select dropdown.
<div ng-repeat="item in widget.items" class="col-md-6">
<select ng-model="item.chosenTag"
ng-change="widget.updateTag(item)"
ng-class="widget.getButtonClass(item.tag, item.id)">
<option value="companies"
ng-selected="{{item.tag == 'companies'}}"
changed="companies">companies</option>
<option value="news"
ng-selected="{{item.tag == 'news'}}"
changed="news">news</option>
<option value="people"
ng-selected="{{item.tag == 'people'}}"
changed="people">people</option>
</select>
</div>
As the view is loaded, the ng-class="widget.getButtonClass(item.tag, item.id)" calls a function to check if 2 values are met, then sets ng-class to either btn-success or btn-default.
// This checks the view after load to change the class on each widget select
var vm = this;
vm.getButtonClass = function(tag, id) {
console.log('in getButtonClass');
if (tag && id) {
return 'btn-success';
} else {
return 'btn-default';
}
};
Next if the user now updates a select within any widget, ng-change will update to the correct value.
However I need to somehow re-run the ng-class check or rather just go ahead and add btn-success to the select without having to refresh the page.
How would you go about accomplishing this?
Is there a way to do something like this?
ng-class="{ functionToUpdateAll | boolean based on ng-change }"
Is there any specific reason that you need to call the function? Why dont you bind directly to those variables?
ng-class="'btn-success':item.tag && item.id, 'btn-default': !(item.tag && item.id)"
In that way you take advantage of mutual binding i.e. whenever the item.tag or item.id are changed, the class will be evaluated accordingly.
I suggest that instead of calling the function in ng-class, just assign it to a variable:
<select ng-model="item.chosenTag"
ng-change="widget.updateTag(item)"
ng-class="mySelectClass">
And in your updateTag function in the controller update that variable:
vm.updateTag = function(item) {
if (item.tag && item.id) {
vm.mySelectClass = 'btn-success';
} else {
vm.mySelectClass = 'btn-default';
}
};

Check all boxes toggle method not working like expected

I'm wiriting a method to toggle a checklist as checked / unchecked, as follow:
$scope.checkAllToggle = function(dtProvider, destiny, ev) {
$(ev.currentTarget).parent().find('span').html());
data[destiny] = [];
if ($(ev.currentTarget).parent().find('span').html()=='Check all') {
for (var val in data[dtProvider]) data[destiny].push(data[dtProvider][val].id);
$(ev.currentTarget).parent().find('span').html('Uncheck all');
}
else $(ev.currentTarget).parent().find('span').html('Check all');
}
The label of the toggle button changes every time, but the state of the checkboxs only becomes checked after 2 click, from this point change in each 3 clicks.
What's wrong?
Append
if(!$scope.$$phase) $scope.$apply();
to the method make no difference, as prepending $scope to data
Code in plunker: http://plnkr.co/edit/Zf6UzLbC4osRov7IR5Na?p=preview
Rather than do it that way, this would be the easier way to do it.
Make the master input and assign it to a model.
<input type="checkbox" ng-model="master">
Then have your other inputs be tied to the master like this.
<input type="checkbox" ng-model="box1" ng-checked="master">
<input type="checkbox" ng-model="box2" ng-checked="master">
<input type="checkbox" ng-model="box3" ng-checked="master">
Here is your plunker with these changes.
Master Checkbox Plunker
I got your plunker to work by doing this.
$scope.checkToggle = function(dtProvider, destiny, ev) {
$scope.data[destiny] = [];
if ($(ev.currentTarget).parent().find('span').html() == 'Check all') {
for (var val in $scope.data[dtProvider]){
$scope.data[destiny].push($scope.data[dtProvider][val].id);
$(ev.currentTarget).parent().find('span').html('Uncheck all');
}
} else {
$(ev.currentTarget).parent().find('span').html('Check all');
}
$scope.$apply();
};
I could not get it to work if calling safely like if(!$scope.$$phase){$scope.$apply();} but it is working with straight $scope.$apply(). This might have something to do with rootScope and need to be safetly called in a different manner.
See this link: https://coderwall.com/p/ngisma
You also had some missing {} in your code that could have been causing some issues.

Resources