Angularjs nested ng-repeat linking back to object - javascript

I have an object like so:
$scope.group = {
"Jim Jenkins": {
"Blue": {
"Circle": [
"Item1",
"Item2",
"Item3"
]
}
},
"Rachel Smith": {
"Blue": {
"Circle": [
"Item 1"
]
},
"Red": {
"Circle": [
"Item 1",
"Item 2"
]
}
}
}
I created a nested ng-repeat function that cycles through the object and displays it.
<script type="text/ng-template" id="group.html">
<ul style="padding:10px;">
<li type="none" ng-repeat="(i, c) in group">
<div ng-click="test(i)" style="background-color:#fff;padding:5px;" ng-if="i.length > 0">{{ i }}</div>
<div ng-click="test(c)" style="background-color:#fff;padding:5px;margin-bottom:5px;" ng-if="!i.length">{{ c }}</div>
<div ng-switch on="i.length > 0">
<div ng-switch-when="true">
<div ng-init="group = c;" ng-include="'group.html'"></div>
</div>
</div>
</li>
</ul>
</script>
<div ng-include="'group.html'" ng-model="group"></div>
My only issue is, now I have now way of linking back to the original $scope.group object. I have a ng-click where I display the items and I'd like to be able to know where this element is located (so I know what the parent is, know how many levels in, add more items, etc).
Does anyone know how I can achieve this?

