AngularJS: groups of checkboxes inside a loop - angularjs

There are some categories inside ng-repeat, and each one includes some accounts, If each category is selected then all accounts inside it must be selected and vice versa. Also, if one account is not selected, then the parent category is not selected.
How can I do that?
Here is how the view is:
And the code fiddle:
http://jsfiddle.net/2f6qscrp/208/
Thank you for any help.

Here is the working fiddle for your case,
http://jsfiddle.net/balasuar/2f6qscrp/209/
HTML
<div ng-app='home'>
<!-- App goes here -->
<md-content layout-padding ng-controller="MainCtrl as mainCtrl">
<md-checkbox ng-model="selectedAll"
ng-change="toggleAll()"
class="md-primary">
<span ng-if="selectedAll">Un-</span>Select All
</md-checkbox>
<div ng-repeat="category in naturalAccounts">
<md-checkbox class="md-primary" ng-model="category.selected" ng-change="toggleCategory(category)">
{{ category.name }}
</md-checkbox>
<div ng-repeat="acc in category.accounts">
<md-checkbox class="md-primary" ng-model="acc.selected" ng-change="toggleAccount(category, acc)" >{{acc.name}}</md-checkbox>
</div>
</div>
</md-content>
</div>
JS
angular.module('home', ['ngAria', 'ngAnimate', 'ngMaterial']);
angular.module('home').config(function ($mdThemingProvider) {
$mdThemingProvider.theme('default')
.primaryPalette('pink')
.accentPalette('grey');
});
angular.module('home').controller('MainCtrl', function ($scope) {
$scope.naturalAccounts = [
{"id":0,"name":"category0","accounts":[{"id":0,"name":"acc0"},{"id":1,"name":"acc1"},{"id":2,"name":"acc2"}] },
{"id":1,"name":"category1","accounts":[{"id":0,"name":"acc0"},{"id":1,"name":"acc1"},{"id":2,"name":"acc2"}] },
{"id":2,"name":"category2","accounts":[{"id":0,"name":"acc0"},{"id":1,"name":"acc1"},{"id":2,"name":"acc2"}] }
];
$scope.selectedAll = false;
function setSelectedAll() {
for(var i = 0; i < $scope.naturalAccounts.length; i++) {
var category = $scope.naturalAccounts[i];
$scope.selectedAll = category.selected;
if(!$scope.selectedAll) {
break;
}
}
}
$scope.toggleAll = function() {
for(var i = 0; i < $scope.naturalAccounts.length; i++) {
var category = $scope.naturalAccounts[i];
category.selected = $scope.selectedAll;
for(var j = 0; j < category.accounts.length; j++) {
var account = category.accounts[j];
account.selected = $scope.selectedAll;
}
}
};
$scope.toggleCategory = function(category) {
for(var j = 0; j < category.accounts.length; j++) {
var account = category.accounts[j];
account.selected = category.selected;
}
setSelectedAll();
};
$scope.toggleAccount = function(category, account) {
for(var j = 0; j < category.accounts.length; j++) {
var account = category.accounts[j];
category.selected = account.selected;
if(!category.selected) {
break;
}
}
setSelectedAll();
};
});

<input type="checkbox" ng-model="category.checked" ng-change="checkAllAccountsOfCategoryIfChecked(category)" />
and
<input type="checkbox" ng-model="account.checked" ng-change="checkOrUncheckCategoryBasedOnItsAccounts(category)" />
In your controller:
$scope.checkAllAccountsOfCategoryIfChecked = function(category) {
// TODO if category is checked, then loop over all its accounts and check them
}
$scope.checkOrUncheckParentCategory = function(category) {
// TODO if all the category's accounts are checked,
// then check the category, otherwise uncheck it
}

Related

How to match both the arrays in Angularjs and have to display matched one?

