Angular ngfor loop displaying menu - javascript

I am trying create a menu and sub menu.. The structure I want for my menu is mentioned below. Here is the demo I am trying I am getting wrong structure.
Demo https://stackblitz.com/edit/angular-odvcsm.
"Sub Test": { // Main menu
"Example1":"hai",//sub menu
"Ex2":"hello"// sub menu
},

You need one more level of iteration here to go down in the sub-menu and to remove the top level label as it's no use for your case:
HTML
<ul *ngFor="let partner of list_value | keyvalue let i=index">
<li *ngFor="let innerData of partner.value | keyvalue">
<ul class="submenu">
<li *ngFor="let innerData1 of innerData.value | keyvalue">
{{innerData1.key}}
<ul class="submenu">
<li *ngFor="let item of innerData1.value | keyvalue">
{{item.value}}
</li>
</ul>
</li>
</ul>
</li>
</ul>
demo

Related

How to fix Slimmenu multi level sub items going out of the screen

I am using slimmenu for my website. but unfortunately submenu is going out of my desktop screen if there have nested child items. So i tried to add a class "edge" with'ul' when it will go out of screen.
Here is the screenshot of the preview where i used the code https://codepen.io/themeix/pen/gyxGNO
But my code doesn't work. Here is my HTML code.
<div class="main-menu-area">
<div class="logo-area">
<h1>My Logo </h1>
</div>
<div class="menu-warpper">
<div class="navigation-navbar">
<ul id="navigation" class="slimmenu">
<li>Main Item</li>
<li>Main Item</li>
<li>Main Item</li>
<li>Main Item</li>
<li>
Main Item
<ul>
<li>
Sub Menu 1
<ul>
<li>
Sub Menu 2
<ul>
<li>
Sub Menu 3
<ul>
<li>
Sub Menu 4
<ul>
<li>
Sub Menu 5
<ul>
<li>Sub Menu 6</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>Sub Menu 1</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
I tried the following js code to inject a class edge but unfortunately its adding for all the ul when sub menu items going out of the screen.. I want to inject only for the specific ($this) submenu item when it goes out of the screen.
jQuery(".slimmenu li").on('mouseenter mouseleave', function(e) {
if (jQuery('ul', this).length) {
var elm = jQuery('ul:first', this);
var off = elm.offset();
var l = off.left;
var w = elm.width();
var docH = jQuery(".navigation-navbar").height();
var docW = jQuery(".navigation-navbar").width();
var isEntirelyVisible = (l + w <= docW);
if (!isEntirelyVisible) {
jQuery(this).addClass('edge');
} else {
jQuery(this).removeClass('edge');
}
}
});
in that js code edge class adding for all the submenu items but i want to inject it only for the current .has-submenu item while mousehove and its going out of the screen. and removeclass also not working when i leave the mouse. Can anyone help me to fix that issue for me by using js?
remove your menu width....there is limited space between the nav link and that's why this was happened.

How to iterate an object with a specific key in angularjs?

I want to list an item inside a specific key using a filter. Now listing like this.
Sanal
Jin
John
Tim
Jeff
Sam
John
Tim
I want like this using a filterJeffSam
Here is the Fiddle
function testCtrl($scope) {
$scope.items = {"id":"B716","day":8,"di":{"type":"normal","one":[{"name":"Sanal","age":"18"},{"name":"Jin","age":"25"}],"two":[{"name":"Jeff","age":"55"},{"name":"Sam","age":"32"}],"three":[{"name":"John","age":"34"},{"name":"Tim","age":"39"}]}};
}
<div ng-app="" ng-controller="testCtrl">
<ul>
<li ng-repeat="val in items.di">
<ul>
<li ng-repeat="value in val">{{value.name}}</li>
</ul>
</li>
</ul>
</div>
in your ng repeat change it as
<li ng-repeat="value in val | filter: val.name='jeff'">{{value.name}}</li>
I have used name you can use the value that you want ot test

Isolated scope for individual items in list in angularjs

I have a list of items which I'm populating using ng-repeat
<ul>
<li ng-repeat="item in items" ng-class="setClass" ng-click="assignClass()">{{item.name}}</li>
</ul>
and in my controller
$scope.assignClass = function(){
$scope.setClass = "sampleClass";
}
When I'm doing like this and clicking on any one item all the items are getting the sampleClass added.
I need this scenario,
When I click on the first item that item should have the sampleClass and when I click on the second item I want both first and second items should have sampleClass
How can I achieve this scenario?
The code you we're using sets the styling for all the list items as you mentioned.
I've change the code a bit to set the class for an individual item in the unordered list.
By calling the assignClass using the selected item as a parameter you can set the class for this item.
<ul>
<li ng-repeat="item in items" ng-class="item.setClass" ng-click="assignClass(item)">
{{item.name}}
</li>
</ul>
$scope.assignClass = function(selectedItem){
selectedItem.setClass = "sampleClass";
}
Pass the item into assignClass function.
<ul>
<li ng-repeat="item in items" ng-click="assignClass(item)">{{item.name}}</li>
</ul>
Then change the class of that item
$scope.assignClass = function(item){
$(item).toggleClass("sampleClass");
}

