How to escape an ng-Repeat loop? - angularjs

I have the following ng-repeat loops that unpack JSON data into an Accordion:
<accordion close-others="oneAtATime">
<accordion-group ng-repeat="service in userPF.custom.services">
<accordion-heading><input type="checkbox" name="status" disabled>On <input type="checkbox" name="status" disabled checked>Off {{service.name}}</accordion-heading>
Related Items:<br>
<div class="secondary" ng-repeat="fields in userPF.custom.fields">
<span ng-show="checkForMatch(service.name, fields.services)">
<span ng-repeat="value in fields.values">
{{value.name}}<br>
</span>
</span>
</div>
</accordion-group>
</accordion>
The first trip through the loop {{service.name}} will always return data but the second value {{value.name}} might not. If it doesn't I don't want the div or span to render, just the heading. I've tried some variations on ng-if but haven't come close to being able to tell if I'm getting data back or not.

Refer this Link.
AS this code shows and its working fine you can have ng-show inside ng-repeat.
<div ng-app ng-controller="RepeatTestCtrl">
<ul ng-repeat="item in items">
<li ng-show="item.id.length == 0">{{item.name}} is even</li>
<li ng-show="item.id % 2 == 1">{{item.name}} is odd</li>
</ul>
</div>
function RepeatTestCtrl($scope) {
$scope.items = [
{ id: 1, name: 'test 1' },
{ id: 2, name: 'test 2' },
{ id: 3, name: 'test 3' },
{ id: 4, name: 'test 4' }
];
}
http://jsfiddle.net/b004t06z/41/

Related

How to make expand and collapse manually child wise in angularjs

I have an accordion expand is working fine but collapse is not working,it should work like accordion,for ex when I click 'title 2' its content should expand and 'title 1' content should collapse.below is my code,I am new to angularjs.Anyone can help me.If its in jquery also fine.
HTML
<link rel='stylesheet prefetch' href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/css/bootstrap.css'>
<body ng-app="app">
<h1>Dynamic accordion: nested lists with html markup</h1>
<div ng-controller="AccordionDemoCtrl">
<div>
<div ng-repeat="group in groups">
<div class="parents" ng-click="item=1"><i class="glyphicon-plus"></i> {{ group.title }}
</div>
{{ group.content }}
<ul class="childs" ng-show="item==1">
<li ng-repeat="item in group.list">
<span ng-bind-html="item"></span>
</li>
</ul>
</div>
</div>
</div>
</body>
<script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.1/angular.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/angular-filter/0.5.4/angular-filter.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.1/angular-sanitize.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.5.0/ui-bootstrap-tpls.js'></script>
<script src="js/index.js"></script>
index.js
angular.module('app', ['ui.bootstrap','ngSanitize','angular.filter']);
angular.module('app').controller('AccordionDemoCtrl', function ($scope) {
$scope.oneAtATime = true;
$scope.groups = [
{
title: 'title 1',
isOpen: true,
list: ['<i>item1a</i> blah blah',
'item2a',
'item3a']
},
{
title: 'title 2',
list: ['item1b',
'<b>item2b </b> blah ',
'item3b']
},
{
title: 'title 3',
},
{
title: 'title 4',
},
{
title: 'title 5',
}
];
});
I suggest you those functions :
$scope.open = function (index) {
$scope.groups[index].isOpen = !$scope.groups[index].isOpen;
$scope.closeOthers(index);
}
$scope.closeOthers = function (index) {
for(var i = 0; i < $scope.groups.length; i++) {
if (i !== index)
$scope.groups[i].isOpen = false;
}
}
open is fired when clicking on a parent, closeOthers is called in open. I init a visible boolean to parents. Each time user clicks on a parent, it set visible to true, and others to false.
<div ng-controller="AccordionDemoCtrl">
<div>
<div ng-repeat="group in groups track by $index">
<div class="parents" ng-click="open($index)"><i ng-class="{'glyphicon-minus': group.isOpen, 'glyphicon-plus': !group.isOpen}"></i> {{ group.title }}
</div>
{{ group.content }}
<ul class="childs" ng-show="group.isOpen">
<li ng-repeat="item in group.list">
<span ng-bind-html="item"></span>
</li>
</ul>
</div>
</div>
</div>
Working demo

AngularJS filter nested ng-repeat based on repeated object properties

I have an array of restaurant objects and I want to list them by grouping their cities
My object is like;
restaurant = {
id: 'id',
name: 'name',
city: 'city'
}
This HTML Markup can give some info about what I want to do.
<div ng-repeat="restaurant in restaurant | filter: ???">
<div class="header">
<h1 ng-bind="restaurant.city"></h1>
<a>Select All</a>
</div>
<div class="clearfix" ng-repeat="???">
<input type="checkbox" id="restaurant.id" />
<label ng-bind="restaurant.name"></label>
</div>
</div>
Can I do it with one single array or do i need to create seperate city and restaurant arrays to do it?
If you want to group restaurants by city, you can use groupBy of angular.filter module.
Just add the JS file from here: http://www.cdnjs.com/libraries/angular-filter to your project and use following code.
var myApp = angular.module('myApp',['angular.filter']);
function MyCtrl($scope) {
$scope.restaurants = [
{id: 1, name: 'RestA', city: 'CityA'},
{id: 2, name: 'RestB', city: 'CityA'},
{id: 3, name: 'RestC', city: 'CityC'},
{id: 4, name: 'RestD', city: 'CityD'}
];
}
<div ng-controller="MyCtrl">
<ul ng-repeat="(key, value) in restaurants | groupBy: 'city'">
<b>{{ key }}</b>
<li ng-repeat="restaurant in value">
<i>restaurant: {{ restaurant.name }} </i>
</li>
</ul>
</div>
I've created JSFiddle for you with working example.

