I have a fully functional menu (static), as im going to post, i want to replicate it based on what i get from a json file, i mean, create menu based on json file.
heres what i want as a menu:
html:
<div class="menu-container" >
<div class="menu">
<nav class="navbar-toggleable-md">
<div id="toggle" class="navbar-toggler"><a></a>
</div>
</nav>
<ul id="my_styles" class="rowcenter" >
<li>
<a role="button" class="button button4 menu-button" ><i role="button" class="icon-ambientais fs1 icon menu-button"></i><span class="button-text rowcenter menu-button">menu1</span></a>
<ul class="menu-list">
<li>
<i style="color: white" class="icon-ambientais fs1"></i>submenu
<ul>
<li>{{ 'submenu</li>
<li>submenu</li>
<li>{{ 'Imagens' | translate }}</li>
</ul>
</li>
<li>
<i style="color: white" class="icon-gestao-ambient fs1"></i>submenu3
<ul>
<li>submenu2</li>
<li>submenu2</li>
<li>submenu2</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
i have javascript to make it work.
I was searching for some help, because i cant figute it out..
i found that example, but i can't make it look like what i need.
https://www.codeproject.com/Articles/311758/Building-Menu-from-JSON
(passing the json obj to json file)
but i can't make it work like the menu i have.. if i change, for example, <ul> to <ul class="bla"> on this one, it breaks.
then i found that: Creating a Menu from JSON
but no success..
heres my trying code:
on html i just call
my typescript file:
.ts
ngOnInit() {
this._menu.getMenu()
.subscribe( res => {
let data = res;
console.log(data);
var getMenuItem = function (itemData) {
var item = $("<li>")
.append(
$("<a>", {
href: itemData.link,
html: itemData.name
}));
if (itemData.sub) {
var subList = $("<ul>");
$.each(itemData.sub, function () {
subList.append(getMenuItem(this));
});
item.append(subList);
}
return item;
};
var $menu = $("#menu");
$.each(data.menu, function () {
$menu.append(
getMenuItem(this)
);
});
$menu.menu();
});
}
had somebody done something like this before?
if someofyou have a working example with one menu item and submenu, even without img, i would appreciate it.
thank you.
Ok i got the solution!
Having al lthe css and html done, i've just got the JSON file to array that way:
this._menu.getMenu()
.subscribe( res => {
let data = res;
console.log(data);
this.arr = data;
this.arr = (<any>Object).values(data);
});
Then, on html i just picked the menus and sub menus names / links / icons, and ngfor them into the already made tags:
<li *ngFor="let item of arr[0]; let i = index;">
<a role="button" class="button button4 menu-button" ><i role="button" class={{item.class}}></i><span class="button-text rowcenter menu-button">{{item.name}}</span></a>
<ul class="menu-list" *ngIf=item.sub>
<li *ngFor="let sub of item.sub; let j = index;">
<i style="color: white" class={{item.sub[j].class}}></i>{{item.sub[j].name}}
<ul *ngFor="let smn of sub.submenu; let x = index;">
<li>{{smn.name}}</li>
</ul>
</li>
</ul>
</li>
heres the JSON i've used:
{
"menu": [
{
"name": "Menu Name",
"link": "link",
"class": "icon-ambientais fs1 icon menu-button",
"sub": [{
"name": "SubMenuTitle1",
"link": "link",
"class": "icon-ambientais fs1",
"submenu":[{
"name": "SubMenu1",
"routerlink": "/link/Qld"
},{
"name": "SubMenu2",
"routerlink": "/link/eQld"
},{
"name": "SubMenu3",
"routerlink": "/link/aQld"
}
]
},
{
"name": "SubMenuTitle2",
"link": "link",
"class": "icon-gestao-ambient fs1",
"submenu":[{
"name": "SubMenu1",
"routerlink": "/link2/oQld"
},{
"name": "SubMenu2",
"routerlink": "/doc/eQld"
}
]
}
]
}
}
Hope that helps somebody on the futurue
Related
I have an Angular 8 app I'm working on. I'm using boostrap 4 layout in my application. What I have created yet is a menu which having some nested menu items. I'm following Dynamic Expanding Nav Drawer example to create a dynamic expanding navbar.
The issue which I'm facing is when I click on my (1st Level / Parent) menu item it expands all nested menu items, which I want to prevent.
Below code I've tried:
<div class="row">
<div *ngTemplateOutlet="recursiveMenu; context:{ $implicit: navItems }"></div>
<ng-template #recursiveMenu let-menus>
<ul class="w-100">
<li *ngFor="let menu of menus;">
<a class="align-self-stretch text-left" href="#" title="{{menu.displayName}}" (click)="onItemSelected(menu)">
<i class="fa {{menu.iconName}}"></i> <span class="nav-header-primary p-2">{{menu.displayName}}</span>
<span *ngIf="menu.children" class="fa fa-caret-down fa-2x pull-right" [#indicatorRotate]="expanded ? 'expanded': 'collapsed'">
</span>
</a>
<ul *ngIf="menu.children && expanded" id="nav{{menu.id}}">
<ng-container *ngTemplateOutlet="recursiveMenu; context:{ $implicit: menu.children }"></ng-container>
</ul>
</li>
</ul>
</ng-template>
</div>
Kindly helpHere is a code stackblitz output. Let me know where I'm doing wrong.
All you sub menu items are getting expanded when you expand parent item, as you are maintaining a common/single flag for checking whether the menu is in expanded state or not.
So when you expand a parent item the expanded flag is set to true and all your menu items are also getting expanded.
so instead of maintaining a common flag you can maintain a flag for each item, in map.
You can add a id property in your menu list:
navItems: INavItem[] = [
{
id: 1,
displayName: 'Home',
iconName: 'fa-home fa-lg p-2',
route: 'home'
},
{
displayName: 'Settings',
id: 2,
iconName: 'fa-cog',
children: [
{
displayName: 'Navigation Management',
iconName: 'fa-sliders',
id: 3,
children: [
{
displayName: 'Navigation & Form Mapping',
id: 4,
iconName: 'fa-handshake-o',
route: 'navigation-form-mapping'
}]
}]
}]
You can maintain use expanded as a map of key-value pairs, in update your onItemSelected function as:
onItemSelected(item: INavItem) {
if (item.children && item.children.length) {
this.expanded[item.id] = !this.expanded[item.id];
}
}
And your html can be updated as:
<span *ngIf="menu.children" class="fa fa-caret-down fa-2x pull-right" [#indicatorRotate]="expanded[menu.id] ? 'expanded': 'collapsed'">
</span>
<ul *ngIf="menu.children && expanded[menu.id]" id="nav{{menu.id}}">
<ng-container *ngTemplateOutlet="recursiveMenu; context:{ $implicit: menu.children }"></ng-container>
</ul>
Working Demo
I am new to angular,
I have created a service to loop the nested json data for my list.
export const CATEGORIES: Category[] = [
{
id: 1,
categoryName:'Accessories',
subcatName: [
{subcategory: 'belts',}
],
},
{
id: 2,
categoryName:'Clothing',
subcatName: [
{subcategory: 'jeans}',
],
},
];
and
#Injectable()
export class CategoriesService {
constructor() { }
getCategories(): Category[]{
return CATEGORIES;
}
}
I am trying to loop this data on my list
<ul>
<li *ngFor="let cat of categoryList">
{{cat.categoryName}}
<ul>
<li *ngFor="let subcat of categoryList">
asdad {{subcat.subcategory}}
</li>
</ul>
</li>
</ul>
For this I have added code in component .ts file
export class CategoriesComponent implements OnInit {
categoryList: Category[];
constructor(private categoryservice: CategoriesService) { }
ngOnInit() {
this.categoryList = this.categoryservice.getCategories();
}
}
Please help, I want to create a navbar list of categories, when upon hover it shows the relevant subcategory. Please let me know if you need additional information.
in the inner loop, you should loop over the inner array
<ul>
<li *ngFor="let cat of categoryList">
{{cat.categoryName}}
<ul>
<li *ngFor="let subcat of cat.subcatName">
asdad {{subcat.subcategory}}
</li>
</ul>
</li>
</ul>
Your inner loop should iterate over cat of the parent not categoryList
Change
From
<li *ngFor="let subcat of categoryList">
asdad {{subcat.subcategory}}
</li>
To
<li *ngFor="let subcat of cat.subcatName">
asdad {{subcat.subcategory}}
</li>
I have this dynamic list created with ngFor. When I click on item I want to expand it with new dynamic list, but only for that item. In my following code it expends for every item in the first list. I understand why that is happening, but I don't have ideas how to solve it.
Here is my code
<ul *ngFor="let p of portList">
<li (click)="setONUList(p.name)" id="{{ p.name }}"><img src="app/resources/{{ p['oper-status'] }}.png" class="myimage"/>{{ p.name}}</li>
<ol *ngFor="let onu of portONUList">
<li><img src="app/resources/{{ onu['oper-status'] }}.png" class="myimage" />{{ onu.name}}</li>
</ol>
</ul>
Any ideas how to solve this would be very helpful.
From what I understand, the subarray is the same which is shown for all your items, so there is no relation between the nested array and the outer array.
My suggestion would actually be to add a new property in your array, e.g expanded... so e.g your outer array would look like:
portList = [{id:1,name:'one',expanded:false},{id:2,name:"two",expanded:false}];
And then your HTML:
<ul *ngFor="let p of portList">
<li (click)="expand(p)">{{ p.name}}</li>
<div *ngIf="p.expanded">
<ol *ngFor="let onu of portONUList">
<li>{{ onu.name}}</li>
</ol>
</div>
</ul>
And on click, toggle the expanded property:
expand(p: any) {
p.expanded = !p.expanded;
}
Of course if you want to have a "quick" solution you could rely on HTML5 with no need of the new property:
<details *ngFor="let p of portList">
<summary>{{p.name}}</summary>
<ul *ngFor="let onu of portONUList">
<li>{{ onu.name}}</li>
</ul>
</details>
Here's a plunker with both options.
There should be a relation between parent and childlist and the list should be in json format. Refer below code
<ul>
<li ng-repeat="item in parent" ng-click="showChilds(item)">
<span>{{item.name}}</span>
<ul>
<li ng-repeat="subItem in item.subItems" ng-show="item.active">
<span>{{subItem.name}}</span>
</li>
</ul>
</li>
</ul>
Sample JSON FORMAT
let parent= [
{
name: "Item1",
subItems: [
{name: "SubItem1"},
{name: "SubItem2"}
]
},
{
name: "Item2",
subItems: [
{name: "SubItem3"},
{name: "SubItem4"},
{name: "SubItem5"}
]
},
{
name: "Item3",
subItems: [
{name: "SubItem6"}
]
}
];
I've got the whole questions that I have in my JSON file, but I need only one until the user will click the right answer and go to the next one
HTML template:
<div ng-controller="quizController">
<ul>
<li ng-repeat="q in allData">
<h1 id="question">{{q.question}}</h1>
</li>
</ul>
<div class="answers">
<a class="btn btn-primary"><p>New York</p></a>
<a class="btn btn-warning"><p>Miami</p></a>
<a class="btn btn-success"><p>Washington</p></a>
<a class="btn btn-danger"><p>LA</p></a>
</div>
JS:
app.controller("quizController", function($scope, $http){
$http.get("questions.json")
.then(function(response){
$scope.allData = response.data;
});
});
JSON file:
[
{
"question": "Which is the largest country in the world by population?",
"options": ["India", "USA", "China", "Russia"],
"answer": 2
},
{
"question": "When did the second world war end?",
"options": ["1945", "1939", "1944", "1942"],
"answer": 0
},
{
"question": "Which was the first country to issue paper currency?",
"options": ["USA", "France", "Italy", "China"],
"answer": 3
},
{
"question": "Which city hosted the 1996 Summer Olympics?",
"options": ["Atlanta", "Sydney", "Athens", "Beijing"],
"answer": 0
}
]
You should not use ng-repeat then, since this will just loop through your questions and show them all at once in the UI.
Instead, store your questions array in another variable and then bind your UI to a specific index of that variable.
app.controller("quizController", function($scope, $http){
$scope.allData = [];
//Initially set to first element (question), then you will need to increment in further logic elsewhere probably on a button click handler if the answer is correct
$scope.currentQuestion = $scope.allData[0];
$http.get("questions.json")
.then(function(response){
$scope.allData = response.data;
});
});
This is similar to mindparses approach but goes a little deeper. You can navigate back and forth. It's not full proof but should help you on your way.
HTML
<div ng-app="app" ng-controller="quizController">
<div ng-app="app" ng-controller="quizController">
<p>
<h1 id="question">{{currentQ.question}}</h1>
<div class="answers">
<ul ng-repeat="option in currentQ.options">
<li>{{option}}</li>
</ul>
</div>
</p>
<button ng-click="move(-1)">Previous</button>
<button ng-click="move(1)">Next</button>
</div>
</div>
JS/CONTROLLER
var app = angular.module('app', []);
app.controller("quizController", function ($scope) {
$scope.move = function (direction) {
// you're gonna need an IF block here to stop it from going out of range.
var position = $scope.allData.indexOf($scope.currentQ);
$scope.currentQ = $scope.allData[position + direction];
}
$http.get("questions.json").then(function(response){
$scope.allData = response.data;
$scope.currentQ = $scope.allData[0];
});
});
JSFIDDLE
I'm having a AngularJS spa and want to fetch files from a JSON, which works good so far.
var app = angular.module("MyApp", []);
app.controller("TodoCtrl", function($scope, $http) {
$http.get('todos.json').
success(function(data, status, headers, config) {
$scope.posts = data;
}).
error(function(data, status, headers, config) {
alert("Error");
});
});
and bind it to repeat a list.
<ul ng-repeat="post in posts">
<li>
<b>Name : </b> {{post.name}} <br>
<b>Adress/street :</b> {{post.address.street}}
</li>
</ul>
my problem ist, what if I have nested another object inside the JSON:
"adress": [
{
"street": "somewhat street",
"town": "somewhat town"
}]
My attempt post.adress.street does not work. Any suggestions?
Since address is an array, you have 2 options.
First option:
Use the array notation to access only one of the items in the array. For example:
<ul ng-repeat="post in posts">
<li>
<b>Name : </b> {{post.name}} <br>
<b>Adress/street :</b> {{post.address[0].street}}
</li>
</ul>
Second option:
Iterate over all the address items using another ng-repeat:
<ul ng-repeat="post in posts">
<li>
<b>Name : </b> {{post.name}} <br>
<div ng-repeat="address in post.address">
<b>Adress/street :</b> {{address.street}}
</div>
</li>
</ul>