convert this multiple condition into ng-class conditional - angularjs

Hello there I need help in converting this 'if-else' with 'or' condition into conditon that can be used in ng-class.
This here is my ng-class with condition, but it's not working correctly.
<span ng-class="{'green': work > toWork,
'red': work < toWork,
'black': work == toWork || overall == '-'}">
{{overall = showMonthly(work = (workers | getMonthValue: dts.value),
toWork = getMonthlyToWork(member.id, dts.value))}}
</span>
this is the condition I'd like to apply:
if (work > toWork) {
return "green";
}else if (work < toWork) {
return "red";
}else if (work == toWork || overall == "-") {
return "black";
}

You don't need ng-class for that, you just need to put the logic inside a method in your $scope, like below
$scope.getClass = function(work, toWork, overall){
if (work == toWork || overall == "-"){
return "black";
}else if (work < toWork) {
return "red";
}else if(work > toWork) {
return "green";
}
}
and in your view, call it like this
<span class="{{getClass(work, toWork, overall)}}"></span>

<span ng-class="{'green': work > toWork,
'red': work < toWork,
'black': (work == toWork || overall == '-')}">
...
</span>
Check this. (You have got a spell missing in your conditional statement)
Happy coding!

Related

How to write Nested if else in react js

I am trying to implement nested if else in react compound slider.
I am able to write if else using ternary operator and that is working fine
<div className={source.value >.3 ? 'greater': 'lesser'}>
<Track
key={id}
source={source}
target={target}
getTrackProps={getTrackProps}
/>
</div>
so here i am able to check only condition whether it is greater than .3 or less than but am trying to implement
if(source.value <.3)
{
return classNameFirst
}
else if (source.value >.3 && source.value <.7){
return classnameSecond
}
else if (source.value >.7 && source.value <.9){
return classnamethird
}
else if (source.value >.9 && source.value <1.2){
return classnameFourth
}
else{
return classnamefive
}
how can i implement this thing into my jsx code.
Thanks in advance.
Define a function in your helper or utility file. You can also define the function in your class itself, but generally it is a good idea to use helper file for this.
So you can have a function getTrackClass which will accept source.value as the parameter and return you the appropriate class.
getTrackClass = value => {
if (value < 0.3) {
return classNameFirst;
} else if (value > 0.3 && value < 0.7) {
return classnameSecond;
} else if (value > 0.7 && value < 0.9) {
return classnamethird;
} else if (value > 0.9 && value < 1.2) {
return classnameFourth;
} else {
return classnamefive;
}
};
After this you can use this function to get the class for your Track component.
<div className={this.getTrackClass(source.value)}>
<Track
key={id}
source={source}
target={target}
getTrackProps={getTrackProps}
/>
</div>
Use the package named classNames in your application.
https://www.npmjs.com/package/classnames
This will give you the flexibility of using multiple classes, but will also allow you to use classes conditionally in a more readable way.
Is this what you're trying to accomplish?
return(
source.value < .3 ?
classNameFirst
: source.value < .7 ?
classNameSecond
: source.value < .9 ?
classNameThird
: source.value < 1.2 ?
classNameFourth
: classNameFive
);

Angular 6 *ngFor display different styles for first, odd, even and last

