Nested lists in Angular JS - javascript

I am trying to create JSON to use for a nested list.
I assume I am using incorrect syntax on the second ng-repeat:
<ul>
<li ng-repeat="n in navData">Label = {{n.label}}</li>
<ul>
<li ng-repeat="n.children in n">Child label = {{p.label}}</li>
</ul>
</ul>
When my data model is
var nav = [{
label: 'Pages',
value: 'pages',
children: [{
label: 'Home',
value: 'home'
}, {
label: 'Left Nav',
value: 'left-nav'
}]
}, {
label: 'Components',
value: 'components'
}];
All I am getting in the html is the top level:
Label = Pages
Label = Components

Outer li tag should close after inner li tag with ng-repeat. And you should use different var name and slightly different expression (actually you have name your var as p {{p.label}} somewhere but not in nested loop):
<ul>
<li ng-repeat="n in navData">Label = {{n.label}}<!-- closing li removed //-->
<ul>
<li ng-repeat="p in n.children">Child label = {{p.label}}</li>
</ul>
</li> <!-- closing li tag added //-->
</ul>

Related

reference a json field name that contains a dot

I am trying to reference a field from the JSON in Angular
{ "elements": [
{
"LCSSEASON.IDA2A2": "351453",
"LCSSEASON.BRANCHIDITERATIONINFO": "335697"
},
{
"LCSSEASON.IDA2A2": "353995",
"LCSSEASON.BRANCHIDITERATIONINFO": "298931"
},
{
"LCSSEASON.IDA2A2": "310935",
"LCSSEASON.BRANCHIDITERATIONINFO": "282654"
},
{
"LCSSEASON.IDA2A2": "353967",
"LCSSEASON.BRANCHIDITERATIONINFO": "353966"
},
{
"LCSSEASON.IDA2A2": "355294",
"LCSSEASON.BRANCHIDITERATIONINFO": "355293"
}
]
}
In the HTML Template, I want to print the element - elements.LCSSEASON.IDA2A2
But having 2 dots in key is causing issues in below code
Any ideas and suggestions??
I cannot change server JSON Output as its legacy application and I have no control.
<ul *ngFor="let item of items"> <li> {{item.LCSSEASON.IDA2A2}} </li> </ul>
access the property using square brackets like this
<ul *ngFor="let item of items"> <li> {{item['LCSSEASON.IDA2A2']}} </li> </ul>

dynamically Build ng-template using list

I am trying to build ng-template dynamically, In the Data structure, I have a Object that contains list of object of same type or other type of object.
[
{
type: "device",
id: 1,
allowedTypes: ["device","action"],
max: 5,
columns: [
{
type: "action",
id: "1"
},
{
type: "device",
id: 2,
allowedTypes: ["device","action"],
max: 5,
columns: [
{
type: "action",
id: "1"
},
{
type: "action",
id: "2"
}
]
}
]
}
]
My ng-template code:
<script type="text/ng-template" id="and.html">
<div class="container-element box box-red">
<h3>And {{item.id}}</h3>
<ul dnd-list="item.columns"
dnd-allowed-types="item.allowedTypes"
dnd-disable-if="item.columns.length >= item.max">
<li ng-repeat="element in item.columns"
dnd-draggable="element"
dnd-effect-allowed="move"
dnd-moved="item.columns.splice($index, 1)"
dnd-selected="models.selected = element"
ng-class="{selected: models.selected === element}"
ng-include="element.type + '.html'" onload="onloadAction()">
</li>
</ul>
<div class="clearfix"></div>
</div>
</script>
In the ng-template code the first level or different types of object can easily be added, however same type of object does not work properly when added in the 2nd level, it seems the its going in a recursive loop.
This is because the nested ng-template (child) ng-template use of root item.columns from the ng-repeat="element in item.columns".
<li ng-repeat="element in item.columns"
dnd-draggable="element"
ng-include="element.type + '.html'">
</li>
any advise how to resolve this issue.
I have managed to resolve this issue, ng-repeat create a new child scope, however the item from the parent scope is also visible to in the child scope, as this is recursive that mean child template and parent template both have the variable with the same name called item. However the child scope variable item is ignored:
<li ng-repeat="element in item.columns"
dnd-draggable="element"
ng-include="element.type + '.html'">
</li>
in the above snippet the element also has a variable called item, so in the child scope when we call item.columns the item variable of parent is invoked again, to ensure that the item variable of child is not ignored, we need to use ng-init with ng-include and set the current element as item in the child scope as shown below:
<li ng-repeat="element in item.columns"
dnd-draggable="element"
ng-include="element.type + '.html'" ng-init="item=element">
</li>
To read more on this please visit
http://benfoster.io/blog/angularjs-recursive-templates

How to filter objects in array by category key in Angular ng-repeat