How to handle selected/unselected ng-class to manage a tabbed popover

My code is as follows (the fiddle):
<div ng-controller="myCtrl">
<div ng-model="currentTab" ng-init="currentTab='Tab1'"/>
<div ng-init="popovers = [
{ name: 'Popover1',
displayName: 'Pop over with two tabs',
tabs: [
{ name: 'Tab1',
displayName: 'First tab',
description: ['First tab description']
},
{ name: 'Tab2',
displayName: 'Second tab',
description: ['Second tab description']
}
]
}
]"/>
<b>Tabs in popover</b>
<div
class="popover"
ng-repeat="p in popovers"
>
Popover name: {{p.displayName}}
<div ng-repeat="t in p.tabs"
class="tab"
ng-class="currentTab==t.name?'selected':''"
ng-click="currentTab=t.name"
>
{{t.name}}
</div>
<div ng-repeat="t in p.tabs"
class="tabContent"
ng-class="currentTab==t.name?'selected':''"
>
<p>{{t.displayName}}</p>
</div>
</div>
</div>
There is something I don't get which make the code not working perfectly, as the selected class name is never removed as one click on the tab.
When you want to modify a variable of your parent scope from within a ng-repeat you need to use $parent.currentTab.
Updated Fiddle

Nested checkboxes in AngularJS resource with external options

I have this data structure, search:
{
id: '1',
name: 'Foo'
service_ids:
[
3,
8,
12
]
}
I then have another data structure, services, that matches the ids from service_ids above with the below:
[
{
id: 3,
name: 'Fighter'
},
{
id: 4,
name: 'Typhoon'
},
{
id: 8,
name: 'Kung'
},
{
id: 12,
name: 'Builder'
}
]
I want to display this in a form using AngularJS. The name is fine. I want to display all possible services as checkboxes and if the search has one of the services checked then it is ticked in the checkbox. Something like:
<li ng-repeat="search in searches">
<input ng-model="search.name">
<ul>
<li ng-repeat="service in services">
<input type="checkbox">
{{service.name}}
</li>
</ul>
</li>
I don't know how to link that checkbox to the service_ids and the services. Any help appreciated.
I am using $resource.
Update
Ignore my answer, misread you nesting request.
If anyone needs nesting guidance see below:
The best way to nest in angular that I have found is to create a template which is aware of child items like this:
<script type="text/ng-template" id="tree_item_renderer.html">
<span>{{tag.Name}}</span>
<ul ng-show="tag.Children.length > 0">
<li ng-repeat="tag in tag.Children" ng-include="'tree_item_renderer.html'" ></li>
</ul>
</script>
<ul class="tag-list">
<li ng-repeat="tag in tags" ng-include="'tree_item_renderer.html'" ></li>
</ul>
If I understand your question it should be as easy as:
<input type="checkbox" ng-model="search.service_ids[service.id]">
And you should also get bi-directional binding.
Updated
Just realized search.service_ids is an array not a map. So the solution above is not accurate.
You might want instead to use a filter:
<input type="checkbox" ng-checked="search.service_ids | contains:service.id">
Then
filter('contains', function() {
return function(haystack, needle) {
return haystack.indexOf(needle) >= 0;
}
});

Creating a dynanic form in AngularJS with nested lists

I have a model in AngularJS that is structured like so:
region = { 'substances': [
{ 'id': 123, 'name': 'Hello', 'versions': ['A', 'B', 'C'] },
{ 'id': 456, 'name': 'World', 'versions': ['A', 'B', 'C'] }
]}
I want to be able to display and modify this model in a form. Currently I have nested ng-repeats:
<ul>
<li ng-repeat="substance in region.substances">
<input name="substance[]" class="input-medium" type="text" ng-model="substance.name">
<ul>
<li ng-repeat="version in substance.versions">
<input style="margin-left: 10px;" type="text" name="<% substance.id %>.version[]" class="input-medium" ng-model="version">
</li>
</ul>
</li>
</ul>
(Note: I've redefined AngularJS brackets to be <% %>).
I can modify the name, but I AngularJS prevents me from even typing in the inner inputs. I'm guessing that I'm not binding to the model correctly? Also, how would I go about adding another "substance" that has a name and a list of versions?
Is there a proper way to be naming my inputs?
As suggested by #Yoshi , is always easiest to use object inheritance rather than primitive within nested scopes.
$scope.region = { substances: [
{ name: 'Hello', versions: [{x:'A'},{x: 'B'},{x: 'C'}] },
{ name: 'World', versions: [{x:'A'},{x: 'B'},{x: 'C'}] }
]};
<ul>
<li ng-repeat="substance in region.substances">
<input class="input-medium" type="text" ng-model="substance.name">
<ul>
<li ng-repeat="version in substance.versions">
<input type="text" ng-model="version.x">
</li>
</ul>
</li>
</ul>
Demo

Resources