ng-class doesn't work properly for selected checkbox - javascript

I faced with a small problem related with ng-class. I have a list of checkboxes. For this list, I setup ng-class next way, if checkbox selected, set custom css class for selected item. Also I have a checkbox "Select All ", if I click on this box, css class applied for all items, but when I deselect all, css class doesn't change for items which been selected manually before.
I created plunker to show my problem.
What am I missing and where is my mistake? Thanks in advance.
html
<table class="table table-hover">
<tr ng-class="{'selected': allCategoriesSelected, 'default': !allCategoriesSelected}">
<td class="col-md-2">
<input type="checkbox" ng-click="selectAllCategories()" >
</td>
<td class="col-md-10" ng-if="!allCategoriesSelected">Select all</td>
<td class="col-md-10" ng-if="allCategoriesSelected">Deselect all</td>
</tr>
<tr ng-repeat="category in categories | orderBy : 'id'" ng-class="{'selected': allCategoriesSelected, 'default': !allCategoriesSelected}" >
<td class="col-md-2">
<input type="checkbox" ng-model="allCategoriesSelected" ng-click="updateCategory(category.id)">
</td>
<td class="col-md-10">{{ category.name }}</td>
</tr>
</table>
js
$scope.selectedCategories = [];
$scope.allCategoriesSelected = false;
$scope.selectAllCategories = function() {
$scope.allCategoriesSelected = !$scope.allCategoriesSelected;
};
$scope.updateCategory = function(categoryId) {
if ($scope.selectedCategories.indexOf(categoryId) > -1) {
$scope.selectedCategories.splice($scope.selectedCategories.indexOf(categoryId), 1);
} else {
$scope.selectedCategories.push(categoryId);
}
};

Take a look at this plunker, it should work.
This is the controller :
$scope.selectAllCategories = function () {
if(!$scope.allCategoriesSelected) $scope.setAll(false);
else $scope.setAll(true);
};
$scope.updateCategory = function () {
if($scope.checkedAll()) $scope.allCategoriesSelected = true;
else $scope.allCategoriesSelected = false;
};
$scope.checkedAll = function(){
var ret = true;
$scope.categories.forEach(function(item){
if(!item.selected) ret = ret && false;
});
console.log(ret);
return ret;
}
$scope.setAll = function(state){
$scope.categories.forEach(function(item){
item.selected = state;
});
}

I think you are making it too complicated. This can be easily solved with much less code. Here is a working plunker: https://plnkr.co/edit/xJz8pdRa4CBWUbdeYbyk?p=preview
Instead of trying to make a separate array to keep track of selected items, just set selected property on categories array.
<table class="table table-hover">
<tr ng-class="{'selected': allCategoriesSelected, 'default': !allCategoriesSelected}">
<td class="col-md-2">
<input type="checkbox" ng-model="allCategoriesSelected" ng-click="selectAllCategories()" >
</td>
<td class="col-md-10" ng-if="!allCategoriesSelected">Select all</td>
<td class="col-md-10" ng-if="allCategoriesSelected">Deselect all</td>
</tr>
<tr ng-repeat="category in categories | orderBy : 'id'" ng-class="{'selected': category.selected}" >
<td class="col-md-2">
<input type="checkbox" ng-model="category.selected">
</td>
<td class="col-md-10">{{ category.name }}</td>
</tr>
</table>
Changing the markup above, allows this to be accomplished with only one method.
$scope.allCategoriesSelected = false;
$scope.selectAllCategories = function () {
var selected = $scope.allCategoriesSelected ? true : false;
angular.forEach($scope.categories, function(category) {
category.selected = selected;
});
};

Related

How do i filter name in ng-repeat angularjs?