Filter matched elements by class name in Angular js.

Problem:
I have an unordered list of items which are returned from a json call and are output using ng-repeat. Each one of these items has a class name (there are about 9 categories).
I have a second unordered list which is simply a list of available categories.
Aim:
I want to be able to select one of the categories in the right hand list, which will apply a filter to the actual list of returned elements. This should be activated via a toggle (so click once: filtered, click again: filter removed). So it is simply looking to match the classname in the clicked element, to the elements that share the same classname in the list of json data.
I cannot use ng-model (as this is reserved for certain form elements).
For my jsfiddle I am simply using static html.
Here is my angular code:
/* angular custom filter on returned ajax api data */
var app = angular.module('app', []);
app.controller('main', function($scope) {
$scope.chFilters = {};
$scope.links = [
{name: 'atm'},
{name: 'internet'},
{name: 'mobile'},
{name: 'sms'},
{name: 'postal'}
];
$scope.channels = ["ATM", "INTERNET", "SMS", "POSTAL","MOBILE"];
});
(this is based on another question I found on SO). Unfortunately the fiddle is a bit messy and has some extraneous code in it.
HTML:
<div ng-app="app">
<div ng-controller="main">
<ul>
<li class="atm">Some stuff ATM</li>
<li class="internet">Some stuff INTERNET</li>
<li class="sms">Some stuff ATM</li>
<li class="atm">Some stuff ATM</li>
<li class="postal">Some stuff POSTAL</li>
<li class="atm">Some stuff ATM</li>
<li class="internet">Some stuff INTERNET</li>
<li class="postal">Some stuff POSTAL</li>
<li class="postal">Some stuff POSTAL</li>
<li class="atm">Some stuff ATM</li>
<li class="sms">Some stuff SMS</li>
<li class="mobile">Some stuff MOBILE</li>
<li class="internet">Some stuff INTERNET</li>
<li class="mobile">Some stuff MOBILE</li>
</ul>
<ul class="channel-filters">
<li ng-repeat="link in links | filter:chFilters" class="{{link.name | lowercase}}"><a ng-click="chFilters.name = link.name">{{link.name | uppercase}}</a></li>
<li class="last" ng-click="chFilters.name = ''">CLEAR FILTER</li>
</ul>
<ul>
<li ng-repeat="channel in channels | filter:chFilters">
<strong>{{channel}}</strong>
<a ng-click="chFilters = channel">{{channel}}</a>
</li>
</ul>
<!-- original -->
<ul>
<li ng-repeat="link in links | filter:chFilters">
<strong>{{link.name}}</strong>
<a ng-click="chFilters.name = link.name">{{link.name}}</a>
</li>
</ul>
</div>
</div>
This is the actual HTML from the application (with the call to the api).
<ul class="accordion">
<li class="search-text-channel">
<input type="textarea" ng-model="searchTextChannel.$" placeholder="Search"/>
</li>
<li ng-repeat="day in interactions.model.byDay | filter:searchTextChannel" ng-click="hidden = !hidden" ng-init="hidden = false" class="{{day.channel | removeSpace | lowercase}}" ng-class="{'closed': !hidden, 'open': hidden}">
<span class="date">{{day.date}}</span>
<span class="subheading">{{day.channel}}</span>
<ul ng-show="hidden">
<li ng-repeat="interaction in day.interactions">
{{interaction.time}} {{interaction.description | removeUnderscore}}
</li>
</ul>
</li>
<li class="load-more">
<i class="fa fa-plus"></i>LOAD MORE
</li>
</ul>
I have managed to recreate this functionality in jquery, but I think it would be better to implement an angular solution in an angular application.
I've tried researching and also attempted to implement show/hide as well as a custom filter, but so far no joy.
Here is my (messy) jsfiddle
<ul>
<li ng-repeat="channel in channels | filter:chFilters.name">
<strong>{{channel}}</strong>
<a ng-click="chFilters = channel">{{channel}}</a>
</li>
</ul>
<!-- original -->
<ul>
<li ng-repeat="link in links | filter:chFilters.name">
<strong>{{link.name}}</strong>
<a ng-click="chFilters.name = link.name">{{link.name}}</a>
</li>
</ul>
Update Plunker
Let me know if you have any question on this.
Here is part of the solution:
Suppose your items look like this:
$scope.items = [
{ class: "atm", label: "Some stuff ATM" },
{ class: "internet", label: "Some stuff INTERNET" },
{ class: "sms", label: "Some stuff SMS" },
{ class: "postal", label: "Some stuff POSTAL" },
...
];
To show a filtered list (only filtering by a single channel for now): create a separate list in the scope, with the filters applied:
$scope.click = function(name) {
$scope.chFilters.name = name;
$scope.filteredItems = $scope.items.filter(function(item) {
return item.class === $scope.chFilters.name;
});
};
Call this click handler from the bottom list:
...<a ng-click="click(link.name)">{{link.name | uppercase}}</a>....
And show filteredItems in the top list:
<ul>
<li ng-repeat="item in filteredItems" ng-class="item.class">{{item.label}}</li>
</ul>
So this is really just a starting point, it should be extended to handle multiple filters, etc...

