I have an application created with AngularJS which has a strip of menus. What I am trying to do is to create submenus with each menu. The submenus can be created by adding additional <ul> <li> ... </li> </ul> under my existing list items of menus. How can I do it?
This is my code with AngularJS calls:
<div id="menu">
<ul>
<li ng-class="{selected: $index==currPage}" ng-repeat="page in data.pages">
{{page.menuTitle}} {{page.subMenu}}
</li>
</ul>
</div>
This generates the following code in HTML with div of id=menu:
<ul>
<li class="ng-scope ng-binding selected" ng-class="{selected: $index==currPage}" ng-repeat="page in data.pages">
<a class="ng-binding" href="" ng-click="goToPage($index)">Introduction</a>
</li>
<li class="ng-scope ng-binding" ng-class="{selected: $index==currPage}" ng-repeat="page in data.pages">
<a class="ng-binding" href="" ng-click="goToPage($index)">Cases</a>
</li>
...
...
</ul>
AngularJS JS code
The Angular JS Code to compliment above HTML is:
data.title = 'Amanpour consult Petrochemicals & Energy';
data.pages = [];
data.pages[0] = {};
data.pages[0].menuTitle = 'Introduction';
data.pages[0].slides = [];
data.pages[0].slides[0] = {heading:'A Heading: profile', speaker: 'The man himself', title:'Expert in awesomeness', img:'showing-awesomeness.jpg', video:'witnessing-awesomeness.m4v'};
....
data.pages[0].slides[1]
....
data.pages[0].slides[2]
....
data.pages[0].slides[3]
Now to add the submenu, I thought may be I could following to AngularJS code:
data.pages[0].subMenu = '<ul> <li> First Link </li> <li> Second Link </li> </ul>';
and then call it in HTML like this (notice the {{page.subMenu}}):
<li ng-class="{selected: $index==currPage}" ng-repeat="page in data.pages">
{{page.menuTitle}} **{{page.subMenu}}**
</li>
But it doesn't work, all it gives me is the following, which just prints the HTML literally on the page:
<ul> <li> <a href="#">First Link</a> </li> <li> <a href="#">Second Link</a> </li> </ul>
Update
I'd have to create a menu within JS like this:
data.subMenu = [];
data.subMenu[0] = {};
data.subMenu[0].list = [];
data.subMenu[0].list[0] = 'Menu 1';
data.subMenu[0].list[1] = 'Menu 2';
data.subMenu[0].list[2] = 'Menu 3';
and would have to call it in my HTML like this:
<div id="menu">
<ul>
<li ng-class="{selected: $index==currPage}" ng-repeat="page in data.pages">
{{page.menuTitle}}
<ul>
<li ng-repeat="smenu in data.subMenu">
{{smenu.list[smenu]}}
</li>
</ul>
</li>
</ul>
</div>
The only problem is that I'd have to do the looping right; I am not able to make the index within the loop correctly.
I'm not quite sure if this is what you were looking for but take a look at this jsfiddle : http://jsfiddle.net/Marabyte/dxBe8/
In the HTML you have the structure for two nav, the main nav, the sub nav and respective ul/li
<section ng-app ng-controller="navCtrl">
<nav class="main">
<ul class="ul-nav">
<li class="li-nav li-main" ng-click="select($index)" ng-repeat="list in lists">{{list.name}}</li>
</ul>
</nav>
<nav class="sub" ng-show="subMenuShow">
<ul class="ul-nav ul-sec">
<li class="li-nav li-main" ng-repeat="sublist in sublists">{{sublist}}</li>
</ul>
</nav>
</section>
In your controller you have 2 lists for the main and sub nav.
function navCtrl($scope) {
$scope.lists = [{
name: "Cinema"
}, {
name: "TV Shows"
}, {
name: "Music"
}, {
name: "Awards"
}];
$scope.subMenu = [
["Snatch", "Rockrolla"],
["Sherlock", "Game of Thrones"],
["The National", "Johnny Cash", "Xutos & Pontapés"],
["Oscars", "Golden Globes", "Emmys", "BAFTA"]
];
$scope.select = function ($index) {
$scope.sublists = $scope.subMenu[$index];
$scope.subMenuShow = true;
};
}
The select() function is showing the subMenu based on the index of the main list.
Hope it helps!
Hugo
Related
I have a list of parents: ['a','b','c'],
and 3 lists of children:
$ctrl.aChildren = ['aa','aaa']
$ctrl.bChildren = ['bb','bbb']
$ctrl.cChildren = ['cc','ccc']
I'd like to access these 3 variables in the inner <li> using variable parent from outer <li>
<li ng-repeat="parent in $ctrl.parents">
....
<ul>
<li ng-repeat="child in $ctrl[{{parent}} + 'Children']">
</li>
</ul>
...
</li>
I got an error saying
'{' is an unexpected
Thanks
You don't need put {{}}.It should be like this
<li ng-repeat="parent in $ctrl.parents">
{{parent}}
<ul>
<li ng-repeat="child in $ctrl[parent + 'Children']">
{{child}}
</li>
</ul>
var app = angular.module('anApp', []);
app.controller('ctrl', function($scope) {
var $ctrl = this;
$ctrl.parents = ['a', 'b', 'c'];
$ctrl.aChildren = ['aa', 'aaa']
$ctrl.bChildren = ['bb', 'bbb']
$ctrl.cChildren = ['cc', 'ccc']
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.min.js"></script>
<div ng-app="anApp" ng-controller="ctrl as $ctrl">
<li ng-repeat="parent in $ctrl.parents">
{{parent}}
<ul>
<li ng-repeat="child in $ctrl[parent + 'Children']">
{{child}}
</li>
</ul>
</li>
</div>
You no need to add {{}} inside ng-repeat directive. Replace the following code
<li ng-repeat="child in $ctrl[{{parent}} + 'Children']">
with
<li ng-repeat="child in $ctrl[parent + 'Children']">
angular.module('myApp')
.component('sideNav', {
controller: function SideNavController($scope) {
$scope.navigation = {};
$scope.click = function(key) {
$scope.navigation[key] = !$scope.navigation[key];
}
},
templateUrl: 'components/side-nav/side-nav.html',
})
to be used as simply
<side-nav></side-nav>
The template is
<!-- other li items -->
<li ng-init="navigation.charts = false"
ng-click="click('charts')">
<a href="#">
<i class="fa fa-bar-chart-o fa-fw"></i>
Charts {{ navigation.charts }}
<span class="fa arrow"></span>
</a>
<ul class="nav nav-second-level"
ng-show="navigation.charts">
<li>
Charts
</li>
<li>
Graphs
</li>
</ul>
</li>
navigation.charts is correctly initialized to false and hence the li > ul is hidden. Clicking the top level li item updates the navigation object but the view does not update. I was expecting the li > ul element to get displayed.
Plunkr: https://plnkr.co/edit/UJpdFErwVUzsCd65hlW0?p=preview
Clicking on the link reloads the page and re-initializes the directive. Try modifying to:
<li ng-init="navigation.charts = false"
ng-click="$event.preventDefault(); click('charts')">
You can actually add href="javascript:void(0)"
<ul>
<li ng-click="click('charts')">
<a href="javascript:void(0)">
<i class="fa fa-bar-chart-o fa-fw"></i>
Charts {{ navigation.charts }}
<span class="fa arrow"></span>
</a>
<ul class="nav nav-second-level"
ng-show="navigation.charts">
<li>
Charts
</li>
<li>
Graphs
</li>
</ul>
This actually happens as you put href="#" which I think refresh the page.
In this plunker I'm trying to get the selection of a list of dropdown lists. The problem is that the dropdowns appear empty (no labels are selected by default, as set in the controller). How to fix this?
Javascript
var app = angular.module('app', ['ui.bootstrap']);
app.controller('ctl', function ($scope) {
$scope.rows = [ {selection: "Sel 1"}, {selection: "Sel 2"} ];
$scope.selectItem = function(ev,index) {
var sel = ev.target.textContent;
$scope.lastSelection = index + " - " + sel;
$scope.rows[index].selection = sel;
};
});
HTML
<table>
<tr ng-repeat="row in rows">
<td>
<div class="btn-group" uib-dropdown>
<button id="btn-append-to-body" type="button" class="btn btn-primary" uib-dropdown-toggle="">
{{selection}} <span class="caret"></span>
</button>
<ul class="dropdown-menu" ng-click="selectItem($event,$index)" uib-dropdown-menu="" role="menu" aria-labelledby="btn-append-to-body">
<li role="menuitem">
<a href="#" data-value="1" >The first item</a>
</li>
<li role="menuitem">
Another item
</li>
<li role="menuitem">
Yet another item
</li>
</ul>
</div>
</td>
</tr>
</table>
<br/>
Last selection: {{lastSelection}}
You're missing the row element in your binding
{{row.selection}} instead of {{selection}}
http://plnkr.co/edit/Q5YnByLUKmjkpet2gKWC?p=preview
there is the console error: i is not deifned,
solution is:
$scope.selectItem = function(ev,index) {
var sel = ev.target.textContent;
$scope.lastSelection = index + " - " + sel;
};
also edit button {{row.selection}} .
here is the plunker code without errors.
Try this ;)
In app.js replace
$scope.lastSelection = i + " - " + sel;
with
$scope.lastSelection = index + " - " + sel;
And in index.html replace
<ul class="dropdown-menu" uib-dropdown-menu="" role="menu" aria-labelledby="btn-append-to-body" ng-click="selectItem($event,$index)">
<li role="menuitem">
<a href="#" data-value="1" >The first item</a>
</li>
<li role="menuitem">
Another item
</li>
<li role="menuitem">
Yet another item
</li>
</ul>
with
<ul class="dropdown-menu" uib-dropdown-menu="" role="menu" aria-labelledby="btn-append-to-body">
<li role="menuitem">
<a href="#" data-value="1" ng-click="selectItem($event,$index)" >The first item</a>
</li>
<li role="menuitem">
<a href="#" data-value="2" ng-click="selectItem($event,$index)" >Another item</a>
</li>
<li role="menuitem">
<a href="#" data-value="3" ng-click="selectItem($event,$index)" >Yet another item</a>
</li>
</ul>
Check example below. In this case the 'expensiveFunction' is called for every item in myList
<ul>
<li ng-show="expensiveFunction(period)" ng-repeat="a in myList">
<a ng-click="onMove(period)">Move here </a>
</li>
<li ng-hide="!canBook">
<small>No free resources</small>
</li>
</ul>
Any ideas on how to prevent that?
<ul>
<!-- Possible, but creates invalid html -->
<div ng-show="expensiveFunction(period)">
<li ng-repeat="a in myList">
<a ng-click="onMove(period)">Move here </a>
</li>
</div>
<li ng-hide="!canBook">
<small>No free resources</small>
</li>
</ul>
Thanks for any suggestion
Larsi
If the value of period is static or at least does not change with every iteration I would calculate the expensiveFunction(period) only once when the corresponding controller is loaded:
$scope.period = whatEverItIs
$scope.isExpensive = expensiveFunction(period);
And in your view:
<ul>
<li ng-show="isExpensive" ng-repeat="a in myList">
<a ng-click="onMove(period)">Move here </a>
</li>
<li ng-hide="!canBook">
<small>No free resources</small>
</li>
</ul>
You can try to make all calculations in a separate function by adding new display attribute to store statuses for ng-show.
Try to make all your calculations at once by calling function once.
For example.
/**
* Expensive function
* #param {string} lists
* #returns {object}
*/
function expensiveFunction(lists){
angular.forEach(lists, function (key, value) {
lists.display = true; // here goes your logic
});
return lists;
}
var myList = expensiveFunction(myList);
<ul>
<li ng-show="a.dispaly" ng-repeat="a in myList">
<a ng-click="onMove(period)">Move here </a>
</li>
<li ng-hide="!canBook">
<small>No free resources</small>
</li>
</ul>
I am using angularjs to render a hierarchical structure. The test case is at http://jsbin.com/agodoj/1/edit
My question is why ng-repeat stop working at level 3 ? Thanks
Here is my model
function Test($scope) {
$scope.cars = {
chrylser: {
nameplates: [{
name: "np1",
trims: [
"tirm1", "trim2"
]
}]
}
};
}
Here is my template
<div ng-app ng-controller="Test">
<div ng-repeat="(key, value) in cars">
{{key}}
<ul>
<li ng-repeat="np in value.nameplates">{{np.name}}, {{np.trims}}</li>
<ul>
<li ng-repeat="trim in np.trims">
(ng-repeat stop working here) {{trim}}
</li>
</ul>
</ul>
</div>
</div>
Just need to move the closing </li> tag after your inner <ul>. You had the <li ng-repeat="np in value.nameplates"> immediately closing, ending the loop.
<div ng-app ng-controller="Test">
<div ng-repeat="(key, value) in cars">
{{key}}
<ul>
<li ng-repeat="np in value.nameplates">{{np.name}}, {{np.trims}}
<ul>
<li ng-repeat="trim in np.trims">
works! {{trim}}
</li>
</ul>
</li>
</ul>
</div>
</div>