Currently, if I filter, the BookingID and Product I see that filtered result in UI. How do I have to add a filter for a name? because this name is coming from another array and getting it based on id
need to add filter based on BookingID, Product and name fields
Here's my code:
<div ng-app="datatable" ng-controller="datacontroller">
<md-card>
<div layout="row" style="height:50px; vertical-align: middle;">
<md-input-container md-no-float class="md-block" flex="85" >
<input ng-model="searchBooking" type="text" placeholder="Search">
</md-input-container>
</div>
</md-card>
<md-table-container>
<table md-table>
<thead md-head md-order="filter">
<tr md-row>
<th md-column><span>BookingID</span></th>
<th md-column><span>Product</span></th>
<th md-column><span>Name</span></th>
</tr>
</thead>
<tbody md-body>
<tr md-row ng-repeat="row in filterBooking() | orderBy:filter">
<td md-cell>{{row.BookingID}}</td>
<td md-cell>{{row.Product}}</td>
<td>
<md-select ng-model="row.UserID" ng-change="test(row)">
<md-option ng-repeat="user in users" ng-value="user.id">{{user.name}}</md-option>
</md-select>
</td>
</tr>
</tbody>
</table>
</md-table-container>
</div>
controller
angular.module("datatable", ['ngRoute', 'ngMaterial', 'md.data.table']).controller("datacontroller", ['$scope', function($scope) {
$scope.bookings = [
{
"BookingID":1,
"Product":"test",
"Shop":"A",
"ContactNumber":124,
"UserID":1
},
{
"BookingID":2,
"Product":"bgh",
"Shop":"d",
"ContactNumber":345,
"UserID":2
}
];
$scope.users = [
{
"id":1,
"name":"abc"
},
{
"id":2,
"name":"xyz"
}
]
$scope.searchBooking = '';
$scope.filterBooking = function () {
return $scope.bookings.filter(function (item) {
return (
item.BookingID.toString().indexOf($scope.searchBooking) > -1||
( item.Product.toLowerCase().indexOf($scope.searchBooking.toLowerCase()) > -1)
);
});
};
}]);
demo
Please advice
user name comes from a different array so I'm not sure how should filter name
so if you first add a 'name' property to every object in your bookings array, having its value cross matched from your 'users' array, this will make your life easier as you can then filter like:
<tr md-row ng-repeat="row in filterBooking() | orderBy:'+name'">
'name' being the new property in each of your objects, and + indicating an ascending order.
Adding the 'name' property to the items of your bookings array can be done with a simple for loop.
for (var i=0; i<$scope.bookings.length; i++) {
$scope.bookings[i].name = $scope.users.filter(function(_){ _.id === $scope.bookings[i].UserID })[0].name;
}

Change style for element from ng-repeat