AngularJS ng-repeat handle empty list case

I thought this would be a very common thing, but I couldn't find how to handle it in AngularJS. Let's say I have a list of events and want to output them with AngularJS, then that's pretty easy:
<ul>
<li ng-repeat="event in events">{{event.title}}</li>
</ul>
But how do I handle the case when the list is empty? I want to have a message box in place where the list is with something like "No events" or similar. The only thing that would come close is the ng-switch with events.length (how do I check if empty when an object and not an array?), but is that really the only option I have?
You can use ngShow.
<li ng-show="!events.length">No events</li>
See example.
Or you can use ngHide
<li ng-hide="events.length">No events</li>
See example.
For object you can test Object.keys.
And if you want to use this with a filtered list here's a neat trick:
<ul>
<li ng-repeat="item in filteredItems = (items | filter:keyword)">
...
</li>
</ul>
<div ng-hide="filteredItems.length">No items found</div>
You might want to check out the angular-ui directive ui-if if you just want to remove the ul from the DOM when the list is empty:
<ul ui-if="!!events.length">
<li ng-repeat="event in events">{{event.title}}</li>
</ul>
With the newer versions of angularjs the correct answer to this question is to use ng-if:
<ul>
<li ng-if="list.length === 0">( No items in this list yet! )</li>
<li ng-repeat="item in list">{{ item }}</li>
</ul>
This solution will not flicker when the list is about to download either because the list has to be defined and with a length of 0 for the message to display.
Here is a plunker to show it in use: http://plnkr.co/edit/in7ha1wTlpuVgamiOblS?p=preview
Tip: You can also show a loading text or spinner:
<li ng-if="!list">( Loading... )</li>
<ul>
<li ng-repeat="item in items | filter:keyword as filteredItems">
...
</li>
<li ng-if="filteredItems.length===0">
No items found
</li>
</ul>
This is similar to #Konrad 'ktoso' Malawski but slightly easier to remember.
Tested with Angular 1.4
Here's a different approach using CSS instead of JavaScript/AngularJS.
CSS:
.emptymsg {
display: list-item;
}
li + .emptymsg {
display: none;
}
Markup:
<ul>
<li ng-repeat="item in filteredItems"> ... </li>
<li class="emptymsg">No items found</li>
</ul>
If the list is empty, <li ng-repeat="item in filteredItems">, etc. will get commented out and will become a comment instead of a li element.
You can use this ng-switch:
<div ng-app ng-controller="friendsCtrl">
<label>Search: </label><input ng-model="searchText" type="text">
<div ng-init="filtered = (friends | filter:searchText)">
<h3>'Found '{{(friends | filter:searchText).length}} friends</h3>
<div ng-switch="(friends | filter:searchText).length">
<span class="ng-empty" ng-switch-when="0">No friends</span>
<table ng-switch-default>
<thead>
<tr>
<th>Name</th>
<th>Phone</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="friend in friends | filter:searchText">
<td>{{friend.name}}</td>
<td>{{friend.phone}}</td>
</tr>
</tbody>
</table>
</div>
You can use as keyword to refer a collection under a ng-repeat element:
<table>
<tr ng-repeat="task in tasks | filter:category | filter:query as res">
<td>{{task.id}}</td>
<td>{{task.description}}</td>
</tr>
<tr ng-if="res.length === 0">
<td colspan="2">no results</td>
</tr>
</table>
i usually use ng-show
<li ng-show="variable.length"></li>
where variable you define for example
<div class="list-group-item" ng-repeat="product in store.products">
<li ng-show="product.length">show something</li>
</div>
you can use ng-if because this is not render in html page and you dont see your html tag in inspect...
<ul ng-repeat="item in items" ng-if="items.length > 0">
<li>{{item}}<li>
</ul>
<div class="alert alert-info">there is no items!</div>

Categories