AngularJS multi dimension array calling ng-repeat - javascript

I am trying to get the inner array of the array main in side_menu_angular.js. The first part of the array, i am able to detect it and it works. From the second on wards did not work. My structure of my HTML is slightly different which I think it affects the calling of those inner arrays. What have I done wrong here or have I missed out?
Below are my codes:
HTML
<div ng-app="theme" ng-controller="sideController">
<div id="mainSlideout">
<div id="mainSlideMenu">
<ul style="list-style-type: none;">
<li class="active" ng-repeat="main in menuName">
<h3><a class="mainMenuItem" id="photography">{{main.main_menu}}</a></h3>
</li>
</ul>
</div>
</div>
<div id="slideout">
<div id="slideMenu" >
<ul style="list-style-type: none;" >
<li class="active" ng-repeat-start="sub in menuName" ng-repeat="menus in sub.main_content">
<h3><a class="menuItem" id="{{menus.name}}">{{menus.name}}</a></h3>
</li>
<li id="{{subMenu.id}}" class="draggable {{menus.name}}" ng-repeat="subMenu in menus.element" ng-repeat-end>
<img ng-src="{{subMenu.template}}" id="{{subMenu.id}}" />
</li>
</ul>
</div>
</div>
</div>
side_menu_angular.js
angular.module( 'theme' , [
] ).controller('sideController' , function($scope){
$scope.menuName = [
{ main_menu:'Photography' , main_content:[
{ name:'Header' , element:[
{ id:'template1' , template:'wp-content/themes/dynamictheme/img/template/header/template1.png' },
{ id:'template2' , template:'wp-content/themes/dynamictheme/img/template/header/template2.png' }
]
},
{ name:'Content' , element:[
{ id:'template3' , template:'wp-content/themes/dynamictheme/img/template/header/template3.png' }
]
},
{ name:'Footer' , element:[
{ id:'template4' , template:'wp-content/themes/dynamictheme/img/template/header/template4.png' }
]
}]
}];
})
;

The problem lies here.
<li id="{{subMenu.id}}" class="draggable {{menus.name}}" ng-repeat="subMenu in menus.element" ng-repeat-end>
<img ng-src="{{subMenu.template}}" id="{{subMenu.id}}" />
</li>
You have used subMenu in menus.element but menus is not available to this ng-repeat. Only sub is available here as it lies within the ng-repeat-start block.
Here is a good solution which explains about nesting ng-repeat-starts which seems like a nice solution.

Related

getting last item in an each() loop

