AngularJS: function call with ng-class - angularjs

i am calling a function from ng class because i want to return class name dynamically based on price.
i have 6 data and function suppose to call 6 times but when i run the code then i saw it is calling 12 times.....anyone can see the code and tell me why the function is getting called 12 time instead of 6.
<div ng-app="myApp">
<ul ng-controller="MyController">
<li ng-class="setColor(item.price)" ng-repeat="item in products">{{item.name}} — {{item.price}}</li>
</ul>
</div>
var myApp = angular.module('myApp', []);
myApp.controller('MyController', function MyController($scope) {
$scope.setColor = function(price) {
alert(price);
}
$scope.products = [
{
'name' : 'Xbox',
'clearance' : true,
'price' : 30.99,
},
{
'name' : 'Xbox 360',
'clearance' : false,
'salesStatus' : 'old',
'price' : 99.99,
},
{
'name' : 'Xbox One',
'salesStatus' : 'new',
'price' : 50,
},
{
'name' : 'PS2',
'clearance' : true,
'price' : 79.99,
},
{
'name' : 'PS3',
'salesStatus' : 'old',
'price' : 99.99,
},
{
'name' : 'PS4',
'salesStatus' : 'new',
'price' : 20.99,
}
]
})
here is jsfiddle https://jsfiddle.net/tridip/ob8jh2o7/1/
UPDATE : My Objective
if price less than 50 then item color should be red. if price more than 50 then item color should be yellow and if price more than (50+(50*60/100)) then item color should be green. now tell me how could i achieve it with less iteration. guide me with best approach to complete it.
thanks
if fix it. here is my new fiddle link https://jsfiddle.net/tridip/ob8jh2o7/22/

Based on Using ng-class with a function call - called multiple times
You can try something like this if you are just modifying the class:
var colourMap = {
"30.99": "speciality1Class",
"99.99": "speciality2Class",
"50": "speciality3Class",
"79.99": "speciality4Class",
"20.99": "speciality5Class"
};
$scope.setColor = function(price) {
return colourMap[price];
}
fiddle: https://jsfiddle.net/ob8jh2o7/11/
However, if you are using an alert or log it is going to be called all those times because angulars use of dirty checking. If you are trying to fire an alert though, I would not use ng-class. You can read more about angulars dirty checking here - https://docs.angularjs.org/guide/scope#scope-life-cycle .

Angularjs uses a dirty-check approach, so it need to call all the filters to see if exists any change. After this it detect that have a change on one variable(the one that you typed) and then it execute all filters again to detect if has other changes.
The first call is from the watchers that are detecting the change. Because there is one then they need to be called again to see if is there news changes because a watcher can make changes.

<li ng-class="{red : item.price <= 50 , yellow: item.price > 50 && item.price <= 50 + 50*0.6, green: item.price > 50 + 50*0.6}" ng-repeat="item in products track by $index">{{item.name}} — {{item.price}}</li>
Edited Fiddle working: https://jsfiddle.net/ob8jh2o7/21/

Related

Limit number of chips display

I'd like to display only a the first three chips of a list, and put a marker that there are more to see (like three dots for example).
Is there a way to do so with the <md-chips> directive ?
I'd prefer specify that I'm talking about a read-only chips list, not editable. I've tried with md-max-chips but it only controls the add of new chips.
Some piece of code :
<div layout="row" layout-align="start center">
<md-chips ng-model="mylist" readonly="true"></md-chips>
</div>
How I would like it to be displayed (the header is not in the code)
Try this solution:
HTML:
<md-chips ng-model="ctrl.visible" readonly='true' ng-click="ctrl.select($event)">
</md-chips>
Javascript:
self.fruitNames = ['Apple', 'Banana', 'Orange', 'Test1', 'Test2', 'Test3', 'Test4'];
var i = 0;
function ModifyVisible(){
self.visible = self.fruitNames.slice(0, (3 * ++i));
if(self.fruitNames.length > self.visible.length)
self.visible.push('...');
}
ModifyVisible();
self.select = function($event) {
if($event.path[0].textContent == '...')
ModifyVisible();
}
You may going to try to manipulate your list object like in this codepen demo. The last item is an placeholder item. You should manipulate your list before rendering / binding to view.
self.vegObjs = [
{
'name' : 'Broccoli',
'type' : 'Brassica'
},
{
'name' : 'Cabbage',
'type' : 'Brassica'
},
{
'name' : 'Carrot',
'type' : 'Umbelliferous'
},
{
'name' : '...',
'type' : ''
}
];

angular ui-grid enable disable row element based on flag

