handlebar - unable to loop through data - javascript

I'm trying to apply the below model to a handlebar template to get a simple list , but I guess
either the data hierarchy or the way I'm trying to loop through the data
model may be incorrect.
data.js
{
"categories":[
{
"games":{
"action":{
"game":{
"name":"Game 1",
"Description":"Description 1"
},
"game":{
"name":"Game 2",
"Description":"Description 2"
}
}
}
},
{
"movies":{
"fantasy":{
"movie":{
"name":"Movie 1",
"Description":"Description 1"
},
"movie":{
"name":"Movie 2",
"Description":"Description 2"
}
}
}
}
]
}
template
<ul id="categories">
<li> Games
<ul class="subcategories">
{{#each categories}}
...........
{{/each}}
</ul>
</li>
</ul>
I'd like to get a simple list (see below)
<ul id="categories">
<li> Games
<ul class="subcategories">
<li> Action
<ul>
<li>Game 1</li>
<li>Game 2</li>
</ul>
</li>
</ul>
</li>
<li> Movies
<ul class="subcategories">
<li> Fantasy
<ul>
<li>Movie 1</li>
<li>Movie 2</li>
</ul>
</li>
</ul>
</li>
</ul>
Any help is greatly appreciated.

Your data structure doesn't really represents your expected output.
The structure should be something like this:
data (object)
categories (array)
category (object)
category name
subcategories (array)
subcategory (object)
subcategory name
items (array)
item (object)
item name
item description
Note: I called the innermost array items instead of games/movies/etc, so it's easier to use it in the template.
You can see my implementation in this jsfiddle.

Related

Add class to element on hover in Vue, without using data

In a Vue-component, I have a menu like this:
<ul class="menu-outer-wrapper">
<li>Foo 1</li>
<li class="has-children">
Foo 2
<ul>
<li>Child 1</li>
<li>Child 2</li>
<li>Child 3</li>
</ul>
</li>
<li>Foo 5</li>
<li class="has-children">
Foo 6
<ul>
<li>Child 1</li>
<li>Child 2</li>
</ul>
</li>
<li>Foo 7</li>
<li>Foo 8</li>
</ul>
And I would like to add the class hovered to the li.has-children-elements upon hover (mouseenter) (to be able to make some nicer animations for the children of that dropdown. And remove that class on mouseleave.
I know that there are options to do this with pure CSS, - but controlling delays and soft fade-in's are a pain (and become very messy very fast, without adding some classes).
I imagined doing something like this:
...
mounted(){
let liWithChildren = document.querySelectorAll( '.menu-outer-wrapper > li.has-children' );
liWithChildren.forEach( (event, window) => {
// Somehow add the class to the hovered element here.
// But I don't know how. Or if it's a good/bad idea (performance-wise).
}
}
But is that the way to go? And can I do it without using data (since the menu is dynamically generated by a CMS-system.
Update 1
I'm trying to keep my markdown readable. So I would like to avoid something like this:
<ul class="menu-outer-wrapper">
<li :class="[ { 'hovered' : someVar } ]">
Foo 1
</li>
<li :class="[ { 'hovered' : someVar }, 'has-children' ]">
Foo 2
<ul>
<li>Child 1</li>
<li>Child 2</li>
<li>Child 3</li>
</ul>
</li>
<li :class="[ { 'hovered' : someVar } ]">
Foo 2
</li>
...
...
...
Both since it won't gel with the dynamically generated menu.
And also since it add a lot of noise to the markdown.
Update 2
I simplified the example, to make it easier to digest. But due to the comments I figured I would elaborate on the dynamic generated menu. I'm making it something like this:
<nav id="secondary-menu" v-if="secondaryMenu">
<ul>
<li
:class="[ { 'has-children': r.children } ]"
v-for="(r, r_key, r_index) in secondaryMenu">
<a :href="r.url" :title="r.title">
{{ r.title }}
</a>
<ul class="children" v-if="r.children">
<li v-for="(c1, c1_key, c1_index) in r.children">
<a :href="c1.url" :title="c1.title">
{{ c1.title }}
</a>
</li>
</ul>
</li>
</ul>
</nav>
You just need the #mouseenter and #mouseleave events. All you need to do is listen for the appropriate events on all list-items that could have children, then perform your class addition (or removal) if the target element has the class of "has-children". Here's how I would do it:
<template>
<nav id="secondary-menu" v-if="secondaryMenu">
<ul>
<li
:class="[{ 'has-children': r.children }]"
v-for="(r, r_key, r_index) in secondaryMenu"
:key="`${r_key}-${r_index}`"
#mouseenter="addClass"
#mouseleave="removeClass"
>
<a :href="r.url" :title="r.title">
{{ r.title }}
</a>
<ul class="children" v-if="r.children">
<li
v-for="(c1, c1_key, c1_index) in r.children"
:key="`${c1_key}-${c1_index}`"
>
<a :href="c1.url" :title="c1.title">
{{ c1.title }}
</a>
</li>
</ul>
</li>
</ul>
</nav>
</template>
<script>
export default {
name: "HoverNav",
props: {
secondaryMenu: {
type: Array,
required: true,
},
},
methods: {
addClass: function (e) {
if (e.target.classList.contains("has-children")) {
e.target.classList.add("hovered");
}
},
removeClass: function (e) {
if (e.target.classList.contains("has-children")) {
e.target.classList.remove("hovered");
}
},
},
};
</script>
Here's a very unaesthetic sandbox of this in action. Let me know if this works for you :)
https://codesandbox.io/s/headless-brook-ysq97?file=/src/components/HoverNav.vue:0-1169

How to get the text of the top most parent of list item in jquery?

I have following design of a ul list.
<ul>
<li class="category">
Design
<ul>
<li>Graphic Design</li>
<li>Web Design </li>
<li>HTML</li>
<li>CSS</li>
<li>Print</li>
</ul>
</li>
<li class="category">
Development
<ul>
<li>PHP</li>
<li>Java</li>
</ul>
</li>
</ul>
Now what I want is if you click on the "CSS" item ,I want to get the text of its parent i.e "Design".
I have tried the following code but I got the whole list in it.
$('ul').on("click", "li", function (e) {
console.log("Child Clicked: "+$(this).text()+" Parent: "+$(this).parents(".category").text());
});
Try replacing this part
$(this).parents(".category").text()
with
$(this).parents(".category")[0].childNodes[0].textContent;
childNodes returns all the child elements including text nodes.
If you want to use jQuery only, then wrap this textnode inside a span
<ul>
<li class="category">
<span>Design</span>
<ul>
<li>Graphic Design</li>
<li>Web Design </li>
<li>HTML</li>
<li>CSS</li>
<li>Print</li>
</ul>
</li>
<li class="category">
<span>Development</span>
<ul>
<li>PHP</li>
<li>Java</li>
</ul>
</li>
</ul>
and fetch that first node's text using
$(this).parents(".category span").html()
Another approach could be to use contents and filter of jquery
$(this).parents(".category").contents().filter(function() {
return this.nodeType == 3;
}).nodeValue;
just change :
console.log("Child Clicked: "+$(this).text()+" Parent: "+$(this).parents(".category").text());
with :
console.log("Child Clicked: "+$(this).text()+" Parent: "+$(this).parent().text());

Loop through an array from JSON using Angular JS

I am trying to loop through an array from JSON and display the contents more like a side menu. I wrote something like
<ul ng-repeat="(key, value) in menuList.Menu">
<li>{{key}}</li>
<ul ng-repeat="(key, value) in value">
<li> {{key}}</li> //second key
<ul ng-repeat="(key, value) in value">
<li> {{key}}</li>
<ul ng-repeat="(key, value) in value">
<li> {{key}} : {{value}}</li>
</ul>
</ul>
</ul>
</ul>
The problem is my second key has both object and array. How do I display the value of Object and loop/ng-repeat just through the array. I cannot modify it with this as it will display the entire content of the array.
<li> {{key}} : {{value}}</li>
A part of my JSON for better understanding is given below:
{
"class": 99,
"mode" : 0,
"Menu": [{
"MenuNum": 1,
"MenuItems": [{
"ItemNum": 0,
"ItemDesc": "Main Menu",
"ActionCode": "-",
"ActionInst": ""
} , {
"ItemNum": 1,
"ItemDesc": "BBQ",
"ActionCode": "M",
"ActionInst": "0992"
}, {
"ItemNum": 2,
"ItemDesc": "Beverages",
"ActionCode": "M",
"ActionInst": "0992"
}]
},{
"MenuNum": 2,
"MenuItems": [{
"ItemNum": 0,
"ItemDesc": "Sub Menu",
"ActionCode": "-",
"ActionInst": ""
}, {
"ItemNum": 1,
"ItemDesc": "BBQTYPE1",
"ActionCode": "P",
"ActionInst": "0996"
}, {
"ItemNum": 2,
"ItemDesc": "BeveragesTYPE1",
"ActionCode": "P",
"ActionInst": "0998"
}]
}]
}
I want the sidebar more like
Presuming at the moment that you just want the ng-repeat logic, this may be what you are looking for:
<ul ng-repeat="topMenu in menuList.Menu">
<li>
{{$index}}
<ul>
<li>
MenuNum: {{topMenu.MenuNum}}
</li>
<li> MenuItems
<ul ng-repeat="submenu1 in topMenu.MenuItems">
<li>
{{$index}}
<ul>
<li>ItemNum: {{submenu1.ItemNum}}</li>
<li>ItemDesc: {{submenu1.ItemDesc}}</li>
<li>ActionCode: {{submenu1.ActionCode}}</li>
<li>ActionInst: {{submenu1.ActionInst}}</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
If you then want a relatively easy way to do the menu opening/closing, you would probably want to put all this into an Angular accordion. I can probably help you with that if you want.
It looks like you're trying to create a list with nested children. How about a recursive pattern which uses ng-include recursively to display all the nested children? Something like this:
<script type="text/ng-template" id="menuTree">
{{ menuItem.name }}
<ul ng-if="menuItem.children">
<li ng-repeat="menuItem in menuItem.children" ng-include="'menuTree'"></li>
</ul>
</script>
<ul>
<li ng-repeat="menuItem in menuItems" ng-include="'menuTree'"></li>
</ul>
I'm using a slightly different data structure to your code, but you should get the idea. Here's a demo: http://jsfiddle.net/mmmxh8kq/
EDIT:
If the data is as simple as the JSON you posted and you don't need a recursive menu, you could just try this:
<ul>
<li ng-repeat="menus in menuList.Menu">
{{ menus.MenuNum }}
<ul>
<li ng-repeat="menuItems in menus.MenuItems">
{{ menuItems.ItemDesc }}
</li>
</ul>
</li>
</ul>
Demo: http://jsfiddle.net/n4mo80od/

AngularJS: How to display nested objects?

I have following (json) object:
[
{
name: "Foo",
children: [{
name: "bar",
children:[{
...
}]
}]
}
]
There can be any number of children/objects in any level. Now I want to get following HTML Code:
<ul>
<li>Foo</li>
<li>
<ul>
<li>Bar</li>
</ul>
</li>
<ul>
But of course there could be 10 or more levels with 20 or more children per level.
Is there any way to do that? Thank you very much!
this should work, just replace json array with your data
<script type="text/ng-template" id="nodes_renderer.html">
{{node.name}}
<ul ng-model="node.children" ng-class="{hidden: collapsed}">
<li ng-repeat="node in node.children" ng-include="'nodes_renderer.html'">
</li>
</ul>
</script>
<div data-drag-enabled="false">
<ul>
<li ng-repeat="node in #*JSON ARRAY*#" ng-include="'nodes_renderer.html'">
</li>
</ul>
</div>

Using angular to turn a multi-dimensional array into a multi list

js` and I would like to repeat an array into a list
From this:
This is in the Service:
var Response= [
["Article One"],
["Article Two"],
["Article Three"],
["Article Images", ["Images 1", "Images 2", "Images 3"] ],
["Article Five"]
];
And calling the Object from the Controller:
$scope.Response = function () {
return ArtikelSucheService.Response;
};
I want to repeat it like this:
<ul ng-repeat="Article in Response()">
<li>Article One</li>
<li>Article Two</li>
<li>Article Three</li>
<li>Images
<ul ng-repeat="What must stay here?">
<li>Images 1</li>
<li>Images 2</li>
<li>Images 3</li>
</ul>
</li>
<li>Article Five</li>
</ul>
I don't know, how can I repeat an array in an array.
Response is an array. And in Response there are x images.
1 article can have many images.
Can anybody help me out?
May be like following?
<ul>
<li ng-repeat="Article in Response()">
{{ Article[0] }}
<ul ng-show="Article[1]">
<li ng-repeat="img in Article[1]">{{ img }}</li>
</ul>
</li>
</ul>
var Response1= [
["Article One"],
["Article Two"],
["Article Three"],
["Article Images", ["Images 1", "Images 2", "Images 3"] ],
["Article Five"]
];
and in html use below template
<ul>
<li ng-repeat='option in responses1'>
{{option[0]}}
<ul>
<li ng-repeat='suboption in option[1]'>{{suboption}}</li>
</ul>
</li>
</ul>
working fiddle
http://jsfiddle.net/jw5Qf/1/

Categories

Resources