I'm struggling to understand how to get the last item in an each() loop. I asked a question last week on this topic, which can be seen here: .find() relationship with loops, each() and this keyword - .find() returning 4 when it should only be 2
The original requirement was to check a series of uls inside uls, and if there were more than 1 lists I need to add a class. Now - I need to build upon this code where if there are more than three lists inside a div, or it is the last ul in a series, I need to add a class to the last ul as well.
I did research on the topic and will be referencing this answer: Last element in .each() set
For reference, the first sample case is below:
$(function(e) {
var getMenuItems = $(".item");
getMenuItems.each(function( index ) {
if ($(this).find("ul.sub-menu").length > 0) {
$(this).addClass("red");
}
});
});
.red {background-color: red;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li class="item">
<ul class="sub-menu">
<li></li>
</ul>
</li>
<li class="item">
</li>
<li class="item">
<ul class="sub-menu">
<li></li>
</ul>
</li>
<li class="item">
</li>
</ul>
This code just checks if there are more than 1 lists inside a div and if there are add a class.
Now the next step is to not only add a class to the divs with more than 1 list but the last ul in the series irregardless of amount of lists. The answer Last element in .each() set suggests to simply cross reference index and see if you are at the last item.
The highest upvoted answer says to:
Check index against the length of the set and you're good to go:
That concept integrated into my sample looks like this:
$(function(e) {
var getMenuItems = $(".item");
var howManyListItems = getMenuItems.length;
getMenuItems.each(function( index ) {
if ($(this).find("ul.sub-menu").length > 0) {
$(this).addClass("red");
} else if (index == (howManyListItems.length - 1)) {
console.log($(this));
$(this).addClass("red");
}
});
});
.red {background-color: red;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li class="item">
<ul class="sub-menu">
<li></li>
</ul>
</li>
<li class="item">
</li>
<li class="item">
<ul class="sub-menu">
<li></li>
</ul>
</li>
<li class="item">
</li>
<li class="item">
</li>
<li class="item">
</li>
<li class="item">
</li>
</ul>
The expected/desired behavior is to add the red to the last item but sadly that does not happen.
As can be seen as a troubleshooting measure, console logging this into that conditional returns nothing. So is that not the last item of the array? How would you modify it/target it? What does that conditional represent? Since console logging does nothing, how does one go about troubleshooting this code?
How do you hit the last element in an each loop and modify it's DOM properties?
This is as easy as:
$(function(e) {
$(".sub-menu:last-of-type").last().addClass("red");
});
.red {background-color: red;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li class="item">
<ul class="sub-menu">
<li></li>
</ul>
</li>
<li class="item">
</li>
<li class="item">
<ul class="sub-menu">
<li></li>
</ul>
</li>
<li class="item">
</li>
<li class="item">
</li>
<li class="item">
</li>
<li class="item">
</li>
</ul>

Show value on title from clicked item with jQuery

I am working on a project and facing a problem. It's a jQuery problem and I am not good in jQuery. I want when someone clicked on list item(<ul id="res-menu-filters"><li></li></ul>) the value will change on h3(<h3 id="menu-title-layout-text">Change Value</h3>) tag with the value of div#menu-extend-title (<div id="menu-extend-title">Breakfast</div>).
I tried a jQuery but it's not working.
Below is my html code and jQuery code.
How should i make this work?
Thanks in advance.
<div class="menu-title-layout-change">
<h3 id="menu-title-layout-text">Breakfast</h3>
</div>
<ul id="res-menu-filters">
<li class="filter">Category 1
<div id="menu-extend-title">
Breakfast
</div>
</li>
<li class="filter">Category 2
<div id="menu-extend-title">
Launch
</div>
</li>
<li class="filter">Category 3
<div id="menu-extend-title">
Dinner
</div>
</li>
jQuery code:
jQuery('#restaurant-menu-content-tab').on('click', '#res-menu-filters li', function(e)
{
var value = jQuery('#menu-extend-title').text();
jQuery('#menu-title-layout-text').text(value);
return false;
});
Use common class instead if you used duplicated ids
<ul id="res-menu-filters">
<li class="filter">Category 1
<div class="menu-extend-title">
Breakfast
</div>
</li>
<li class="filter">Category 2
<div class="menu-extend-title">
Launch
</div>
</li>
<li class="filter">Category 3
<div class="menu-extend-title">
Dinner
</div>
</li>
jquery
jQuery('#restaurant-menu-content-tab').on('click', '#res-menu-filters li', function(e){
var value = jQuery(this).find('.menu-extend-title').text();
jQuery('#menu-title-layout-text').text(value);
return false;
});
ID of an element must be unique, so need to use class to group similar elements, also in the click handler you need to find the title element which is a descendant of the clicked li
jQuery('#restaurant-menu-content-tab').on('click', '#res-menu-filters li', function(e) {
var value = jQuery(this).find('.menu-extend-title').text();
jQuery('#menu-title-layout-text').text(value);
return false;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="restaurant-menu-content-tab">
<div class="menu-title-layout-change">
<h3 id="menu-title-layout-text">Breakfast</h3>
</div>
<ul id="res-menu-filters">
<li class="filter">Category 1
<div class="menu-extend-title">Breakfast</div>
</li>
<li class="filter">Category 2
<div class="menu-extend-title">Launch</div>
</li>
<li class="filter">Category 3
<div class="menu-extend-title">Dinner</div>
</li>
</ul>
</div>
It doesn't work because of the following issues:
HTML menu-extend-title is an ID. It should be unique for elements.
Change menu-extend-title to class and use .menu-extend-title.
Use the following code:
<li class="filter">Category 1
<div class="menu-extend-title">
Breakfast
</div>
</li>
<li class="filter">Category 2
<div class="menu-extend-title">
Launch
</div>
</li>
<li class="filter">Category 3
<div class="menu-extend-title">
Dinner
</div>
</li>
jQuery('#restaurant-menu-content-tab').on('click', '#res-menu-filters li', function(e) {
var value = jQuery('.menu-extend-title', this).text();
jQuery(this).find('div').text(value);
return false;
});
As arun pointed out, IDs should be unique. You should rather use classname. also you can use current li context to get the required div in it using current clicked context and find selector:
jQuery('#restaurant-menu-content-tab').on('click', '#res-menu-filters li', function(e){
var value = jQuery(this).find('div').text();
jQuery('#menu-title-layout-text').text(value);
return false;
});
Do you mean something like this:
here a better html code:
<div class="menu-title-layout-change">
<h3 class="menu-title-layout-text">Breakfast</h3>
</div>
<ul class="res-menu-filters">
<li class="filter">Category 1
<div class="menu-extend-title">
Breakfast
</div>
</li>
<li class="filter">Category 2
<div class="menu-extend-title">
Launch
</div>
</li>
<li class="filter">Category 3
<div class="menu-extend-title">
Dinner
</div>
</li>
Make sure your html id's are unique!
And this jquery:
$(document).on('click','.res-menu-filters',function(){
$('.menu-title-layout-text').text($(this).find('.menu-extend-title').text());
})

ng-repeat in AngularJS not working when trying to output a multi-dimension array

I have a simple array which i would want to output it on my list. The array of the first dimension of the array works when i called it, But the second one wasn't able to be detect. What have I done wrong here or have I missed anything? Below are my code:
Angular.js
angular.module( 'theme' , [
] ).controller('sideController' , function($scope){
$scope.menuName = [
{'name': 'Header' , 'element' : [
{'id' : 'template1' , 'template': 'wp-content/themes/dynamictheme/img/template/template1.png'}
]
}];
})
;
HTML
<div id="slideout" ng-app="theme">
<div id="slideMenu" ng-controller='sideController'>
<ul style="list-style-type: none;">
<!--- Worked --->
<li class="active" ng-repeat="menus in menuName">
<h3><a class="menuItem" id="{{menus.name}}">{{menus.name}}</a></h3>
</li>
<!--- Didn't Work --->
<li id="{{subMenu.id}}" class="draggable" ng-repeat="subMenu in menus.element">
<img src="{{subMenu.template}}" width="200" />
</li>
</ul>
</div>
</div>
the sub-menus must be inside the outer ng-repeat (replaced with div for simplicity):
<div class="active" ng-repeat="menus in menuName">
<h3><a class="menuItem" id="{{menus.name}}">{{menus.name}}</a></h3>
<div id="{{subMenu.id}}" class="draggable" ng-repeat="subMenu in menus.element">
<img src="{{subMenu.template}}" width="200" />
</div>
</div>
otherwise, there is no menus identifier in scope.

On hover closing specific list element

<ul class="open-close1" id="reportType">
<li class="active">
<div id="subcats">
<ul>
<li>
<img class="loading-spinner" src="store/$vendorSettingsDTO.vendorId/assets/themes/$vendorSettingsDTO.skinname/images/loading.gif" height="18"/>
</li>
</ul>
</div>
</li>
</ul>
<script>
jQuery(document).ready(function($){
jQuery.getJSON('subcat.ajx?vid=$vendorSettingsDTO.vendorId&cid=$catid', function(data) {
//Render subcatergories using Mustache.js (https://github.com/janl/mustache.js)
var subcat_mustache =
'<ul>\
<a style="font-size:14px; font-weight:bold; color:#0073B3;" class="opener"href="{{URL}}">{{description}}</a>\
{{#childs}}\
{{> child}}\
{{/childs}}\
</ul>';
var partials = {
child:
'<li>\
<a class="opener" href="{{URL}}">{{description}}</a>\
<div class="subnav1 hidden">\
<ul>\
{{#childs}}\
{{> child}}\
{{/childs}}\
</ul>\
</div>\
</li>'
}
jQuery("#subcats").html(Mustache.render(subcat_mustache, data, partials));
});
});
</script>
<script>
$(document).ready(function() {
$(".open-close1").hover(function (){
//$(this).children('.subnav1').toggle();
//console.log("$(this).children('.subnav1') "+$(this).children('.subnav1'));
//$(".subnav1", this).toggle();
$(this).find('.subnav1').toggle(); // p00f
});
});
</script>
This is the code I have in case of my category page. I implemented a logic to toggle the block on hover. But entire list of categories is toggling instead of specific list on which it is hovered.
Please help me its IRRITATING me. Thanks a lot for your help in advance.
I assume your rendered html like below;
<ul class="open-close1" id="reportType">
<li class="active">
<div id="subcats">
<ul>
<li>
<a class="opener" href="#">Item1</a>
<div class="subnav1 hidden">
<ul>
<li>Item1-1</li>
<li>Item1-2</li>
<li>Item1-3</li>
</ul>
</div>
</li>
<li>
<a class="opener" href="#">Item2</a>
<div class="subnav1 hidden">
<ul>
<li>Item2-1</li>
<li>Item2-2</li>
<li>Item2-3</li>
</ul>
</div>
</li>
<li>
<a class="opener" href="#">Item3</a>
<div class="subnav1 hidden">
<ul>
<li>Item3-1</li>
<li>Item3-2</li>
<li>Item3-3</li>
</ul>
</div>
</li>
</ul>
</div>
</div>
</li>
</ul>
You can use following js for above html structure;
$(".opener").hover(function (){
$(this).next().toggle();
});
Here is a working demo: http://jsfiddle.net/cubuzoa/EKu2q/
Edit: On your site, category section you mentioned loaded with ajax. So you need to run function after ajax load like below;
<script>
jQuery(document).ready(function($){
jQuery.getJSON('subcat.ajx?vid=$vendorSettingsDTO.vendorId&cid=$catid', function(data) {
//Render subcatergories using Mustache.js (https://github.com/janl/mustache.js)
var subcat_mustache =
'<ul>\
<a style="font-size:14px; font-weight:bold; color:#0073B3;" class="opener"href="{{URL}}">{{description}}</a>\
{{#childs}}\
{{> child}}\
{{/childs}}\
</ul>';
var partials = {
child:
'<li>\
<a class="opener" href="{{URL}}">{{description}}</a>\
<div class="subnav1 hidden">\
<ul>\
{{#childs}}\
{{> child}}\
{{/childs}}\
</ul>\
</div>\
</li>'
}
jQuery("#subcats").html(Mustache.render(subcat_mustache, data, partials));
$(".opener-parent").parent('li').hover(function (){
$(this).find('subnav1').toggle();
});
});
});
</script>
I have also give class name for upper categories as opener-parent and updated js code
Updated demo: http://jsfiddle.net/R9KLz/4/
Final Result: If you do not want to add opener-parent class, you can use following;
$("#subcats ul li").hover(function (){
if ($(this).find('.subnav1').first().find("ul").has("li").length) {
$(this).find('.subnav1').first().toggle();
}
});
Here is a working demo: http://jsfiddle.net/cubuzoa/R9KLz/5/
Something I noticed, I think you have an extra <div> in your list markup.
<ul class="open-close1" id="reportType">
<li class="active">
<div id="subcats">
<ul>
<li><img class="loading-spinner" src="store/$vendorSettingsDTO.vendorId/assets/themes/$vendorSettingsDTO.skinname/images/loading.gif" height="18"/></li>
</ul>
</div>
<!--</div>-->
</li>
</ul>
Also, I just a hunch, but I think you need to be more specific in which element inside of your class you want to talk to. For example, you have this:
$(this).find('.subnav1').toggle();
But I think you need something more along the lines of:
$(this).find('.subnav1 ul').toggle();
Or, if possible, you could give your list(s) some sort of hook to make it even easier to talk to.

AngularJS - ngRepeat with multiple object types

I have a list of items. An item can be a number of things, let's say the list is something like so :
[userObject , vehicleObject , userObject , animalObject , animalObject]
Now I want to render the list with ngRepeat directive that will use a template according to the type of the object (Polymorphic rendering). can this be done?
maybe something like (ng-use is an hypothetically directive):
<ul>
<li ng-repeat="item in items">
<img ng-use="item.type == 'user'" ng-src="item.src">
<a ng-use="item.type == 'vehicle'">{{item.link}}</a>
<span ng-use="item.type == 'animal'">{{item.name}}</span>
</li>
</ul>
<ul>
<li ng-repeat="item in items" ng-switch="item.type">
<img ng-switch-when="user" ng-src="item.src">
<a ng-switch-when="vehicle">{{item.link}}</a>
<span ng-switch-when="animal">{{item.name}}</span>
</li>
</ul>
API reference:
http://docs.angularjs.org/api/ng.directive:ngSwitch
Although this doesn't use ng-switch, it does get round the problem of not having a type field, which #DotNetHaggis pointed out.
<div ng-repeat="field in fields">
<div ng-if="field.user !== undefined">user info</div>
<div ng-if="field.vehicle !== undefined">vehicle info</div>
<div ng-if="field.animal !== undefined">animal info</div>
</div>

Categories