checking multiple condition in ng-if - angularjs

I need to check 4 conditions in ng-if which are boolean conditions. If any of them is true, I need to display some div.
Is there any simple and better way to do it please?
<div ng-if="ctrl.survivor || ctrl.doctor || ctrl.patient || ctrl.beneficiary">
<div ng-bind-html=" {{ myContent }}">
</div>
</div>

In general, complex logic inside of angular expressions is a code smell:
hard to read
hard to debug
hard to test
In general, I try to avoid boolean logic or anything else that indicates complexity in angular expressions that I write or code review. Instead, I recommend that you extract the logic into a controller method and call the controller method directly. This allows you to also write a nice unit test for it. The final code that I would recommend would look something like this:
<div ng-if="ctrl.isApplicable()">
<div ng-bind-html=" {{ myContent }}"></div>
</div>
In the controller:
class Ctrl {
...
isApplicable() {
return survivor || ctrl.doctor || ctrl.patient || ctrl.beneficiary;
}
...
}

Related

AngularJS ng-class the same class with different conditions

I have a option in the back-end to let user change icon in default and in hover state. This is the code
ng-class="{'{{getAnswerButtonHoverIcon()}}':hovering, '{{getAnswerButtonIcon()}}' : !hovering}
But the problem is, when the user selected the same icon for default state and hover state, like for example they have selected "fa-circle-o" the output of the HTML will be
ng-class="{'fa-circle-o':hovering, 'fa-circle-o' : !hovering}"
and it doesn't work anymore. When I try to test it out, it removes the "fa-cricle-o" class on hover. Any idea why is it happening? And if you can suggest better solution, it will be greatly appreciated. Thanks!
I mentioned in a comment that I would probably have a single function but I think I misunderstood your question at first. Building on Joshua's approach here is something that could work for you: if the two functions return the same value then it still works.
I feel that this is not the nicest solution since it is generating a string into a class, but the same can be changed to ng-class and {hovering ? sg() : sgelse()} as value. I hope it shows you a way to handle these kind of interactions.
Let me know if it does/doesn't work so that we could further help you.
var app = angular.module("mainModule",[]);
app.controller("mainCtrl", function($scope){
$scope.icon = {};
$scope.icon.hovering = false;
$scope.getAnswerButtonHoverIcon = function(){
return 'bluebg';
};
$scope.getAnswerButtonIcon = function(){
return 'redbg';
};
});
.bluebg{background-color:blue}
.redbg{background-color:red}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="mainModule">
<div ng-controller="mainCtrl">
<div class="{{ icon.hovering ? getAnswerButtonHoverIcon() : getAnswerButtonIcon() }}"
ng-mouseenter="icon.hovering = true" ng-mouseleave="icon.hovering = false">
<p>I have different backgrounds</p>
</div>
</div>
</div>
You can also use the ng-class like this, which will just apply the class the function outputs:
ng-class="(hovering ? '{{getAnswerButtonHoverIcon()}}': '{{getAnswerButtonIcon()}}')

ngClass Directive: Can I use multiple expressions to add multiple classes?

Here is an example of what I want to achieve
data-ng-class="{ 'tooltip_show' : showTooltip , 'tooltip__' + brand.settings.name }"
but it doesn't work.
Use the array form for ng-class:
<div ng-class="[showTooltip ? 'tooltip_show' : '',
'tooltip__' + brand.settings.name]">
<div>
OR compute the class in JavaScript:
<div ng-class="computeClass(tooltip_show, brand.setting.name)">
</div>
$scope.computeClass(show, name) {
var obj = {};
obj.showTooltip = show;
obj['tooltip_'+name] = true;
return obj;
};
The later approach is more easily debugged and better for complex computation.
See also,
AngularJS ng-class Directive Reference - Known Issues
AngularJS Developer Guide - Why mixing interpolation and expressions is bad practice
It looks like you haven't set a value for the second item. Did you mean something like
{ 'tooltip_show' : showTooltip , 'tooltip__' + brand.settings.name : tooltipText }
or
{ 'tooltip_show' : showTooltip , 'tooltip__' : brand.settings.name }
?
http://jsbin.com/genaqapefe/edit?html,js,output
data-ng-class="{ 'tooltip_show': showToolTip, {{ 'tooltip_' + brand.settings.name }}: true }"
This is working for me in this bin. I couldn't get it to evaluate without the curly braces, although not sure if that's the best practice.

How to do a logic operation in Angular Template

