How to use ng-if to test if a variable is defined - angularjs

Is there a way to use ng-if to test if a variable is defined, not just if it's truthy?
In the example below (live demo), the HTML displays a shipping cost for the red item only, because item.shipping is both defined and nonzero. I'd like to also display a cost for the blue item (shipping defined but zero), but not for the green item (shipping not defined).
JavaScript:
app.controller('MainCtrl', function($scope) {
$scope.items = [
{
color: 'red',
shipping: 2,
},
{
color: 'blue',
shipping: 0,
},
{
color: 'green',
}
];
});
HTML:
<body ng-controller="MainCtrl">
<ul ng-repeat='item in items'>
<li ng-if='item.color'>The color is {{item.color}}</li>
<li ng-if='item.shipping'>The shipping cost is {{item.shipping}}</li>
</ul>
</body>
I tried doing ng-if='angular.isDefined(item.shipping)', but it didn't work. Nor did ng-if='typeof(item.shipping) !== undefined'.

Try this:
item.shipping!==undefined

I edited your plunker to include ABOS's solution.
<body ng-controller="MainCtrl">
<ul ng-repeat='item in items'>
<li ng-if='item.color'>The color is {{item.color}}</li>
<li ng-if='item.shipping !== undefined'>The shipping cost is {{item.shipping}}</li>
</ul>
</body>
plunkerFork

You can still use angular.isDefined()
You just need to set
$rootScope.angular = angular;
in the "run" phase.
See update plunkr: http://plnkr.co/edit/h4ET5dJt3e12MUAXy1mS?p=preview

Related

AngularJS ng-repeat with radio inputs

I have a list of options as an enum:
var Options = {
Option0: 0,
Option1: 1,
Option2: 2,
Option3: 3,
Option4: 4
};
And a sub-list of available options:
var availabledOptions = [
Options.Option0,
Options.Option2,
Options.Option4
];
I then try to show the list of available options as radio inputs but it doesn't work and I'm wondering why. $scope.selectedOption is not updated.
function main($scope) {
$scope.availabledOptions = availabledOptions;
$scope.selectedOption = Options.Option2;
}
</script>
<div ng-app ng-controller="main">
<ul>
<li ng-repeat="option in availabledOptions">
<input name="options" type="radio" ng-model="selectedOption" ng-value="option">option #{{option}}
</li>
</ul>
selected option: option #{{selectedOption}}
</div>
http://jsfiddle.net/1xgsqL67/
I tried ng-repeat="option in availabledOptions track by $index" and also without the name attribute, but it still doesn't work.
Thanks in advance!
Try the following:
ng-model="$parent.selectedOption"
My understanding is that ng-repeat creates it's own scope, and you have to go up one level.

Can I get the value from the key from ng-repeat x in xx | unique x.key