I am learning Angular 6 and just trying to put togheter some of the stuff I have learned and I am currently running into an issue that I cannot find an answer to. I am trying to change the style of a LI using *ngFor depending if the index is First, Last, Odd or Even. So far everything works but I can't figure out how to do it for the Last because everything I add a new object to my list, it is obviously the last so it render the color for the last.
I understand how to do it but the real problem is that I am adding stuff dynamicly to my list from a form and I'm not sure how to evaluate the Last so that the others become to right color.
Keep in mind that I am still a newb and it might look messy and I also understand that some client-side validations I am doing are probably not optimal or required since HTMl5 but I made it to learn.
Here is my code for my component HTML
>
<h1>List of courses :</h1><br>
<div *ngIf="courses.length > 0; then coursesList else noCourses"></div>
<ng-template #coursesList>
<h2>List of Courses :</h2>
<ul *ngFor="let course of courses; index as i;">
<li [ngStyle]="{'background-color':getColor(i)}" style="color: white;">
<strong>Index : </strong>{{i}} <strong>ID : </strong>{{course.id}} <strong>Name</strong> : {{course.name}}
<button (click)="onRemove(i)">Remove</button>
<button (click)="onModify(i)">Modify</button>
</li>
</ul>
</ng-template>
<ng-template #noCourses>
<h5>There are no courses in this list. Use the form bellow to add some.</h5>
</ng-template>
<div (keyup.enter)="onAdd()">
<span>ID : <input type="number" (keypress)="checkNumber($event)" [(ngModel)]="fields.id" placeholder="Enter an ID"></span>
<span>Name : <input type="text" [(ngModel)]="fields.name" placeholder="Enter a NAME"></span>
<button (click)="onAdd()">Add</button>
<button (click)="onClear()">Clear</button>
</div>
<div *ngIf="isNotNumber" style="background-color: red; color:black"><strong>ID can only be numbers !</strong></div>
<div *ngIf="noValues" style="background-color: red; color:black"><strong>Please fill all fields !</strong></div>
<div *ngIf="noModifyValues" style="background-color: red; color:black"><strong>To modify enter all informations!</strong></div>
Code for .TS
>
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
noValues: boolean;
noModifyValues: boolean;
isNotNumber: boolean;
fields: Courses = {id: null, name: null};
courses: Array<Courses> = [];
viewMode: string = null;
checkNumber($event) {
if ($event.keyCode != 13) {
isFinite($event.key) ? this.isNotNumber = false : this.isNotNumber = true;
}
}
onAdd() {
if (!this.fields.id || !this.fields.name) {
this.noValues = true;
} else {
this.courses.push({id: this.fields.id, name: this.fields.name});
this.fields.id = null;
this.fields.name = null;
this.noValues = false;
}
}
onRemove(i) {
this.courses.splice(i, 1);
}
onClear() {
this.courses = [];
this.fields.id = null;
this.fields.name = null;
this.noValues = false;
}
onModify(i) {
if (!this.fields.id || !this.fields.name) {
this.noModifyValues = true;
} else {
this.courses[i].name = this.fields.name;
this.courses[i].id = this.fields.id;
this.noModifyValues = false;
}
}
getColor(i){
if (i % 2 === 0 && i != 0){i = 'odd';}
switch (i) {
case i = 0 : return 'orange';
case i = 'odd' : return 'blue';
}
return 'red';
}
}
interface Courses {
id: number;
name: string;
}
Image of the code in action for better understanding.
If you only want change the background-color you can use [style.background-color] and you can use ternary operator in the .html
<ul *ngFor="let course of courses; let index=i;
let odd=odd;
let last=last;
let first=first">
<li [style.backgound-color]="first?'orange':last?'purple':odd?'blue':'red'">
...
</li>
</ul>
Try something like this
getColor(i){
if (i % 2 === 0 && i != 0){i = 'odd';}
if (this.courses && (this.courses.length - 1 === i)) {i = 'last'}
switch (i) {
case i = 0 : return 'orange';
case i = 'odd' : return 'blue';
}
return 'red';
}
Hope it works - Happy coding !!
Thanks Rahul. The part I was missing is evaluating if there is something in courses. However, I had to had a few more lines to Odd and Last as follow :
getColor(i){
if (this.courses && i != 0 && (this.courses.length - 1 === i)) {i = 'last'}
if (i % 2 === 0 && i != 0 && i != 'last'){i = 'odd';}
switch (i) {
case i = 0 : return 'orange';
case i = 'odd' : return 'blue';
case i = 'last' : return 'purple';
}
return 'red';
}
Quick question. It seems like a whole lot of IF and && and checking specific things. Is that the way to do it properly?
You could use if else ladder instead of mixing up if else and switch and assignments like given below
getColor(i)
{
if(this.courses)
{
if(i==0)
return "orange";
else if(i==this.courses.length-1)
return "purple";
else if (i%2==0)
return "red";
else
return "blue";
}
}

HSL to RGB Auto-Color with AngularJS