I have user_id in two array, one is available user_id's for projects and other is selected user_id.
availableusers = ["00000000a447a9160c9d6b74", "000000005c05c11764445bdb"]
selected Users = ["000000005c05c11764445bdb"]
Now I need to match both the array and have to display matched in selected div and unmatched in availabe div.
How can I able to do this?
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.availableusers = ["00000000a447a9160c9d6b74", "000000005c05c11764445bdb"]
$scope.selectedUsers = ["000000005c05c11764445bdb"]
$scope.matchUser = [];
for (var i = 0; i < $scope.availableusers.length; i++) {
for (var j = 0; j < $scope.selectedUsers.length; j++) {
if ($scope.availableusers[i] === $scope.selectedUsers[j]) {
$scope.matchUser.push($scope.availableusers[i]);
}
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.5/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<span>Available users</span>
<div ng-repeat="available in availableusers">{{available}}</div>
<span>Selected Users</span>
<div ng-repeat="selectUser in selectedUsers">{{selectUser}}</div>
<span>Users</span>
<div ng-repeat="Users in matchUser">{{Users}}</div>
</div>
var result=[];
for(var i = 0 ;i<availableUsers.length;i++){
if(availableusers[i] === selectedUsers[i])
{
result.push(availableusers[i]);
}
}

Search a city using google map

I'm using a google map to show location in find search box (from that link) which is working fine:
angular.module('ui.bootstrap.demo').controller('TypeaheadCtrl',function($scope, $http) {
$scope.getLocation = function(val) {
return $http.get('//maps.googleapis.com/maps/api/geocode/json', {
params: {
address: val,
sensor: false
}
}).then(function(response){
return response.data.results.map(function(item){
return item.formatted_address;
});
});
};
<h4>Asynchronous results</h4>
<pre>Model: {{asyncSelected | json}}</pre>
<input type="text" ng-model="asyncSelected" placeholder="Locations loaded via $http" uib-typeahead="address for address in getLocation($viewValue)" typeahead-loading="loadingLocations" typeahead-no-results="noResults" class="form-control">
<i ng-show="loadingLocations" class="glyphicon glyphicon-refresh"></i>
<div ng-show="noResults">
<i class="glyphicon glyphicon-remove"></i> No Results Found
</div>
I would like to know if possible to show my custom city near the search entry ?
Let's say I have bbCity, aaCity, ccCity and when a user types bb, her/him gets the nearest one (bbCity).
Thanks
I don't know if it's a right way but I solved it by adding the answer from this link.
angular.module('ui.bootstrap.demo').controller('TypeaheadCtrl',function($scope, $http) {
// Predefined areas
var predefinedLocations = [[48,68435270497298,4,39454410970211, 'city 1'],[48,33375503137806,5,616522543132305, 'city 2']];
$scope.getLocation = function(val) {
return $http.get('//maps.googleapis.com/maps/api/geocode/json', {
params: {
address: val,
sensor: false
}
}).then(function(response){
return response.data.results.map(function(item){
// Hold distances
var distances = [];
var start = new google.maps.LatLng(item.geometry.location.lat, item.geometry.location.lng);
for (var i = 0; i < predefinedLocations.length; i++)
{
var point = new google.maps.LatLng(predefinedLocations[i][0],predefinedLocations[i][1]);
var distance = google.maps.geometry.spherical.computeDistanceBetween(start, point);
distances.push(distance);
}
var firstElement = distances[0];
var index = 0;
for (var i = 1; i < distances.length; i++)
{
if(distances[i] < firstElement)
{
firstElement = distances[i];
index = i;
}
}
return predefinedLocations[index][2];
});
});
};

How to programmatically check checkbox with dynamic model name?

I have created a some checkboxes with dynamic model name like this:
<label ng-repeat="item in main.itemDetails">
<input type="checkbox" checklist-value="item.price"
ng-click="itemChanged(item)" ng-model="checkboxes[item.name]">
{{item.name}} - <b>{{item.price}} €</b>
<br>
</label>
In my controller, I want to check some checkboxes if their model's name exists in array $scope.selectedItems.
I'm trying to do something like this but it isn't working:
for (var i = 0, j = $scope.selectedItems.length; i<j; i++) {
$scope['selectedItems[i].name'].isChecked = true;
}
for example if item.name = 'Item1' I want the model to be named $scope.Item1 and later I want to call $scope.Item1.isChecked = true;
What Am I doing wrong here?
Your are storing the model in the $scope.checkboxes, so you can set its value to true like the code below.
for (var i = 0, j = $scope.selectedItems.length; i<j; i++) {
$scope.checkboxes[$scope.selectedItems[i].name] = true;
}
It looks like your using a string literal here:
for (var i = 0, j = $scope.selectedItems.length; i<j; i++) {
$scope['selectedItems[i].name'].isChecked = true;
}
Just change this to read:
for (var i = 0, j = $scope.selectedItems.length; i<j; i++) {
$scope[selectedItems[i].name].isChecked = true;
}
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.main = [{
'name':'test1',
'price':'23',
'isChecked':false
},
{
'name':'test2',
'price': '25',
'isChecked':false
},
{
'name':'test3',
'price': '21',
'isChecked':false
}];
$scope.selectedItems = [{
'name':'test1'
},
{
'name':'test2'
}];
angular.forEach($scope.main, function(valueMain){
angular.forEach($scope.selectedItems,function(valueSelected){
if(valueMain.name=== valueSelected.name){
valueMain.isChecked = true;
}
})
});
$scope.toggleCheck = function(item){
if(item.isChecked === true){
item.isChecked === false;
}else{
item.isChecked === true;
};
}
}
<script src="https://code.angularjs.org/angular-1.0.1.js"></script>
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<label ng-repeat="item in main">
<input type="checkbox" ng-model="item.isChecked" ng-checked="item.isChecked" ng-change="toggleCheck(item)">
{{item.name}} - <b>{{item.price}} €</b>
<br>
</label>
</div>
</div>
Angular Foreach is the easiest way to solve this kind of problem.

Get model array values in controller's service

I've been facing an issue since couple of hours. My view template looks like-
<div class="row" ng-repeat="row in CampaignsService.getRows().subItems track by $index">
<div class="col-sm-2">
<select class="form-control dropDownPercent" ng-model="CampaignsService.dropDownPercent[{{CampaignsService.selectCounter}}]" ng-change="CampaignsService.wow(CampaignsService.dropDownPercent, $index)" ng-options="o as o for o in CampaignsService.showPercentDropDown().values">
</select>
</div>
<div class="col-sm-2" style="line-height: 32px">
of visitors send to
</div>
<div class="col-sm-4">
<select class="form-control" ng-model="campaignSelect" ng-options="campaign.Campaign.id as campaign.Campaign.title for campaign in CampaignsService.getRows().items">
<option value=""> Please select </option>
</select>
</div>
<div class="col-sm-4">
<a class="btn btn-default" target="_blank" href="">Show campaign</a>
</div>
Variable CampaignsService.selectCounter is a counter variable and declared in service but when I'm going to use ng-model="CampaignsService.dropDownPercent[{{CampaignsService.selectCounter}}]" it gives me error -
Error: [$parse:syntax] Syntax Error: Token '{' invalid key at column 35 of the expression [CampaignsService.dropDownPercent[{{CampaignsService.selectCounter}}]] starting at [{CampaignsService.selectCounter}}]]
And when I use ng-model="CampaignsService.dropDownPercent['{{CampaignsService.selectCounter}}']" it does not give any error but it takes this variable as string.
My question is how could I create a model array and get model's array values in my service ?? I read many questions in stack community and none of the trick work for me. My service under my script, is
.service('CampaignsService', ['$rootScope', 'AjaxRequests', function ($rootScope, AjaxRequests) {
this.dropDownPercent = [];
this.selectCounter = 0;
var gareeb = [];
this.showPercentDefault = 100;
// this.campaignsData = [];
this.$rowsData = {
items: [], //array of objects
current: [], //array of objects
subItems: [] //array of objects
};
this.getRows = function () {
return this.$rowsData;
}
this.addNewRow = function () {
var wowRow = {}; //add a new object
this.getRows().subItems.push(wowRow);
this.selectCounter++;
gareeb.push(0);
}
this.calculatePercentages = function (index) {
angular.forEach(this.getRows().current, function (data, key) {
if (key == index) {
console.log(data);
}
})
}
this.showPercentDropDown = function ($index) {
var balle = 0;
var start;
angular.forEach(gareeb, function (aha, keywa) {
balle += aha;
})
var last = 100 - balle;
var final = [];
for (start = 0; start <= last; start += 10) {
final.push(start);
}
return this.values = {
values: final,
};
}
this.wow = function (valueWa, keyWa) {
console.log(this.dropDownPercent);
gareeb[keyWa] = valueWa;
this.changePercentDropDown();
}
this.changePercentDropDown = function () {
var angElement = angular.element(document.querySelector('.dropDownPercent'));
angular.forEach(angElement, function (data, key) {
console.log(data);
})
}
}])
Target model structure should be
ng-model="CampaignsService.dropDownPercent[1]"
ng-model="CampaignsService.dropDownPercent[2]"
ng-model="CampaignsService.dropDownPercent[3]"
A big thanks in advance.
Since you are in context of the Angular expression, you don't need interpolation tags {{...}}. So ngModel directive should look like this:
ng-model="CampaignsService.dropDownPercent[CampaignsService.selectCounter]"

Descending order for list-divider in AngularJs

How may I order the <div class="item item-divider"> in descending way, where on the top I would like to have the most recent date?
// index.html
...
<ion-content>
<div ng-repeat="(date,list) in items">
<div class="item item-divider">
{{date}}
</div>
<ul class="list">
<li class="item item-icon-right" ng-repeat="item in list">
<h2>{{item.name}} {{item.surname}}</h2>
</li>
</ul>
</div>
</ion-content>
...
-------------------------------------------------------------------------------------------------
// app.js
angular.module('ionicApp', ['ionic'])
.controller('MyCtrl', function($scope) {
$scope.items = {
'11/12/2014':[
{name:'mark',surname:'john',birth:'11/12/2014'}
],
'12/12/2014':[
{name:'tom',surname:'smith',birth:'12/12/2014'}
{name:'carl',surname:'northon',birth:'12/12/2014'}
]
}
});
Why not sort the object itself, before passing it to angular.
function sortObjectByKeys(object, order) {
var sortedObject = {}, key, tempKeyArray = [];
for (key in object) {
if (object.hasOwnProperty(key)) {
tempKeyArray.push(key);
}
}
// You can also retrieve all the keys using Object.keys() method and then sort them..
tempKeyArray.sort(function(a, b){return b - a});
for (key = 0; key < tempKeyArray.length; key++) {
sortedObject[tempKeyArray[key]] = object[tempKeyArray[key]];
}
return sortedObject;
}
Can you change the data-structure to have two keys, 'date' and 'people'? Then you could do
items | orderBy:'date'
This should work fine:
$scope.mysort = function(obj){
var sortedObject = {}, key, tempKeyArray = [];
for (key in obj) {
if (obj.hasOwnProperty(key)) {
tempKeyArray.push(key);
}
}
tempKeyArray.sort(function(a, b){
var parts = a.split("/");
a = new Date(parts[2], parts[1] - 1, parts[0])
parts = b.split("/");
b = new Date(parts[2], parts[1] - 1, parts[0]);
return b-a;
});
for (key = 0; key < tempKeyArray.length; key++) {
sortedObject[tempKeyArray[key]] = obj[tempKeyArray[key]];
}
return sortedObject;
}

Resources