I have a collection of items that represent a grouping by one property. I want to create a list of items grouped by the value of this property and in each list present the value of this group once and then all the items that belong to the group.
Something like the following
<div ng-repeat="items in itemcollection | unique: 'groupkey'">
<h3>{{items.groupkey}}</h3>
<div ng-repeat="item in items">
<label>{{item.name}}</label>
</div>
</div>
So if I have a itemscollection like the following:
{{ groupkey: 1; name: 'Ada'}, { groupkey: 1; name: 'Beda'}, {groupkey: 2; name: 'Ceda'}}
So after the generation of divs and labels the result should be
<div>
<h3>1</h3>
<div><label>Ada</label></div>
<div><label>Beda</label></div>
</div>
<div>
<h3>2</h3>
<div><label>Ceda</label></div>
</div>
Is it possible to create this or do I need to handle the creating of the elements to better construct the data to make this happen?
This filter does what you want : https://github.com/a8m/angular-filter#groupby
Yes. Its possible by the combination of orderBy and filter function in angularJS. The following code will work :
var app = angular.module("myApp", []);
app.controller("lists", function($scope) {
$scope.list = [{
groupkey: 1,
name: 'Ada'
}, {
groupkey: 1,
name: 'Beda'
}, {
groupkey: 2,
name: 'Ceda'
}];
});
<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.18/angular.js"></script>
</head>
<body>
<div ng-controller="lists">
<div ng-repeat="items in list | orderBy:'groupkey'">
<h3>{{items.groupkey}}</h3>
<label>{{items.name}}</label>
</div>
</div>
</body>
</html>
Hope it works for you :)
Not tested but something like this I guess should work
<div ng-repeat="items in itemcollection | unique: 'groupkey'">
<h3>{{items.groupkey}}</h3>
<div ng-repeat="item in items | filter:{'groupkey': items.groupkey}:true">
<label>{{item.name}}</label>
</div>
</div>
If you make sure the itemcollection is sorted by groupkey you may display the groupkey header only when the groupkey differs from the previous groupkey. Then you achieve to only show the groupkey header once per group. Here is an example:
angular.module('myapp',[]).controller("thectrl", function($scope) {
$scope.itemcollection = [{ groupkey: 1, name: 'Ada'},
{ groupkey: 1, name: 'Beda'},
{groupkey: 2, name: 'Ceda'},
{groupkey: 2, name: 'D'}];
$scope.itemcollection.sort(function(a,b) { return a.groupkey-b.groupkey;});
});
The HTML:
<div ng-app="myapp" ng-controller="thectrl">
<div ng-repeat="item in itemcollection track by $index" >
<h3 ng-if="$index===0 || itemcollection[$index-1].groupkey!==item.groupkey">{{item.groupkey}}</h3>
<label>{{item.name}}</label>
</div>
</div>
And a working fiddle here:
https://jsfiddle.net/vuksyeyh/

Ng-style with condition