I am using angular ui-grid to show list of rows from database table(Users).
I am doing a back end call and NodeJS fetches the data from DB and returns.
This data is being shown in angular ui-grid.
I want to enable or disable few html elements ., view/edit/delete based on the accessibility of the current user.
If the current user is ADMIN then all the links are enabled. If he is BASIC user then VIEW is enabled and EDIT and DELETE are disabled.
Project accessibility is also returned from the server . I just need to check this flag and disable/enable the links.
Please let me know , how to do this?
id name actions
1 AAA view edit delete
2 BBB view edit delete
3 CCC view edit delete
4 DDD view edit delete
<div class="box">
<div class="box-content box-table">
<div ui-grid="gridUsers" ui-grid-pagination>
</div>
</div>
</div>
$scope.gridUsers = {
paginationPageSizes: [15, 30, 45],
paginationPageSize: 15,
enableColumnMenus: false,
data: $scope.users,
filterOptions: $scope.filterOptions,
columnDefs: [{ field: 'id', displayName: 'Id', width: '20%'},
{ field: 'name', displayName: 'Name', width: '25%', enableFiltering: true},
{ name: 'Actions', displayName: 'Actions', width: '55%', cellTemplate:
'<div class="grid-action-cell action-btns">'+
'<span class="btn-small"><span style="color:#214c77;">view</span> </a>' +
'<a ng-click="grid.appScope.edit(row.entity.id)" class="btn-small btn-link"><span style="color:#80bb41;">edit</span> </a>' +
'<a ng-click="grid.appScope.delete(row.entity.id)" class="btn-small btn-link"> <span style="color:#e15829;">delete</span> </a>'
'</div>'}
]
};
Service.GetAllUsers(function (response) {
if (response.length != 0) {
$scope.users = response;
$scope.gridUsers.data = $scope.users;
}
});
I had the same problema.
In order to resolve it, I call a function after retrieving columns :
function updateColumnsDefs() {
columnsDefs
.forEach(function(column) {
switch (column.field) {
case 'status' :
columnVal = '<span ng-if="c.' + column.filterBy + '">{{c.' + column.filterBy + '}}</span>';
column.cellTemplate = '<div class="ui-grid-cell-contents">' + columnVal + '</span></div>';
break;
default :
break;
}
}
Look how I made a dynamic cellTemplate using ng-if.
After that, I apply the updated columnsDefs to gridOptions:
updateColumnsDefs();
vm.gridOptions = {
...
columnDefs : columnsDefs,
...
};
You should pay attention if use lazy loading or filter. In that case remember to recall updateColumnsDefs every time your data model changes.

angular ui grid date filter to search the date in column

I wanted to search the date in my search column, using angular ui date filter.
When i try to search my date in the column, its not showing the correct date.
I want it to show the exact match of user search.
Example: If user types 22-aug-16, it should show only date matching to this date, suppose if users types 25-aug alone it should show only dates matching 25th august in any year that is present in the database.
I tried with my code like,
.controller(
'BlockADetailsController',
[
'$scope', '$rootScope','$location','$routeParams', '$filter', 'CommonService', 'BlockADetailsService', '$q',
function($scope, $rootScope,$location, $routeParams, $filter, CommonService, BlockADetailsService, $q) {
$scope.changeActorGridOptions = {
enableFiltering : true,
columnDefs : [
{
{
name : 'lLDate',
field : 'lLDate',
displayName : 'LAST_LOGIN',
width : '100',
minWidth: '90',
cellTemplate : '<div title="{{COL_FIELD | date:\'dd-MMM-yy\' }}">{{COL_FIELD | date:"dd-MMM-yy" }}</div>',
headerTooltip : true,
cellClass : function(grid, row,
col, rowRenderIndex,
colRenderIndex) {
return 'gridGroupCell';
},
headerCellFilter : 'translate',
},
Here i also tried with
type: 'date'
And also added the onselect function which is mentioned in the same kind of question in stackoverflow.
Like,
onSelect: function(date){
scope.$apply(function() {
ngModel.$setViewValue(date);
});
}
Please help me in this, hope i explained my requirement. Kindly show some assistance for it.
This is the column field where i am doing the search,
Here i want to search my required date, it has to show only the relevant.'
This worked for me,
{
name : 'lLDate',
field : 'lLDate',
displayName : 'LAST_LOGIN',
type : 'date',
cellFilter : 'date:"dd-MMM-yy"',
filterCellFiltered : 'true',
width : '100',
minWidth: '90',
cellTemplate : '<div title="{{COL_FIELD | date:\'dd-MMM-yy\' }}">{{COL_FIELD | date:"dd-MMM-yy" }}</div>',
headerTooltip : true,
cellClass : function(grid, row,
col, rowRenderIndex,
colRenderIndex) {
return 'gridGroupCell';
},
headerCellFilter : 'translate',
},
I created a custom filter function for matching date and applied it in 'condition' field,PFB the columnDef for the field :
{
name: 'orderDate',
enablePinning: false,
enableSorting: true,
sort: { direction: 'asc' },
width: "15%",
displayName: 'Order Date',
cellClass: 'pr25',
filterCellFiltered:true,
cellFilter: 'date:"yyyy-MM-dd"',
filterHeaderTemplate: '<div class="ui-grid-filter-container" ng-repeat="colFilter in col.filters"><input type="date" class="ui-grid-filter-input" ng-model="colFilter.term" /></div>',
filters:[
{
filterName: "equalsTo",
condition: function(searchTerm, cellValue) {
var strippedValue = (cellValue + '').replace(/[^\d]/g, '-');
var d1= new Date(strippedValue);
var d2= new Date(searchTerm);
return (
d1.getMonth() === d2.getMonth() &&
d1.getDate() === d2.getDate()
);
},
placeholder: 'equals'
}]
}
Hope this helps.
You can add a filter condition to the column to check for less or greater than conditions. If you just want to check for exact date string match use the following as the filter condition.
filter: {
condition: uiGridConstants.filter.CONTAINS,
placeholder: 'placeholder'
},
This plnkr shows the filter condition with date matching
http://plnkr.co/edit/a9W4Gy7oUpdqieQjEw1A?p=preview

ng-model is not passing through correct value

I have a select element in which users can select a orderBy filter,
%select{
"ng-change" => "select()",
"ng-model" => "selectedItem",
"ng-options" => "option.sortBy for option in listOfOptions"}
This is the listOfOptions
$scope.listOfOptions = [
{sortBy: 'Release date', value:'release_date'},
{sortBy: 'Newly added', value:'created_at'}
];
And the select function,
$scope.select = function(){
console.log($scope.selectedItem.value)
}
In the view the select box shows both the release date and newly added options, but when I select one of them I get the error,
TypeError: Cannot read property 'value' of undefined
So it looks like $scope.selectedItem is undefined, but I can't figure out why.
Well I did a plunker and the select works as expected
Plunker
app.js:
$scope.listOfOptions = [{
sortBy: 'Release date',
value: 'release_date'
}, {
sortBy: 'Newly added',
value: 'created_at'
}];
$scope.select = function() {
console.log($scope.selectedItem.value)
}
Index.html:
<select ng-change="select()" ng-options="option.sortBy for option in listOfOptions" ng-model="selectedItem"></select>
<p>{{selectedItem}}</p>
Can you provide your angular version ?

Which ng-grid triggered the ngGridEventEndCellEdit?

I have two ng-grids living in the same $scope, they both have a column of editable cells, ie: enableCellEdit: true
I know I can handle the triggered event like this:
$scope.$on('ngGridEventEndCellEdit', function(event) {
var product = event.targetScope.row.entity;
console.log(product);
});
Question is.. how do I know which grid triggered the event? both grids consume different lists (data attribute of the grid), but these lists contains instances of the same type.
Is there any property inside event that contains the id of the grid?
I had the same trouble and worked around it.
I have three grids and on each cellEditableTemplate I register the ng-click on the cell, thus selecting the next source of the start and end event of the cell edit. The setMethod() that just sets the global variable $scope.thisGridUpdate
$scope.targetTypeDefs = [ {
field : 'id',
displayName : '#',
enableCellEdit : false,
width : 50
}, {
field : 'desc',
displayName : 'Type Description',
enableCellEdit : true,
cellEditableCondition : 'row.selected',
editableCellTemplate : '<input ng-class="\'colt\' + col.index" \
ng-input="COL_FIELD" \
ng-model="COL_FIELD" \
ng-model-options="{ updateOn : \'default blur\' }" \
ng-click="setMethod(\'saveTargetType\')"/>'
} ];
$scope.targetTypeGrid = {
data : 'targetTypeData',
showSelectionCheckbox : true,
selectWithCheckboxOnly : true,
multiSelect : false,
enableCellEditOnFocus : true,
columnDefs : 'targetTypeDefs'
};
Next you just catch and trap the end cell edit events in your normal ngGridEventEndCellEdit event consumer, like this:
$scope.setMethod = function(name) {
console.log("clicked on ", name);
$scope.thisGridUpdate = name;
};
$scope.$on('ngGridEventEndCellEdit', function(evt, other) {
console.log("ended edit on ", $scope.thisGridUpdate, "with " , evt.targetScope.row.entity);
console.log(evt.targetScope.row);
if ($scope.thisGridUpdate === 'saveServerType') {
EntityMgt.saveServerType(evt.targetScope.row.entity);
}
else if ($scope.thisGridUpdate === 'saveOsVersion') {
EntityMgt.saveOsVersion(evt.targetScope.row.entity);
}
else if ($scope.thisGridUpdate === 'saveTargetType') {
EntityMgt.saveTargetType(evt.targetScope.row.entity);
}
});

Resources