How to use ng-class compare to self invoked value - javascript

Hi I have been using this tag to change my css style, if the condition totalAsset and sortedAsset are same
<div class="table-row" ng-repeat="x in myData"
ng-model="sort(x.totalAsset)"
ng-class="{'lightblue': x.totalAsset == sortedAsset}">
totalAsset is my data in like this
$scope.myData = [
{
totalAsset: "23557"
},
{
totalAsset: "4512190",
},
{
totalAsset: "2190",
},
{
totalAsset: "1256790",
}
]
i have create a function that self sort the totalAsset
$scope.sort = function(totalAsset) {
$scope.unsortedAsset = totalAsset;
$scope.sortedAsset = $scope.unsortedAsset.split("").sort().join("");
console.log(sortedAsset);
}
in the logic only the first and last row will become blue the other two rows remain same.
But my problem here is only the last one become blue, the first one doesn't.

I am not sure about, if you need the {{ }}( they are not needed in ng2 atleast ).
<div class="table-row" ng-repeat="x in myData"
ng-model="sort(x.totalAsset)"
ng-class="x.totalAsset == sortedAsset ? 'lightblue' : ''">
Second approach is to do the if in controllers function
$scope.areValuesEqual() {
if($scope.x.totalAssets == $scope.sortedAssets) {
return 'lightblue';
}
return;
}
But this looks rather ugly, but i am just throwing this out there.

Related

AngularJS get first item in a repeat that has a certain value

<div ng-repeat="widget in widgets"
ng-class="">
<div>{{widget.row}}</div>
</div>
I'm trying to apply a class inside the repeat based on a particular value in the repeat, for example if widget.row = 0 and it is the first widget with that value displayed then give it a class and all the other widgets that have row as 0 do not get the class. This will need to be the case if it equals 1 or 2 and so on so I can't just use $first as there will be multiple row values and multiple widgets for example it may output something like:
0 0 0 0 1 1 2 2 2 2
So the easiest way for me to achieve this was using the Adjacent sibling selector rather than do it with angular as each item is not really aware of the others:
<div ng-repeat="widget in widgets"
class="widget-row-{{widget.row}}">
<div>{{widget}}</div>
</div>
and then use CSS for:
.widget-row-0:first-child {}
.widget-row-0 + .widget-row-1 {}
.widget-row-1 + .widget-row-2 {}
.widget-row-2 + .widget-row-3 {}
Best practise is to prepare your data in a init function in your controller. It's nice and KISS! It's the best way to prepare your data in control function instead of misapply the E2E binding of AngularJS. It solve your problem so no class is written when there is no need for (as you asked for). Its proceeded once instead of calling a function again, again and again by E2E binding like ng-class="shouldIAddAClass()".
View
<div ng-repeat="widget in widgets"
ng-class="{ 'first' : widget.first }">
<div>{{widget.row}}</div>
</div>
Controller
$scope.widgets = [{
row: 0
}, {
row: 2
},{
row: 0
},{
row: 1
},{
row: 1
},{
row: 2
},{
row: 0
}];
//self calling init function
(function init () {
var widgetRowFound = {};
angular.forEach($scope.widgets, function (widget, key) {
if (angular.isDefined(widgetRowFound[widget.row])) {
$scope.widgets[key].first = false;
} else {
$scope.widgets[key].first = true;
widgetRowFound[widget.row] = true;
}
});
})();
Not the cleanest one but will work
<div ng-repeat="widget in widgets">
<div ng-class="{'myClass': applyClass(0, widget.row)}"></div>
</div>
----------
$scope.widgetsRows = {};
function applyClass(number, row){
if(!$scope.widgetsRows[row]){
$scope.widgetsRows[row] = true
}
return row == number && $scope.widgetsRows[row];
}
You can add the class you want to use to the widget objects in the controller first:
var tempRow = "";
for(var i = 0;i < $scope.widgets.length;i++) {
if($scope.widgets[i].row != tempRow) {
$scope.widgets[i].class = "myClass";
tempRow = $scope.widgets[i].row;
}
}
Then you can use that class:
<div id="widgets" ng-repeat="widget in widgets"
class="{{widget.class}}">
<div>{{widget.row}}</div>
</div>
Hope this helps
You can create a method that will be called from ng-class to achieve your goal. The method should return the class to be used.
$scope.firstHitFound = false;
$scope.isFirstZeroValue = function(value){
if($scope.firstHitFound == false && value == 0){
$scope.firstHitFound = true;
return class1;
}else{
return class2;
}
}
The HTML / Angular shoudl look as:
<div ng-class="isFirstZeroValue(widget.row)">
If you want to style it, add the class to all the widget that match your criteria, and use css to perform it only on the first of them.
Html:
<div id="widgets" ng-repeat="widget in widgets"
ng-class="{'widget-first': widget.row == 0}">
<div>{{widget.row}}</div>
</div>
Css:
#widgets.widget-first:first-of-type {
background: #ff0000;
}
You can use ng-class in addition of your ng-repeat:
Example
<div ng-repeat="widget in widgets" ng-class="{'test': widget.value === 0}">
<div>{{widget.row}}</div>
</div>
You need to call a method that will check if the row result is not same with previous value. If it not same , it will return true value and will be assigned ng-class, and if not return false. Filter this out using ng-if.
Html
<div ng-repeat="widget in widgets"
ng-class="">
<div ng-if="calculate(widget.row)">
<div ng-class="test">{{widget.row}}</div>
</div>
<div ng-if="!calculate(widget.row)">
<div>{{widget.row}}</div>
</div>
</div>
Controller
var arr = [];
$scope.calculate = function (row) {
arr.push(row);
var breakLoop = false;
angular.forEach(arr, function (oldVal, newVal) {
breakLoop = false;
if (oldVal != newVal) {
breakLoop = true;
}
)};
return breakLoop;
}