How can I apply style on some item in a list that satisfy listed condition:
<div data-ng-repeat="item in items">
<div data-ng-style="{'background' : 'red' : item.selected}> {{item.name}}
<div>
<div>
How is it possible to apply this style on item that is selected.
Try this code,
<div data-ng-repeat="item in items">
<div data-ng-style="item.selected && {'background-color':'red'}">
{{item.name}}
<div>
<div>
I think it would be best to use ng-class for your problem. You then make a new class for the red background, eg:
<style>
.red-background{
background-color: red;
}
</style>
And then use this class according to the condition:
<div data-ng-class="{'red-background':item.selected}">{{item.name}}</div>
(don't forget the single quotes around the class name, they are easily overlooked)
Ironically I just looked this up, the correct thing is to obviously use classes as they have this designed within them.
However, you can do conditionals thanks to the JavaScript ability to return the last value with &&
<div ng-style="conditional && { 'background' : 'red' } || !conditional && { 'background' : 'green' }"> show me the background </div>
Please refer below
function simpleController($scope) {
$scope.items = [
{
selected: false,
name: 'first'
}
,
{
selected: true,
name: 'second'
}
];
}
.red
{
background:red}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<html ng-app>
<body ng-controller="simpleController">
<div data-ng-repeat="item in items">
<div ng-class="{'red' : item.selected}"> {{item.name}}
<div>
<div>
</body>
</html>
ng-style="{'background': (desktop) ? '#ffffff' : ''}"
Explanation:
{CssProperty: Condition ? if condition is True : If condition is False}
CssProperty : meaning background, color, font-size etc..
Condition: just like a If statment..
after the : define the property value for the true and false Condition .for the the CssProperty.
here we have no value if condition is false.
any true or false value should be the Proper value for the CSSProperty.
So for background it's #ffffff or White.
You can use this method described further here. (example below)
angular.module('app', []);
function myCtrl($scope){
$scope.items = [
{ name: 'a', selected: 'false' },
{ name: 'b', selected: 'true' }
];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.min.js"></script>
<html ng-app>
<body ng-controller="myCtrl">
<div ng-repeat="item in items">
<div ng-style="{color: {true:'red'}[item.selected]}">{{item.name}}</div>
</div>
</body>
</html>
On Angular >9 the syntax is following:
[ngStyle]="{'background-color': item.selected ? '#f00' : ''}"
Make sure you do not add a semicolon (;) at the end of the style expression as this breaks the functionality

Hide and Display Subsections

I have menu with sections and subsections, like this:
Section 1
Sub 1.1
Sub 1.2
Section 2
Sub 2.1
Sub 2.2
I want to hide subsections and show one of them by clicking on section (click on Section 2):
Section 1
Section 2
Sub 2.1
Sub 2.2
Here is my code and JSFiddle:
<div ng-controller="MyCtrl">
<div ng-repeat="(meta, counts) in info">
{{ meta }}
<ul class="subsection">
<li ng-repeat="(group, cnt) in counts">
{{ group }}
</li>
</ul>
</div>
</div>
Controller:
var myApp = angular.module('myApp',[]);
//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});
function MyCtrl($scope) {
$scope.name = 'Superhero';
$scope.info = { "one": { "a": 1, "b": 2 },
"two" : { "c": 3, "d": 4 }};
$scope.display = function(meta) {
// ????
};
}
CSS:
ul.subsection {
display: none;
}
How can I fix this code to show one of the subsection by click on the section ?
Update: I fixed the link on JSFiddle
Since ng-repeat creates its own scope, you can simply toggle a variable within the loop, and use ng-show on that variable:
<div ng-repeat="(meta, counts) in info">
{{ meta }}
<ul class="subsection" ng-show="display">
<li ng-repeat="(group, cnt) in counts">
{{ group }}
</li>
</ul>
</div>
Edit: If you can only show one function at a time, then you can do what you were trying to do in your original code with a function:
<div ng-repeat="(meta, counts) in info">
{{ meta }}
<ul class="subsection" ng-show="sectionIndex == $index>
<li ng-repeat="(group, cnt) in counts">
{{ group }}
</li>
</ul>
</div>
$scope.display = function(index) {
$scope.sectionIndex = index;
}
You can simply do something like this:
<div ng-repeat="(meta, counts) in info">
{{meta}}
<ul class="subsection" ng-show="$parent.display == meta">
<li ng-repeat="(group, cnt) in counts">
{{ group }}
</li>
</ul>
</div>
Note, that you can refer $parent scope to avoid local scope display property.
In this case you don't need CSS rule. Bonus point is that you can set in controller $scope.display = 'two' and the second item will expand.
However cleaner way would be using a controller function as demonstrated by #tymeJV, this is the best approach.
Demo: http://plnkr.co/edit/zXeWjXLGHMv0BZZRZtud?p=preview

Angular js - basic toggle of additional object values

I would like to output a basic list of names, and below the list display some text. This text should only be displayed once you've clicked on an item and it should toggle when selecting another.
What I've got so far
<div ng-app>
<div ng-controller="contacts">
<ul>
<li ng-repeat="person in people | orderBy:'name'">
{{person.name}}
<span>{{person.age}}</span>
</li>
</ul>
<div class="desc">
<!-- I would like to output the descriptions here -->
</div>
</div>
</div>
<script>
var contacts = function($scope) {
$scope.people = [
{name:"paul", age:30, desc:"this is a description"},
{name:"jax", age:33, desc:"this is another description right here"},
{name:"yoda", age:33, desc:"final description goes here"},
{name:"steve", age:53, desc:"jsut kidding - one more."}
];
};
</script>
I'm pretty sure I should be using ng-click and possible the model etc but this simple task is doing my head in. I'm able to do a basic show and hide below the link (though not sure about toggling them).
Super new to angular, please excuse me if this seems like a retarded request.
Looking for a super clean, quick and easy way to do this. Any input would be great.
There are not silly questions; at some point we were all newbies :)
Controller
var contacts = function($scope) {
$scope.people = [
{name:"paul", age:30, desc:"this is a description"},
{name:"jax", age:33, desc:"this is another description right here"},
{name:"yoda", age:33, desc:"final description goes here"},
{name:"steve", age:53, desc:"jsut kidding - one more."}
];
$scope.selectedPersonDescription = null;
$scope.selectPerson = function(person) {
$scope.selectedPersonDescription = person.desc;
}
};
View
<div ng-app>
<div ng-controller="contacts">
<ul>
<li ng-repeat="person in people | orderBy:'name'", ng-click="selectPerson(person)">
{{person.name}}
<span>{{person.age}}</span>
</li>
</ul>
<div class="desc">
{{ selectedPersonDescription }}
</div>
</div>
</div>

Resources