Try like this
var app = angular.module("app", []);
app.controller('mainCtrl', function($scope) {
$scope.isArray = angular.isArray;
$scope.group = [{
"Jim Jenkins": {
"Blue": {
"Circle": [
"Item1",
"Item2",
"Item3"
]
}
},
"Rachel Smith": {
"Blue": {
"Circle": [
"Item 1"
]
},
"Red": {
"Circle": [
"Item 1",
"Item 2"
]
}
}
}]
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.2/css/font-awesome.min.css" rel="stylesheet" />
<div ng-app="app" ng-controller="mainCtrl">
<script type="text/ng-template" id="dummy.html">
<ul>
<li ng-repeat="(k,v) in group">
<div ng-include=" 'nested.html' " onload="group = v"></div>
</li>
</ul>
</script>
<script type="text/ng-template" id="nested.html">
<div ng-repeat="(k1,v1) in v">{{k1}}
<ul>
<li ng-if="isArray(v1)" ng-repeat="val in v1">
{{val}}
</li>
</ul>
<li ng-if="!isArray(v1)" >
<div ng-include=" 'dummy.html' " onload="group = v1"></div>
</li>
</div>
</script>
<div ng-include=" 'dummy.html'"></div>
</div>

Related

ng repeat with <li> within a <td>

I am trying to put a list li inside a row of a table using ng repeat.
My code below of what I am trying to achieve:
<td>
<div ng-repeat="x in total.count">
<ul>
<li>
{{x.key}}
</li>
</ul>
</div>
</td>
A sample of total:
"total": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"count": [
{
"key": "0",
"doc_count": 83714
},
{
"key": "1",
"doc_count": 11034
}
The issue is that nothing is appearing. But when I hard code the li, it works.
Can somebody advise me on how to do it in angularjs using ng-repeat ?
Try this:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.object = {"total": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"count": [
{
"key": "0",
"doc_count": 83714
},
{
"key": "1",
"doc_count": 11034
}]
}};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<table border=1>
<tr>
<td>
<ul>
<li ng-repeat="x in object.total.count">
{{x.key}}
</li>
</ul>
</td>
</tr>
</table>
</div>
Try and use the ng-repeat on the li element, the ng-repeat makes a "copy" of the element its placed in. So this will repeat the list item element.
<td>
<ul>
<li ng-repeat="x in total.count">
{{x.key}}
</li>
</ul>
</td>
You are repeating a list with one element, not the element itself

Add Prev/Next buttons in multiple items array in AngularJS (ngRepeat)

I want to create a multiple items slider to list some players using ng-repeat (Angular 1.6). I'd like to add a prev/next buttons in the ul>lis to access the next or previous player in the array, shifting the view item by item.
HTML----sliderdemo.html
<div ng-controller="SliderDemoCtrl">
<div class="champions-slider">
<ul class="team-members list-inline text-center" style="display:flex" >
<li ng-repeat="player in players | limitTo: 4" style="padding:10px">
<div class="img-holder">
<img ng-src="{{ player.image }}" alt="{{player.name}}" width="20px">
</div>
<strong class="name">{{ player.name }}</strong>
</li>
</ul>
Prev
Next
</div>
</div>
My controller js---slider.demo.controller.js
var myApp = angular.module('slider.demo', []);
myApp.controller('SliderDemoCtrl',['$scope',function($scope){
$scope.players = [
{
image:"http://placehold.it/500/e499e4/fff&text=1",
name: "tes 1"
},
{
image:"http://placehold.it/500/e499e4/fff&text=2",
name: "tes 2"
},
{
image: "http://placehold.it/500/e499e4/fff&text=3",
name: "tes 3"
},
{
image:"http://placehold.it/500/e499e4/fff&text=4",
name: "tes 4"
},
{
image:"http://placehold.it/500/e499e4/fff&text=5",
name: "tes 5"
},
{
image: "http://placehold.it/500/e499e4/fff&text=3",
name: "tes 6"
}
];
}]);
Here is a plunkr of the question: https://plnkr.co/edit/J7dxeMfM22ju5gpZl5ri?p=preview
Any help would be greatly appreciated.
Thx!
I think you are searching like below solution :
// Code goes here
var myApp = angular.module('slider.demo', []);
myApp.controller('SliderDemoCtrl',['$scope',function($scope){
$scope.players = [
{
image:"http://placehold.it/500/e499e4/fff&text=1",
name: "tes 1"
},
{
image:"http://placehold.it/500/e499e4/fff&text=2",
name: "tes 2"
},
{
image: "http://placehold.it/500/e499e4/fff&text=3",
name: "tes 3"
},
{
image:"http://placehold.it/500/e499e4/fff&text=4",
name: "tes 4"
},
{
image:"http://placehold.it/500/e499e4/fff&text=5",
name: "tes 5"
},
{
image: "http://placehold.it/500/e499e4/fff&text=3",
name: "tes 6"
},
];
$scope.size=0;
$scope.next=function(){
if($scope.size+4==$scope.players.length)
return;
$scope.size+=1;
}
$scope.prev=function(){
if($scope.size==0)
$scope.size=0;
else
$scope.size-=1;
}
}]);
<!doctype html>
<html ng-app="slider.demo">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js"></script>
<script src="script.js"></script>
</head>
<body>
<div ng-controller="SliderDemoCtrl">
<div class="champions-slider">
<ul class="team-members list-inline text-center" style="display:flex" >
<li ng-repeat="player in players | limitTo: 4" style="padding:10px">
<div class="img-holder">
<img ng-src="{{ players[$index+val].image }}" alt="{{players[$index+val].name}}" width="20px">
</div>
<strong class="name">{{ players[$index+size].name }}</strong>
</li>
</ul>
Prev
Next
</div>
</div>
</body>
</html>
You can handle the pagination by ng-if using a $index.Just go through Plunker
$scope.pre = 0;
$scope.nex = 4;
$scope.nextItem = function(){
$scope.pre = $scope.nex;
$scope.nex = $scope.nex + 4;
}
$scope.prevItem = function(){
$scope.nex = $scope.pre
$scope.pre = $scope.pre - 4;
}

AngularJS ng-repeat Post Value not getting in proper pattern using id as key

I'm new in AngularJS I want to get post value in proper format. When I use
field name as key in checkbox it gives proper value but when I use id as key it does't.
Given below code with name as key
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope) {
$scope.mainMenu = {};
$scope.submenu = {};
$scope.pagemenu ={};
$scope.menu = {};
$scope.menus = [
{"menuID":"11","sub_menu":"N","name":"dashboard","sub_menus":""},
{"menuID":"1","sub_menu":"Y","name":"settings","sub_menus":[{"sub_menuID":"1","name":"settings1","page":"Y","pages":[{"pageID":"1","name":"page1"},{"pageID":"2","name":"page2"}]},{"sub_menuID":"2","name":"settings2","page":"N","pages":""}]},
{"menuID":"2","sub_menu":"Y","name":"help","sub_menus":[{"sub_menuID":"3","name":"help1","page":"N","pages":""},{"sub_menuID":"4","name":"help2","page":"N","pages":""}]},
{"menuID":"3","sub_menu":"Y","name":"contact","sub_menus":[{"sub_menuID":"5","name":"contact1","page":"N","pages":""},{"sub_menuID":"6","name":"contact2","page":"N","pages":""}]}
];
$scope.assignValue = function(menuId,submenuId,pageId){
/* if(!$scope.mainMenu[menuId]&&!$scope.submenu[menuId]&&!$scope.pagemenu[menuId]){
delete($scope.mainMenu[menuId]);
delete($scope.submenu[menuId]);
delete($scope.pagemenu[menuId]);
} */
$scope.menu=Object.assign({},$scope.mainMenu, $scope.submenu,$scope.pagemenu);
console.log($scope.menu);
}
$scope.submit = function(){
// alert(JSON.stringify($scope.menu));
console.log(JSON.stringify($scope.menu));
console.log($scope.menu);
}
});
<!DOCTYPE html>
<html>
<head>
<title>rules</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.3/angular.min.js"></script>
<script src="mainCtrl.js"></script>
</head>
<body ng-app="app">
<div ng-controller="MainCtrl">
<form ng-submit="submit()">
<ul>
<li ng-repeat="x in menus">
<input type="checkbox" ng-change= "assignValue(x.menuID)" ng-model="mainMenu[x.name]" ng-true-value="'{{x.menuID}}'">{{x.name}}
<ul ng-if="[x.sub_menu] == 'Y'">
<li ng-repeat="subMenu in x.sub_menus">
<input type="checkbox" ng-model="submenu[x.name][subMenu.name]" ng-true-value="'{{subMenu.sub_menuID}}'" ng-change= "assignValue(x.menuID,subMenu.sub_menuID,null)">{{subMenu.name}}
<ul ng-if="[subMenu.page] == 'Y'">
<li ng-repeat="page in subMenu.pages">
<input type="checkbox" ng-model="pagemenu[x.name][subMenu.name][page.name]" ng-true-value="'{{page.pageID}}'" ng-change= "assignValue(x.menuID,subMenu.sub_menuID,page.pageID)">{{page.name}}
</li>
</ul>
</li>
</ul>
</li>
</ul>
<button>Submit</button>
</form>
</div>
</body>
</html>
And the code with id as key
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope) {
$scope.mainMenu = {};
$scope.submenu = {};
$scope.pagemenu ={};
$scope.menu = {};
$scope.menus = [
{"menuID":"11","sub_menu":"N","name":"dashboard","sub_menus":""},
{"menuID":"1","sub_menu":"Y","name":"settings","sub_menus":[{"sub_menuID":"1","name":"settings1","page":"Y","pages":[{"pageID":"1","name":"page1"},{"pageID":"2","name":"page2"}]},{"sub_menuID":"2","name":"settings2","page":"N","pages":""}]},
{"menuID":"2","sub_menu":"Y","name":"help","sub_menus":[{"sub_menuID":"3","name":"help1","page":"N","pages":""},{"sub_menuID":"4","name":"help2","page":"N","pages":""}]},
{"menuID":"3","sub_menu":"Y","name":"contact","sub_menus":[{"sub_menuID":"5","name":"contact1","page":"N","pages":""},{"sub_menuID":"6","name":"contact2","page":"N","pages":""}]}
];
$scope.assignValue = function(menuId,submenuId,pageId){
/* if(!$scope.mainMenu[menuId]&&!$scope.submenu[menuId]&&!$scope.pagemenu[menuId]){
delete($scope.mainMenu[menuId]);
delete($scope.submenu[menuId]);
delete($scope.pagemenu[menuId]);
}*/
$scope.menu=Object.assign({},$scope.mainMenu, $scope.submenu,$scope.pagemenu);
console.log($scope.menu);
}
$scope.submit = function(){
// alert(JSON.stringify($scope.menu));
console.log(JSON.stringify($scope.menu));
console.log($scope.menu);
}
});
<!DOCTYPE html>
<html>
<head>
<title>rules</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.3/angular.min.js"></script>
<script src="mainCtrl.js"></script>
</head>
<body ng-app="app">
<div ng-controller="MainCtrl">
<form ng-submit="submit()">
<ul>
<li ng-repeat="x in menus">
<input type="checkbox" ng-change= "assignValue(x.menuID)" ng-model="mainMenu[x.menuID]" ng-true-value="'{{x.menuID}}'">{{x.name}}
<ul ng-if="[x.sub_menu] == 'Y'">
<li ng-repeat="subMenu in x.sub_menus">
<input type="checkbox" ng-model="submenu[x.menuID][subMenu.sub_menuID]" ng-true-value="'{{subMenu.sub_menuID}}'" ng-change= "assignValue(x.menuID,subMenu.sub_menuID,null)">{{subMenu.name}}
<ul ng-if="[subMenu.page] == 'Y'">
<li ng-repeat="page in subMenu.pages">
<input type="checkbox" ng-model="pagemenu[x.menuID][subMenu.sub_menuID][page.pageID]" ng-true-value="'{{page.pageID}}'" ng-change= "assignValue(x.menuID,subMenu.sub_menuID,page.pageID)">{{page.name}}
</li>
</ul>
</li>
</ul>
</li>
</ul>
<button>Submit</button>
</form>
</div>
</body>
</html>
I executed your code and compared the results. The only difference that I figured out was of the order you wants the key to be in.
In json, there is no meaning of ordering keys. Moreover your keys are numbers so they are arranged in an ascending order.
It's the way v8 handles associative arrays. A known issue Issue 164 but it follows the spec so is marked 'working as intended'. There isn't a required order for looping through associative arrays.
A simple workaround is to precede number values with letters e.g: 'size_7':['9149','9139'] etc.
The standard will change in the next ECMAScript spec forcing [chrome] developers to change this.
So nothing to worry about the order. You can access it with the keys as that is how json is to be used.
If you need order then you need some dirty hacky ways to do it which will either force you to rename your keys to something else or to create sub-objects of json.
For your case, the hacky way is to add _ before all your menuIds except 11
This will make you menus array look like below
$scope.menus = [
{"menuID":"11","sub_menu":"N","name":"dashboard","sub_menus":""},
{"menuID":"_1","sub_menu":"Y","name":"settings","sub_menus":[{"sub_menuID":"1","name":"settings1","page":"Y","pages":[{"pageID":"1","name":"page1"},{"pageID":"2","name":"page2"}]},{"sub_menuID":"2","name":"settings2","page":"N","pages":""}]},
{"menuID":"_2","sub_menu":"Y","name":"help","sub_menus":[{"sub_menuID":"3","name":"help1","page":"N","pages":""},{"sub_menuID":"4","name":"help2","page":"N","pages":""}]},
{"menuID":"_3","sub_menu":"Y","name":"contact","sub_menus":[{"sub_menuID":"5","name":"contact1","page":"N","pages":""},{"sub_menuID":"6","name":"contact2","page":"N","pages":""}]}
];
and this will provide you with the desired output of 11 to be the first element and _1,_2 and _3 following it.
Here is the code snippet.
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope) {
$scope.mainMenu = {};
$scope.submenu = {};
$scope.pagemenu = {};
$scope.menu = {};
$scope.menus = [{
"menuID": "11",
"sub_menu": "N",
"name": "dashboard",
"sub_menus": ""
},
{
"menuID": "_1",
"sub_menu": "Y",
"name": "settings",
"sub_menus": [{
"sub_menuID": "1",
"name": "settings1",
"page": "Y",
"pages": [{
"pageID": "1",
"name": "page1"
}, {
"pageID": "2",
"name": "page2"
}]
}, {
"sub_menuID": "2",
"name": "settings2",
"page": "N",
"pages": ""
}]
},
{
"menuID": "_2",
"sub_menu": "Y",
"name": "help",
"sub_menus": [{
"sub_menuID": "3",
"name": "help1",
"page": "N",
"pages": ""
}, {
"sub_menuID": "4",
"name": "help2",
"page": "N",
"pages": ""
}]
},
{
"menuID": "_3",
"sub_menu": "Y",
"name": "contact",
"sub_menus": [{
"sub_menuID": "5",
"name": "contact1",
"page": "N",
"pages": ""
}, {
"sub_menuID": "6",
"name": "contact2",
"page": "N",
"pages": ""
}]
}
];
$scope.assignValue = function(menuId, submenuId, pageId) {
$scope.menu = Object.assign({}, $scope.mainMenu, $scope.submenu, $scope.pagemenu);
console.log($scope.menu);
}
$scope.submit = function() {
console.log(JSON.stringify($scope.menu));
console.log($scope.menu);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="app">
<div ng-controller="MainCtrl">
<form ng-submit="submit()">
<ul>
<li ng-repeat="x in menus">
<input type="checkbox" ng-change="assignValue(x.menuID)" ng-model="mainMenu[x.menuID]" ng-true-value="'{{x.menuID}}'">{{x.name}}
<ul ng-if="[x.sub_menu] == 'Y'">
<li ng-repeat="subMenu in x.sub_menus">
<input type="checkbox" ng-model="submenu[x.menuID][subMenu.sub_menuID]" ng-true-value="'{{subMenu.sub_menuID}}'" ng-change="assignValue(x.menuID,subMenu.sub_menuID,null)">{{subMenu.name}}
<ul ng-if="[subMenu.page] == 'Y'">
<li ng-repeat="page in subMenu.pages">
<input type="checkbox" ng-model="pagemenu[x.menuID][subMenu.sub_menuID][page.pageID]" ng-true-value="'{{page.pageID}}'" ng-change="assignValue(x.menuID,subMenu.sub_menuID,page.pageID)">{{page.name}}
</li>
</ul>
</li>
</ul>
</li>
</ul>
<button>Submit</button>
</form>
</div>
</body>

Splicing array nested within ng-repeat,

The array is structured like so
$scope.structure = {
sections: [{
id:0,
sectionItems: []
},{
id:1,
sectionItems: []
},{
id:2,
sectionItems: []
}]
};
I have a nested ng-repeat so I can show items within sectionItems[]
(Inside should be objects and one of the keys is Name - not relevant)
<div ng-repeat="sections in structure.sections" class="col-md-12">
<div class="panel panel-info">
<ul class="screenW-section">
<li class="col-xs-6" ng-repeat="item in sections.sectionItems"
ng-click="item.splice($index, 1)">
{{item.Name}}
</li>
</ul>
</div> </div>
I want to be able to remove items on click but the
ng-click="item.splice($index, 1)
Is not working no matter how I format it.
try this:
var app = angular.module("testApp", []);
app.controller('testCtrl', function($scope){
$scope.structure = {
sections: [{
id:0,
sectionItems: ['1','2','3']
},{
id:1,
sectionItems: ['11','21','32']
},{
id:2,
sectionItems: ['12','22','32']
}]
};
$scope.remove = function(sectionItems,index){
sectionItems.splice(index, 1);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="testApp" ng-controller="testCtrl">
<div ng-repeat="sections in structure.sections" class="col-md-12">
<div class="panel panel-info">
<ul class="screenW-section">
<li class="col-xs-6" ng-repeat="item in sections.sectionItems"
ng-click="remove(sections.sectionItems,$index)">
{{item}}
</li>
</ul>
</div> </div>
</div>
To remove an item you need to remove it from the array.
So, for example, you could do
ng-click="remove(sections.sectionItems, $index)"
in the view, and
$scope.remove = function(array, index) {
array.splice(index, 1);
}
in the controller...
You're calling splice on the item and not the array
ng-click="sections.sectionItems.splice($index, 1)"

Angular ui-tree and accept callback for restricting nodes?

I'm using : https://github.com/angular-ui-tree/angular-ui-tree
I want to accept:
Categories to root scope of ui-tree
apps to the apps of same categories.
My controller is (partial):
//Accept Categories at root scope and accept apps only inside same category
$scope.options = {
accept: function(sourceNodeScope, destNodesScope, destIndex) {
//todo check nodes and return
alert('called');
$log.debug("sourceNodeScope");
$log.debug(sourceNodeScope);
$log.debug("destNodesScope");
$log.debug(destNodesScope);
return false;
},
dropped: function(event) {
},
beforeDrop: function(event) {
}
};
My HTML is:
<div ng-controller="CpoTreeViewCtrl">
<div>
<script type="text/ng-template" id="apps_renderer.html">
<div ui-tree-handle>
{{app.name}}
</div>
</script>
<script type="text/ng-template" id="category_renderer.html">
<div ui-tree-handle >
{{category.name}}
</div>
<ol ui-tree-nodes ng-model="category.apps">
<li ng-repeat="app in category.apps" ui-tree-node ng-include="'apps_renderer.html'">
</li>
</ol>
</script>
<div ui-tree="options">
<ol ui-tree-nodes ng-model="treeData" id="tree-root">
<li ng-repeat="category in treeData" ui-tree-node ng-include="'category_renderer.html'"></li>
</ol>
</div>
</div>
</div>
I want to accept:
Categories to root scope of ui-tree
apps to the apps of same categories.
The accept callback is not getting fired. What's not right here?
Thanks!
If anyone is wondering how to restrict by groups, here's how I got it working. The docs leave a bit to be desired on how to do this.
here is the html markup
<div ng-repeat="list in lists" >
<div ui-tree="treeOptions" class="col-xs-6" >
<ol ui-tree-nodes ng-model="list.categories" data-type="{{list.type}}">
<li ng-repeat="item in list.categories" ui-tree-node data-type="{{item.type}}">
<div ui-tree-handle class="tree-node">
<div class="tree-node-content">
{{item.name}}
</div>
</div>
</li>
</ol>
</div>
<div class="clearfix" ng-if="::$index===1"></div>
</div>
for a sample item array such as
$scope.lists = [{
"name": "Selected Charts",
"type": "charts",
"categories": [{
"name": "222 docs",
"type": "charts"
}]
}, {
"name": "sdf",
"type": "tables",
"categories": [{
"name": "2222 docs",
"type": "tables"
}]
}];
then in tree options, define
$scope.treeOptions = {
accept: function(sourceNodeScope, destNodesScope, destIndex) {
var srctype = sourceNodeScope.$element.attr('data-type');
var dsttype = destNodesScope.$element.attr('data-type');
if(srctype===dsttype){
return true;
}else{
return false;
}
}
};
That will prevent non-matching types from dropping.
The API of this awesome package is updated and same was not available in doc/demo.
Details : https://github.com/angular-ui-tree/angular-ui-tree/pull/281
Quick Fix :
<div ui-tree="options">
should be replaced with
<div ui-tree callbacks="options">
Update (with thanks to #zach-l)
After v2.8.0 you need to switch back to
<div ui-tree="options">
I would do this.
accept: function(sourceNodeScope, destNodesScope) {
return sourceNodeScope.$parent.$id === destNodesScope.$id;
}

Categories