Using AngularJS to create an instant search by querying an array

This is going to be a rather longwinded question, so please bear with me...
I have an array of about 25-30 items. They are sorted through various filters such as brand, type, material, size, etc.. How can I go about building a searchable filter. All of the ones I've seen just include a filter:query | in their filters. However I can't get mine to query my existing array.
Here is what my array looks like, only going to show 1 item to keep size down..
$scope.products = [
{
src: 'images/img/image1.jpg',
name: 'XXX-1A',
brand: 'Brand A',
material: 'dry',
size: '00',
type: 'dry pipe',
color:'red'
}];
Function for filtering (only included 1 to save space):
$scope.brandIncludes = [];
$scope.includeBrand = function(brand) {
var i = $.inArray(brand, $scope.brandIncludes);
if (i > -1) {
$scope.brandIncludes.splice(i, 1);
} else {
$scope.brandIncludes.push(brand);
}
}
$scope.brandFilter = function(products) {
if ($scope.brandIncludes.length > 0) {
if ($.inArray(products.brand, $scope.brandIncludes) < 0)
return;
}
return true;
}
This is what I am using to filter from the HTML, I am using checkboxes to select each filter:
<div class="info" ng-repeat="p in products |
filter:brandFilter |
filter:materialFilter |
filter:typeFilter |
filter:styleFilter">
</div>
My search bar mark up:
<div class="filtering">
<div class="search-sect">
<input name="dbQuery" type="text" placeholder="Search pieces" class="search-input" ng-model="query"/>
</div>
One of the filter's mark up:
<input type="checkbox" ng-click="includeStyle('adaptor')"/>Adaptor<br>
Now that you have all the code, here are some of the things I've tried that don't seem to be running right:
My Attempt:
Search bar:
<input type="text" id="query" ng-model="query"/>
Filter:
<li ng-repeat="p in products | filter:query | orderBy: orderList">
I understand that to some experienced with angular, this is a relatively easy task, but I am just learning and can't seem to wrap my head around searching a query. It's probably a simple solution that I am overlooking. This is my first Angular app and I am trying to bite off more than I can chew in order to learn more.
I appreciate all responses, thanks in advance!
As per request: CodePen
The simple built-in angular filter is not smart enough to to work with your checkbox design, so try writing a custom filter. You will need to bind the checkboxes you mentioned to variables in your scope, e.g. brandFilterIsEnabled. See the tutorial for writing custom filters. Here is a working example.
var myApp = angular.module('myApp', []);
myApp.controller('ctrl', function ($scope) {
$scope.items = [{
name:'foo',
color:'red'
},{
name:'bar',
color:'blue'
},{
name:'baz',
color:'green'
}];
$scope.searchNames = true;
$scope.searchColors = true;
$scope.$watch('searchColors', function(){
$scope.searchKeys = [ $scope.searchNames ? 'name' : null, $scope.searchColors ? 'color' : null ];
});
$scope.$watch('searchNames', function(){
$scope.searchKeys = [ $scope.searchNames ? 'name' : null, $scope.searchColors ? 'color' : null ];
});
});
myApp.filter('advancedSearch', function($filter) {
return function(data, keys, query) {
results = [];
if( !query ){
return data;
} else {
angular.forEach( data, function( obj ){
var matched = false;
angular.forEach( keys, function( key ){
if( obj[key] ){
// match values using angular's built-in filter
if ($filter('filter')([obj[key]], query).length > 0){
// don't add objects to results twice if multiple
// keys have values that match query
if( !matched ) {
results.push(obj);
}
matched = true;
}
}
});
});
}
return results;
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<html ng-app="myApp">
<div ng-controller="ctrl">
<input type='checkbox' ng-model='searchNames'>search names</input>
<input type='checkbox' ng-model='searchColors'>search colors</input>
<input type='text' ng-model='query'>search objects</input>
<ul>
<li ng-repeat="item in items | advancedSearch : searchKeys : query">
<span style="color:{{item.color}}">{{item.name}}</span>
</li>
</ul>
</div>
</html>

i10n angularjs assign translate variable

Okay so i have the following small translation file:
{
"components" : {
"1" : "Video",
"2" : "Lyd",
"3" : "Dokument",
"4" : "Tekst"
}
}
And then i have the following li item:
<li ng-repeat="type in componentTypes" ng-hide="module.module_type_id == 2 || module.module_type_id == 10">{{type.name}}</li>
What you need to notice is :
{{type.name}}
Or more precisely:
translate="components.{{1}}"
With this it does not translate the <a></a> tag.
However if i do
translate="components.1"
it translates correctly however this method doesnt work for me
so my question is how can dynamicly change the value of a the translate attribute?
The reason components.{{1}} is not working is because the double curlies in Angular is just meant to evaluate an expression. 1 is just a number, so you'll get components.1 everytime.
If I understand what you need correctly, you need to have a corresponding component based on type. So if type.id === 1 then your type is Video.
In order to achieve that in Angular dynamically, you should just have:
translate="{{components[type.id]}}"
Fiddle
As far as I understand you want to dynamize the translation json if added a new type to your componentTypes array.
There is a solution for that need, you can implement a new custom translation loader factory and use it with specified way here https://github.com/angular-translate/angular-translate/wiki/Asynchronous-loading. After that you have to add this new item to the translation json, your array and then refresh the translation.
View:
<div ng-app="myApp">
Links to jsfiddle.net must be accompanied by code. Please indent all code by 4 <div ng-controller="MyCtrl">
<input type="text" ng-model="type.name" /> Add Component
<ul>
<li ng-repeat="type in componentTypes" ng-hide="module.module_type_id == 2 || module.module_type_id == 10">{{ 'components.' + type.name | translate }}</li>
</ul>
</div>
</div>
Implementation of your application:
var myApp = angular.module('myApp', ['pascalprecht.translate']);
var components_en = {
"components": {
"1": "Video",
"2": "Lyd",
"3": "Dokument",
"4": "Tekst"
}
};
myApp.config(function ($translateProvider) {
$translateProvider.useLoader('customLoader', {});
$translateProvider.translations('en', components_en);
$translateProvider.preferredLanguage('en');
});
myApp.controller('MyCtrl', function ($scope, $translate) {
$scope.module = {
module_type_id: 1
};
$scope.addComponent = function (type) {
// Add the componentTypes array you took from database
$scope.componentTypes.push({
name: $scope.componentTypes.length + 1
});
// Add the translation object
components_en["components"][$scope.componentTypes.length] = type.name;
console.log(components_en);
$translate.refresh();
};
$scope.componentTypes = [{
name: 1
}, {
name: 2
}, {
name: 3
}, {
name: 4
}];
});
myApp.factory('customLoader', function ($http, $q) {
return function (options) {
var deferred = $q.defer();
deferred.resolve(components_en);
return deferred.promise;
}
})
I prepared a demonstration for that like usage, please below jsfiddle:
http://jsfiddle.net/nerezo/1z071wzg/6/
Note: This like translation modifications will not be persistent and new translations will be lost.
Please give this a try:
translate="{{'components.' + type.id}}" //if there is id in type
or
translate="{{'components.' + ($index + 1)}}"

How to write VISIBILITY if-else condition in ANGULARJS?

How to Write Condition on data which is fetching from Json to Angularjs?
Example : if user FIRM NAME exists Show else if user FULL NAME exists Show else Show REALNAME
I have a working Example of fetching data
at line number 25 <h3 class="moduletitle">Name : {{ module.realname }}</h3>
Please See that in PLUNKER
I hope i will get the working code update along with PLUNKER
I can suggest you have a function that returns the entity in which you want to display. Then using ng-show / ng-hide to display/hide the things you want.
Example:
function pseudoDecide(){
var displaythis = "";
if(/*boolean exp*/){ displaythis = "firm" }
else if(/*boolean exp*/) { displaythis = "full" }
else(/*boolean exp*/) { displaythis = "real" }
return displaythis;
}
Then <div ng-show="{{psedoDecide() === 'firm'}}>" etc etc, something like that.
With AngularJS 1.1.5+, you can use the ternary operator inside an expression. In your case, I believe you want something like:
<h3 class="moduletitle">Name : {{ module.firmname ? module.firmname : (module.fullname ? module.fullname : module.realname)) }}</h3>
If you don't want a nested ternary in your template, you could also go this route:
Somewhere in your controller:
$scope.pickName = function (module) {
var val;
if (module.firm_name) {
val = module.firm_name;
} else if (module.full_name) {
val = module.full_name;
} else {
val = module.realname;
}
return val;
};
And in your template:
<h3 class="moduletitle">Name : <span ng-bind="pickName(module)"></span></h3>

externalizing ng-class for table cells

I'm trying to see if angularJs is useful for me to create a team-management application.
The issue I have:
I have a complex ng-class definition, being
ng-class="{'guard': ( guard.checked && day.func.indexOf('guard') != -1) }"
and it will prove to be bigger yet.
I was wondering if there is a way to have basically this:
# pseudocode, needs to be translated to js/angularJs
function getClasses(){
classes = ''
if ('guard' in user.day.func and guardCheckBox == checked){
classes = classes.append(' guard')
}
if ('f2' in user.day.func and f2CheckBox == checked){
classes = classes.append(' f2')
}
....
if ('fx' in user.day.func and fxCheckBox == checked){
classes = classes.append(' fx')
}
return(stripLeadingSpace(classes)
}
any tips on what to search, or any bits of code would be appreciated
a js-fiddle with what I have as of yet can be found here:
http://jsfiddle.net/mTJDh/1/
code from the fiddle for dead links
HTML:
Guard
<!--
this snippet applies the class 'guard' to every cell when the checkbox 'Guard' is checked
-->
<div ng-controller="MyCtrl">
<table ng-repeat="user in users">
<tr>
<td>{{user.name}}</td>
<td ng-repeat="day in user.days" ng-class="{'guard': ( guard.checked && day.func.indexOf('guard') != -1) }">
{{day.number}}
</td>
</tr>
</table>
</div>
JS
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.users = [
{name: 'PEDC',
days : [{number:'1', func:'guard'},
{number:'2', func:'guard'},
{number:'3', func:'guard'},
{number:'4', func:['guard','spoc']}
]
},
{name: 'JOVH',
days : [{number:'1', func:'guard'},
{number:'2', func:'guard'},
{number:'3', func:'spoc'},
{number:'4', func:'guard'}
]
}
];
}
CSS
.pending-delete {
background-color: pink
}
.guard {
border:solid black 1px
}
.spoc {
background-color: pink
}
EDIT:
This is the actual solution I use now:
http://jsfiddle.net/mTJDh/2/
basically:
added functions isGuard, isSpoc and isHoliday to my controller, with the day as an argument
these return true or false based on the json array.
idea gotten from here and https://docs.angularjs.org/api/ng/input/input%5Bcheckbox%5D
ngClass also accepts methods defined on scope which return a boolean value. So you can do something like this:
<td ng-repeat="day in user.days" ng-class="{ 'guard' : getClass(day) }">
{{day.number}}
</td>
JS
$scope.getClass = function(day){
return $scope.guard.checked && day.func.indexOf('guard') != -1
}
I updated your fiddle:
http://jsfiddle.net/mTJDh/4/
use the ngClass as in the accepted answer:
<td ng-repeat="day in user.days" ng-class="getClasses(day)" day="day">
{{day.number}}
</td>
but this time rewrite the method getClasses to return an array.
the array contains at the end every class you wants for a specific day.
$scope.getClasses = function(day){
var classes = [];
if($scope.spoc && $scope.isSpoc(day)) classes.push("spoc");
if($scope.guard && $scope.isGuard(day)) classes.push("guard");
if($scope.holiday && $scope.isHoliday(day)) classes.push("holiday");
return classes;
}
and if you want a more generic one:
http://jsfiddle.net/mTJDh/5/
define:
var availableClasses = [
"guard",
"spoc",
"holiday"]
and use a loop:
$scope.getClasses = function (day) {
var classes = [];
angular.forEach(availableClasses, function (value) {
if ($scope[value] && day.func.indexOf(value) != -1) classes.push(value);
});
return classes;
}
I would use a directive, it was a bit hard to tell from your example which scope variables your CSS rules rely on (and what exactly the rules are), but hopefully it's enough to get started.
.directive('guardClass', [function() {
return {
restrict: 'A',
scope: {
guard: '=',
user: '='
},
link: function(scope, element, attrs, controller) {
scope.$watch(function() {
//return enough info about scope.guard and scope.user
//to know when one has changed
return ...
}, function() {
var classes = [];
if (...) {
classes.push('guard');
}
if (...) {
classes.push('f2');
}
....
if (...) {
classes.push('fx');
}
element.attr('class', classes.join(' '));
});
}
};
}])
And then in HTML
<td guard-class guard="guard" user="user" />
You feed the directive the two (or more) objects it needs to calculate the CSS classes. The directive sets up a $watch to trigger whenever whatever properties on those objects change. It then finds all CSS classes that needs to be there and puts them on the element using angular element.
This saves you from cluttering up your controller with this logic, and it saves you from having extensive amounts of logic inside your templates.

Categories