All:
I wonder how can I set a OR operator on a HTML string in Angualar Template, something like:
<div>{{value || <h6>No Header for now.</h6>}}</div>
The logic is if value is a string but not undefined, we show the value text, otherwise we show a error "No Header for Now" wrapped up by <h6>.
I do not know why this expression can not be correctly interpreted?
Thanks
This can be solved with ng-if:
<div ng-if="value">value</div>
<div ng-if="!value"><h6>No Header for now.</h6></div>
You can add specific attributes (e.g. class) and/or directives (e.g. ng-click) on each <div>.
The problem with using a single element is that you have to repeat your condition several times:
<div ng-class="{ value: 'class1', !value: 'class2' }"
ng-click="value ? action1() : action2()"
ng-bind-html="value || html">
</div>
You have to put a string, not an expression: <h6>No Header for now.</h6> is an invalid js expression. '<h6>No Header for now.</h6>' is a string and can be displayed in the {{ }}.
<div>{{value || '<h6>No Header for now.</h6>' }}</div>
or
<div>{{value != null ? value : '<h6>No Header for now.</h6>' }}</div>
I'm convinced the 2nd works.
EDIT:
If you want to add html code in the {{ }}, it is another problem. See AngularJS : Insert HTML into view, the filter 'sanitize' in 2nd answer should help you ( call {{ '<h1>test</h1>' | sanitize }} and it should work.
EDIT 2:
In a js file:
angular.module('yourapp')
.filter("sanitize", ['$sce', function($sce) {
return function(htmlCode){
return $sce.trustAsHtml(htmlCode);
}
}]);
In view:
<div>{{value || '<h6>No Header for now.</h6>' | sanitize }}</div>
In dont know if you need 'ngResource' to use $sce, if it doesn't work, you will have to install angular-resource :/

AngularJs Divs won't toggle using <select>

I have this in my view:
<div>
<select ng-model="chartType" ng-change="AnalyticsChartTypeChanged(chartType)"
ng-init="chartType='Data grid'">
<option value="Data grid">Data grid</option>
<option value="Histogram">Histogram</option>
</select>
{{chartType}}
<br>showAnalyticsDataGrid == {{showAnalyticsDataGrid}}
<br>showAnalyticsHistogram == {{showAnalyticsHistogram}}
<div ng-show="{{showAnalyticsDataGrid}}">
<p>Data grid goes here</p>
</div>
<div ng-show="{{showAnalyticsHistogram}}">
<p>Histogram goes here</p>
</div>
and the ng-chnage funtion is
$scope.AnalyticsChartTypeChanged = function(chartType)
{
switch (chartType)
{
case 'Data grid': $scope.showAnalyticsDataGrid = true;
$scope.showAnalyticsHistogram = false;
console.log('Show analytics data grid');
break;
case 'Histogram': $scope.showAnalyticsDataGrid = false;
$scope.showAnalyticsHistogram = true;
console.log('Show analytics histogram');
break;
}
}
When I alernately select each of the options, the debug text updates correcrly:
Data grid
showAnalyticsDataGrid == true
showAnalyticsHistogram == false
and
Histogram
showAnalyticsDataGrid == false
showAnalyticsHistogram == true
BUT, it constantly shows the Data grid DIV and never the Historgram DIV.
Obviouly I am making an extermely simple mistake, but I just can't see it :-(
With ng-show, you give it an expression and it evaluates it for you. What you're trying to do here is evaluating the expression by using the double curly braces{{}}, which doesn't make sense. If you simply remove those double curly braces and use the ng-show like this:
ng-show="showAnalyticsDataGrid"
it will work just fine.
Also, remember that those 2 variables aren't being initialized so when the view loads there will be no div shown by default, but you can fix that with an ng-init.
Here's a fiddle. http://jsfiddle.net/5DMjt/5248/
You don't use {{}} interpolation in ng-show. Like many other directives it directly evaluates expressions
Change
<div ng-show="{{showAnalyticsHistogram}}">
To
<div ng-show="showAnalyticsHistogram">

ngClass string binding expression with class map

Is it possible to use ngClass with an expression AND a class map? I want to conditionally add a class based on the existence of a variable as well as use that variable in the expression that creates the class.
For instance, if isActive() is true and getStatus() returns "valid" I want the class list to be "element element--active element--valid". If getStatus() returns undefined I want the class list to be "element element--active".
<div
class="element"
ng-class="{
'element--active': ctrl.isActive(),
'element--{{ ctrl.getStatus() }}': ctrl.getStatus()
}"></div>
Doesn't seem to work.
<div
class="element element--{{ctrl.getStatus()}}"
ng-class="{
'element--active': ctrl.isActive()
}"></div>
Works but then there's an extra hanging "element--" if getStatus() returns undefined.
Do I have to add a method in my controller to handle the class generation?
i'd suggest to make just one function call to get the classes. It will make it cleaner and have the class logic in one place.
In your controller:
this.getElementStatus = function(){
var rules = {active:this.isActive()}; //Prefix with element-- {element--active:}
rules[this.getStatus()] = true; //Prefix with element--, rules['element--' + this.getStatus()] = true
return rules;
}
and your view would just be:
<div
class="element"
ng-class="ctrl.getElementStatus()"></div>
It seems like your element-- is redundant with the rule instead make use of cascadeability(CSS) property. and define rules as :
Example:
.element.active{ /*....*/ }
.element.success {/*...*/}
.element.error{/*...*/}
This will help in maintenance, gets more verbose and get to the natural way of adding css rules and could remove these kind of complexities from the view.
You could as well do:
<div class="element"
ng-class="{'active': ctrl.isActive(), '{{ctrl.getStatus()}}':true}"
or :
<div class="element"
ng-class="[ctrl.isActive() ? 'active' : '', ctrl.getStatus()]"
If you don't mind getting a true added as a rule(should not affect anything anyways) then,
<div class="element"
ng-class="[!ctrl.isActive() || 'element--active' , 'element--' + ctrl.getStatus()]">
You can use class and ng-class map on the same element. But since your class name is dynamic you will have to something like this.
<div
ng-class="'element '
+ (ctrl.isActive() ? ' element--active' : '')
+ (ctrl.getStatus() ? ' element--' + ctrl.getStatus() : '')"></div>

Resources