I'm trying to use Angular filter to display only sorted tags by category
Example of a tag object in tags array:
{
term: term,
id: id,
category: category
}
The ng-repeat tags:
<li ng-repeat="(k, m) in tags | filter: filterTags | orderBy:predicate:reverse"
ng-class="{'selected': m.selected}"
ng-click="selectTag(m)">
<div class="tag">{{m.term}}</div>
</li>
The sort by category radio buttons:
<div class="category-selection">
<ul>
<li>
<input type="radio" ng-model="catSort" name="brand" value="brand">
Brand
</li>
<li>
<input type="radio" ng-model="catSort" name="client" value="client">
Client
</li>
In the sort radio button directive controller:
// Detect category sort
// Then apply the value to the filter function:
$scope.$watch('catSort', function(value) {
console.log(value);
tagsPanel = ScopeFactory.getScope('tagsPanel');
tagsPanel.filterTags(value);
});
I found out that filter is has it's own Angular module, so my question is, how do I get the category strings into this filter?
.filter('filterTags', function() {
return function(tags, category) {
return tags;
};
});
Here is where I capture the new category, how would I send the value into the filter above?
$scope.$watch('catSort', function(value) {
console.log(value);
});
If I got it right. You want to filter your tag object array by category.
You can call a scope method and return true if it matches the currently selected category. The parameter for this method will be a tag object of your ng-repeat. So you can do a check like return tag.category == $scope.catSort;
Please have a look at the demo below and here at jsFiddle.
(I've took sport categories just to have some dummy data.)
angular.module('myApp', [])
.controller('mainCtrl', function ($scope) {
$scope.catSort = "football";
$scope.tags = [{
term: 'foot1',
id: 'id',
category: 'football'
}, {
term: 'foot2',
id: 'id2',
category: 'football'
}, {
term: 'base1',
id: 'id',
category: 'baseball'
}, {
term: 'base2',
id: 'id2',
category: 'baseball'
}, ];
$scope.filterTags = function (tag) {
//console.log(tag, $scope.catSort);
return tag.category == $scope.catSort;
};
});
ul {
list-style-type: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="mainCtrl">Filter by category:
<div class="category-selection">
<ul>
<li>
<input type="radio" ng-model="catSort" name="football" value="football" />Football</li>
<li>
<input type="radio" ng-model="catSort" name="baseball" value="baseball" />Baseball</li>
</ul>
</div>Teams:
<ul>
<li ng-repeat="(index, tag) in tags | filter: filterTags" ng-class="{'selected': tag.selected}" ng-click="selectTag(tag)">
<div class="tag">{{tag.term}}</div>
</li>
</ul>
</div>

Accessing data inside nested objects and arrays

I'm making a fairly complex menu system where it should change depending on the authority that has logged in. Now my question is, have I nested it too much? How do I access for example a title in the items, in the admin within the menus? I'm gonna generate the menus using angularJS's ng-repeat so I need to be able to access it via "item in menus.admin.items.title" for example. I figured I should ask now before I add more in case this isn't a viable option.
This is my menu structure inside the angular controller:
$scope.menus = [{
admin: [{
title: 'Administration',
items: [{
title: 'Hantera utbildningar',
URL: 'mngprograms'
},
{
title: 'Hantera kurser',
URL: 'mngcourses'
},
{
title: 'Hantera lärare',
URL: 'mngteachers'
},
{
title: 'Hantera studenter',
URL: 'mngstudents'
}],
URL: 'administration',
id: 'administration'
}]
}]
Here's my failed attempt at accessing it:
EDIT:
To get a clearer view of the whole thing go here: http://jsfiddle.net/52evmfg9/
<ul id="main-menu">
<li data-ng-repeat="menu in menus" id="{{menu.id}}">{{menu.title}}
<ul data-ng-if="menu.admin">
<li data-ng-repeat="subitem in menu[3].admin.items">{{subitem.title}}</li>
</ul>
</li>
</ul>
How do I write this?
I recommend making your hierarchy structure more explicit. For each menu, you can have a key "submenus" where you can find menus further down in the hierarchy. A useful directive for hiding elements is ng-show.
I would only build one complete menu tree and then set permissions for your users or roles. Otherwise the tree will become unmanageable and there will be repeated data.
Here is an example jsBin:
http://jsbin.com/sixiw/2/edit?html,js,output
To answer the question in the comments:
<div data-ng-repeat="(k,v) in menus">
<div data-ng-repeat="(k,w) in v">
<div data-ng-repeat="(k,x) in w">
<ul data-ng-repeat="(k,y) in x" >
{{k}} : {{y}}
<li ng-if="z.title" data-ng-repeat="(k,z) in y track by $index">
Title: {{z.title}} URL: {{z.URL}}
</li>
</ul>
</div>
</div>
</div>
http://plnkr.co/edit/WLnXBQbbOqveJuHiUeEI?p=preview

Calling a function defined within knockout js ViewModel

I have a html 5 view and want to perform Drag and Drop. In my html I have a knockout foreach as given below. The li element is being dragged on.
<ul class="games-list" data-bind="foreach: games">
<li data-bind="text: name, attr: { 'data-dragdrop': id }"
ondragstart='setTransferProperties(event)'
draggable="true">
</li>
</ul>
and here is the javascript with knockout ViewModel
<script type="text/javascript">
var AppScope = function () {
...//plain js object here
//knockout js View Model
function PlayersViewModel() {
var self = this
self.games = ko.observableArray([
new Game({ id: 0, name: "Cricket" }),
new Game({ id: 1, name: "Football" }),
new Game({ id: 2, name: "Hockey" })
]);
...
//Drag and Drop
self.setTransferProperties = function (event) { //Not invoked
event.dataTransfer.setData("Text", event.target.getAttribute('data-dragdrop'));
};
}
}
With the above the setTransferProperties(event) is looked for in AppScope, instead of inside the knockout ViewModel, and hence not found.
What would be the way to invoke the setTransferProperties(event) defined in the knockout ViewModel when performing the Drag.
You need to do the following
<ul class="games-list" data-bind="foreach: games">
<li data-bind="text: name, attr: {
'data-dragdrop': id ,
'ondragstart':$parent.setTransferProperties
}"
draggable="true">
</li>
</ul>

Categories