I am trying to uniqeley identify buttons in a tablerow, so I can change the style if one of them is clicked. Here is the table i am working on:
And here is the code:
<table class="table">
<thead>
<tr>
<th>Allergi navn</th>
<th>Allergi verdi</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="items in $ctrl.allergen">
<td>
<b>
{{items.Allergennavn}}
</b>
</td>
<td id="{{$index}}">
<button
id="tableButton"
type="button"
class="btn-grey"
ng-repeat="item in $ctrl.allergenVerdiType"
ng-click="$ctrl.allergiAssigned($index, items, item)"
>
<b>
{{item.Allergenverdi}}
</b>
</button>
<hr>
</td>
</tr>
</tbody>
</table>
And js:
ctrl.allergiAssigned = function($index, itemAllergen, itemAllergenType){
var index = $('button').index(this);
$(index, '#tableButton').css("background-color", "green");
}
I have tried several approaches to reference the specific button-element, using this, index, etc. I also need to verfiy that for every row, there is only one of the buttons that are selected.
I also tried to pass {{$index}} to get a unique identifier for the row, but jquery doesn't support the syntax.
UPDATE based on answers:
<table class="table">
<thead>
<tr>
<th>Allergi navn</th>
<th>Allergi verdi</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="items in $ctrl.allergen">
<td>
<b>
{{items.Allergennavn}}
</b>
</td>
<td id="{{$index}}">
<button id="tableButton" type="button"
class="btn-grey" ng-class="{activeBtn: item.active == true}"
ng-repeat="item in $ctrl.allergenVerdiType"
ng-click="$ctrl.select(items.type, item)">
{{item.AllergenverditypeKode}}</button>
<hr>
</td>
</tr>
</tbody>
</table>
ctrl.select = function(items, index) {
angular.forEach(items, function(item){
item.active=false;
});
index.active = true;
};
index returns undefined
You can change the CSS class based on the user action by using ng-class directive.
details
Code will be like that.
In CSS class :.activeButton:{background-color", "green"}
In button ng-click function : buttonClicked[$index]=true;
In Html button input:
..... ng-class="{'btn-grey':'btn-grey',
'activeButton':<add your condition like 'buttonClicked[$index]'>}"
To uniquely identify an element in nested ng-repeat, you can assign a unique Id to it by combining the $index from the parent loop and from the child loop as :
id="tableButton_{{$parent.$index}}_{{$index}}"
Now, pass the parent index and the child index to the event, fetch the element and change its css:
ng-click="assigned($parent.$index, $index)"
Below is a snippet of a sample data:
angular.module("app", []).controller("ctrl", function($scope) {
$scope.items = ["Item A", "Item B"];
$scope.buttonTypes = ["Btn1", "Btn2", "Btn3", "Btn4"];
$scope.assigned = function(parentIndex, childIndex) {
//Reset all buttons for one row
var parentBtns = "#" + parentIndex + " :button";
$(parentBtns).css("background", "transparent");
//Change the selected button css
var btn = "#tableButton_" + parentIndex + "_" + childIndex;
$(btn).css("background", "green");
};
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body ng-app="app" ng-controller="ctrl">
<table class="table">
<thead>
<tr>
<th>Allergi navn</th>
<th>Allergi verdi</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in items">
<td>
<b>{{item}}</b>
</td>
<td id="{{$index}}">
<button id="tableButton_{{$parent.$index}}_{{$index}}" type="button" class="btn-grey" ng-repeat="type in buttonTypes" ng-click="assigned($parent.$index, $index)">
<b>{{type}}</b>
</button>
<hr>
</td>
</tr>
</tbody>
</table>
</body>
You can try something like the below code, also you check you given working plunker example.
Template:
<button id="tableButton" type="button" class="defaultBtn" ng-class="{activeBtn: item.active}" ng-repeat="item in items.type" ng-click="select(items.type, item)">{{item.value}}</button>
Controller:
$scope.select= function(items, index) {
// You can remove this loop part if you don't want to reset your selection..
angular.forEach(items, function(item){
item.active=false;
});
index.active = true;
};

Function isn't called with responsed data

Hello I got a weird problem... I lost almost 2 hrs and I have no idea why it doesn't work.
It should sum all values for every dept where username = name choosed by select and where date = date choosed by datepicker.
It works great on jsFiddle but when I am trying use it with responsed data it doesn't work and don't have any errors in console.
What am I doing wrong? This is code in my app not the same which is in jsFiddle
HTML:
<div layout="row">
<md-datepicker ng-model="myDateUser" md-placeholder="Enter date"></md-datepicker>
{{myDateUser}}
<md-input-container flex="50">
<label for="repeatSelect"> Select user: </label>
<md-select ng-model="data.model" ng-change="sum(data.model)">
<md-option ng-value="logins.name" ng-repeat="logins in chooseLogins">{{logins.name}}</md-option>
</md-select>
</md-input-container>
<br/>
<hr/>
<tt>{{data.model}}</tt>
</div>
<md-table-container>
<table md-table>
<thead md-head>
<tr md-row>
<th md-column>Dept</th>
<th md-column>Total time</th>
<th md-column></th>
</tr>
</thead>
<tbody md-body>
<tr ng-if="!data.model" md-row md-select="test" md-on-select="" md-auto-select ng-repeat="test in tests">
<td md-cell>{{ test.dept }}</td>
<td md-cell>{{ test.total }}</td>
<td md-cell></td>
</tr>
<tr ng-if="data.model" md-row md-select="test" md-on-select="" md-auto-select ng-repeat="(key,val) in data.model">
<td md-cell>{{ key }}</td>
<td md-cell>{{ val }}</td>
<td md-cell></td>
</tr>
</tbody>
</table>
</md-table-container>
JS:
function getTotalTime() {
$http.get('db_files/totalTimeDB.php').then(function(response) {
$scope.data = response.data;
$scope.sum = function(name) {
let model = $scope.data.filter(function(item) {
return (item.username == name && TheDate(item))
});
let tests = {};
model.forEach(function(item) {
if (!tests.hasOwnProperty(item.dept)) {
tests[item.dept] = 0;
}
tests[item.dept] += parseFloat(item.task_time);
});
$scope.data.model = tests;
}
function TheDate(item){
if($scope.myDateUser){
var myDateUser = new Date($scope.myDateUser);
var itemDate = new Date(item.task_end);
console.log("task_end " + item.task_end);
console.log("myDate " + $scope.myDateUser);
if(myDateUser.getFullYear() != itemDate.getFullYear() || myDateUser.getMonth() != itemDate.getMonth()){
return false;
}
}
return true
}
Example console.log from $scope.data = response.data;
Object
dept:"Test2"
status:"Closed"
task:"test test test"
task_end:"2016-09-02"
task_start:"2016-09-02"
task_time:"80"
username:"Nelson"
__proto__:Object
It works like show total sum only where username = choosed name and TheDate function is ignored. Also console.log shows nothing ( in example jsFiddle console.log shows selected date and name )
It looks like the function isn't called.

Keep selected element highlighted after resorting table

I have a table in AngularJS with several columns that can each be sorted ascending and descending. I want a row to be selected whenever a user clicks on it. I do this by getting the selected index of the table. However, once I resort one of the columns, the selected row remains highlighted. What I want to do is to keep the previously selected item highlighted...whereever its new index may be after the resorting. Here is a code snippet:
My table body:
<tbody>
<tr
ng-class="{'selected':$index == list.selectedRow}"
ng-repeat="item in list.itemList | order:list.orderBy:list.orderAsc">
<td ng-click="list.select(item);list.setClickedRow($index)">{{ item.number }}
</td>
<td ng-click="list.select(item);list.setClickedRow($index)">{{ item.name }}
</td>
</tr>
</tbody>
The method for setting the selected row:
function setClickedRow(index) {
vm.selectedRow = index;
}
Based on Slonski answer, I suggest you to loop over all items to set selected = false when you change your selection:
function setClickedRow(item) {
for(var i = 0; i < $scope.list.itemList.length; i++) {
if(item == $scope.list.itemList[i]) item.selected = true;
else $scope.list.itemList[i].selected = false;
}
item.selected = true;
}
Update: Solution without a loop
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', ['$scope', function($scope) {
$scope.setMaster = function(section) {
$scope.selected = section;
}
$scope.isSelected = function(section) {
return $scope.selected === section;
}
}]);
.active {
background-color: orange;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<table>
<tr ng-repeat="i in ['One', 'Two', 'Three']" ng-class="{active : isSelected(i)}">
<td ng-click="setMaster(i)">{{i}}</td>
</tr>
</table>
<hr> {{selected}}
</div>
You can add selected to your item, and the set it to true on click (or set it to !item.selected if you want to toggle selection on click)
<tbody>
<tr
ng-class="{'selected':item.selected}"
ng-repeat="item in list.itemList | order:list.orderBy:list.orderAsc">
<td ng-click="list.select(item);list.setClickedRow(item)">{{ item.number }}
</td>
<td ng-click="list.select(item);list.setClickedRow(item)">{{ item.name }}
</td>
</tr>
</tbody>
function setClickedRow(item) {
item.selected = true;
}

Number the rows in ng-repeat

I have a table which has a ng-repeat directive in it. It uses a filter to filter out objects not having property qty>0. I need to give a serial no. to each of the rows. Note that the rows are not fixed. If a user changes the qty of a product to make it 0, it is removed from the table.
<table class="table table-striped">
<tr>
<th>S.no</th><th>Product Name</th><th>Qty</th><th>Sub-Total</th>
</tr>
<tr class="orders" ng-repeat="product in products" ng-if="product.qty">
<td>{{$index}}</td><td>{{product.name}}</td><td> <input type="number" min="0" ng-blur="product.qty = qty" ng-model="qty" value="{{product.qty}}"> </td> <td>{{product.qty*product.price | currency:"₹"}}</td>
</tr>
</table>
Now, the problem with this code is that, the $index gives the actual index of the product in the products array. I need it to give the index in the filtered array. How do I do that?
You can filter the items beforehand as follows:
<tr class="orders" ng-repeat="product in filterItems(products)">
<td>{{$index}}</td><td>{{product.name}}</td><td> <input type="number" min="0" ng-blur="product.qty = qty" ng-model="qty" value="{{product.qty}}"> </td> <td>{{product.qty*product.price | currency:"₹"}}</td>
</tr>
Controller:
$scope.filterItems = function(items) {
var filtered_items = [];
angular.forEach(items, function(item) {
if(item.qty > 0) {
filtered_items.push(item)
}
})
return filtered_items;
}
Use filter in ng-repeat:
HTML
<tr class="orders" ng-repeat="product in products | filter: hasQty">
<td>{{$index}}</td><td>{{product.name}}</td><td> <input type="number" min="0" ng-blur="product.qty = qty" ng-model="qty" value="{{product.qty}}"> </td> <td>{{product.qty*product.price | currency:"₹"}}</td>
</tr>
JS:
$scope.hasQty = function (value) {
return value.qty > 0
}
Untested.

Categories

Resources