I have a few different working pieces here, but I'm struggling with how to to bring them all together. I currently have a list of elements sorted by their health status (value given between 0 and 100).
For each element, I would like to color the background based on its health status. So, status = 0 would mean I have a fill color of red; status=50 yellow; status=100 green.
In something like d3, I would accomplish that with the following code (which, is a great trick, by the way):
/*normalize input between 0 and 100 to hsl color scale -- so 0=0 and 100 = 120, where hue=0 is red and hue=120 is green */
var hueScale = d3.scale.linear().domain([0,100]).range([0,120]);
.style("fill", function(d){
var hslColor = 'hsl(' + hueScale(d.status)) + ', ' + (100) + '%, ' + (50) + '%, ' + (1) + ')';
return d3.rgb(hslColor).toString().toUpperCase(); })
but here, I'm dealing with a normal list, not a d3 graphic.
I've also made use of ng-class in the past to specify a dynamic color:
$scope.getClass = function(status) {
if (status == (100)) {
return "good-feed";
} else {
return "bad-feed";
}
};
and
ng-class="[getClass(item.status)]"
I need to combine both of these techniques. I think using ng-class in a similar way to what I have is what I need to do, but I'm not sure how to get the color change function to work without being needlessly complicated.
Any thoughts?
EDIT
Both my current code snippets above work, but the issue is I want to be able to iterate through all status values between 0 and 100, not just handle an either-or situation.
For example:
Item 1 with status of 23 (approx. color: orange)
Item 2 with status of 45 (approx. color: yellow-orange)
Item 3 with status of 67 (approx. color: yellow-green)
Item 4 with status of 99 (approx. color: green)
And so on. Now, I COULD write my color function for ng-class to look something like this (update: this doesn't work) :
$scope.getClass = function(status) {
if (status <= (10)) {
return "dark-red";
} else if (10 < status <= 20){
return "red-orange";
// continue pattern for all intervals until 100 is reached
} else {
return "undefined-grey";
}
};
But manually going through like that for each value seems clunky. Is there any way to make this smoother (akin to the d3 solution)?
just use this
ng-class="{'good-feed' : item.status == 100,'bad-feed' : item.status != 100 }"
Alright, so this answer is the best I've got for now. It still requires some work to get this to do exactly what I would like, but it's on the right track:
I ended up usuing jquery to break apart colors based on value (like I was attempting to do with my ng-class function)
See my JSFiddle for details.
$(document).ready(function () {
var cell = $('ul.list-view li');
cell.each(function() {
var cell_value = parseFloat($(this).html().slice(0, -1));
// Positief
if ((cell_value >= 0) && (cell_value <= 0.3)) {
$(this).css({'background-color' : '#7FFF95'});
}
else if ((cell_value >= 0.31) && (cell_value <= 0.5)) {
$(this).css({'background-color' : '#66FF7C'});
}
else if ((cell_value >= 0.51) && (cell_value <= 0.7)) {
$(this).css({'background-color' : '#4DFF63'});
}
else if ((cell_value >= 0.71) && (cell_value <= 1)) {
$(this).css({'background-color' : '#33F749'});
}
else if ((cell_value >= 1.01) && (cell_value <= 1.5)) {
$(this).css({'background-color' : '#1ADE30'});
}
else if (cell_value >= 1.5) {
$(this).css({'background-color' : '#00CC66'});
}
// Negatief
else if ((cell_value >= -0.01) && (cell_value <= -0.2)) {
$(this).css({'background-color' : '#F6ADAC'});
}
else if ((cell_value >= -0.31) && (cell_value <= -0.5)) {
$(this).css({'background-color' : '#F18483'});
}
else if ((cell_value >= 0.51) && (cell_value <= -0.7)) {
$(this).css({'background-color' : '#EF706E'});
}
else if ((cell_value >= -0.71) && (cell_value <= -1)) {
$(this).css({'background-color' : '#ED5B5A'});
}
else if ((cell_value >= -1.01) && (cell_value <= -1.5)) {
$(this).css({'background-color' : '#EB4745'});
}
else if (cell_value >= -1.5) {
$(this).css({'background-color' : '#E93331'});
}
});

Why is my custom filter predicate filter not working

I have an use case wherein I have to filter an array based on selection from two dropdowns. Both the selections are from md-select (from Angular material) hence both the selection will be an array. Any record from the original array that matches any of the record from the selection arrays should be returned by filter.
I have returned the following logic, but I can't figure out why my data do not get filtered.
$scope.filterTasks = function (t, i, array) {
if ($scope.filter.tradeDir.length === 0 && $scope.filter.cluster.length === 0) {
return true;
}
else if ($scope.filter.tradeDir.length !== 0 && $scope.filter.cluster.length === 0) {
$scope.filter.tradeDir.forEach(function (td) {
if ((t.Trade.code === td.trade.code) && (t.Direction.code === td.direction.code)) {
return true;
}
});
} else if ($scope.filter.cluster.length !== 0 && $scope.filter.tradeDir.length !== 0) {
$scope.filter.tradeDir.forEach(function (td) {
if ((t.Trade.code === td.trade.code) && (t.Direction.code === td.direction.code)) {
$scope.filter.cluster.forEach(function(c) {
if (t.Cluster.code === c.code) {
return true;
}
});
}
});
}
else {
return false;
}
}
Surprisingly, when I debug, I can see the control going till the return statement for each matched record. Still, the data does not get filtered. I am puzzled why?
Below is my html code for md-selects:
<div class="filter layout layout-sm-column task_top_filters">
<md-input-container ng-class="{'md-input-has-value': filter.tradeDir}"
class="flex-sm-100 md_container_fr_task">
<label>Trade/Direction</label>
<md-select multiple ng-model="filter.tradeDir"
md-on-close="closeTradeFilter(filter.tradeDir)"
ng-model-options="{trackBy: '$value.name'}">
<md-option ng-value="t" ng-repeat="t in tradeDirArray track by $index">
{{t.name}}
</md-option>
</md-select>
</md-input-container>
<md-input-container ng-disabled="filter.tradeDir.length === 0"
ng-class="{'md-input-has-value': filter.cluster}"
class="flex-sm-100 md_container_fr_task">
<label>Cluster</label>
<md-select multiple ng-model="filter.cluster"
ng-model-options="{trackBy: '$value.code'}">
<md-option ng-value="t" ng-repeat="t in filterClusters track by $index">
{{t.code}}
</md-option>
</md-select>
</md-input-container>
</div>
and here is how I am calling it:
<li ng-repeat="t in dataList| filter: filterTasks track by t.id" class="li_row">
Is there something wrong with the filter? Any help will be appreciated.
Well, the issue with above code was that I was returning true for forEach function, which instead should be returned from the original filterTasks function.
Below code works fine:
$scope.filterTasks = function (t, i, array) {
if ($scope.filter.tradeDir.length === 0 && $scope.filter.cluster.length === 0) {
return true;
} else if ($scope.filter.tradeDir.length !== 0 && $scope.filter.cluster.length === 0) {
$scope.filter.tradeDir.forEach(function (td) {
if ((t.Trade.code === td.trade.code) && (t.Direction.code === td.direction.code)) {
x = true;
}
});
return x;
} else if ($scope.filter.cluster.length !== 0 && $scope.filter.tradeDir.length !== 0) {
$scope.filter.tradeDir.forEach(function (td) {
if ((t.Trade.code === td.trade.code) && (t.Direction.code === td.direction.code)) {
$scope.filter.cluster.forEach(function (c) {
if (t.Cluster.code === c.code) {
x = true;
}
});
return x;
}
});
return x;
} else {
return false;
}
}

How to show element once in ng-repeat

I need to loop through a list order by price and as soon as the price is not there then I show a message with unavailable but I don't want to show it for each empty element. I'm using angular 1.2
<div ng-repeat="item in list | orderBy: 'cost'">
<div ng-if="cost == 0 and not already shown">Sorry the following are unavailable</div>
<div>...my item here...</div>
<div>
You can conditionally display two spans - one if it's 0 (your 'not available' message) and another for anything else.
<ul>
<li ng-repeat="d in newData track by $index">
<span ng-show="d > 0">{{d}}</span>
<span ng-show="d === 0">Not Available</span>
</li>
</ul>
The data can be passed through a function to pull all the 0 after the first one:
$scope.data = [1,2,3,0,1,0,0,1,0,2]
$scope.pullDupes = function(array) {
var newArray = [];
var zero;
for(var i = 0; i < array.length; i++) {
if (array[i] !== 0) {
newArray.push(array[i])
}
if (array[i] === 0 && !zero) {
zero = true;
newArray.push(array[i])
}
}
return newArray;
}
$scope.newData = $scope.pullDupes($scope.data);
Plunker
You can show only the first message see here :
<div ng-repeat="item in list | orderBy: 'cost'">
<div style="color:red" ng-show="item.cost == 0 && $first">Message Goes Here</div>
<hr>
<div>{{item.name}} - Price : {{item.cost}}</div>
</div>
and here is a plunker for it :
http://plnkr.co/edit/RwZPZp9rFIChWxqF71O7?p=preview
also the ng-if you are using it wrong you need to do it like this item.cost for the next time
Cheers !
Here is the best way I could find to get it done.
Markup
<div class="sold-out-message" ng-if="displaySoldOutMessage(item)">Sorry, sold out</div>
Controller
$scope.firstSoldOutItemId = false;
$scope.displaySoldOutMessage = function(item) {
if ( item.cost ) return false;
$scope.firstSoldOutItemId = $scope.firstSoldOutItemId || item.id;
return item.id == $scope.firstSoldOutItemId;
};
You can try to use $scope.$whatch with a boolean variable like this:
<div ng-model="actualItem" ng-repeat="item in list | orderBy: 'cost'">
<div ng-if="cost == 0 && oneMessage == true">Sorry the following are unavailable</div>
<div>...my item here...</div>
<div>
</div>
And in your controller you look at actualItem :
$scope.oneMessage = false;
var cpt = 0; // if 1 so you stop to send message
$scope.$watch('actualItem',function(value){
if(value.cost == 0 && $scope.oneMessage == false && cpt < 1)
// i don't know what is your cost but value is your actual item
{
$scope.oneMessage = true;
cpt++;
}
else if($scope.oneMessage == true)
{
$scope.oneMessage == false;
}
});
I am not sure about this but you can try it. It's certainly not the best way.

Resources