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;
}
Related
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>
How can I use ng-repeat to loop over data that contains many nested array data?
I have data that will have many "Segments"
Example:
confirm.booking.flightData[0].Segments[0].FlightNumber
confirm.booking.flightData[0].Segments[1].FlightNumber
confirm.booking.flightData[0].Segments[2].FlightNumber
I have done both ng-repeat with angular, and without angular I would end up resorting to javascript that loops over data and creates the html dynamically, but I wish to do this the ANGULAR way.. HOW?
HTML with Angular/Javascript Arrays:
<div class="container-fluid">
<div class="row">
<div class="col-md-4">
<span style="font-weight: bold;">Flight</span>
</div>
<div class="col-md-4">
<span style="font-weight: bold;">Departs</span>
</div>
<div class="col-md-4">
<span style="font-weight: bold;">Arrives</span>
</div>
</div>
<div class="row">
<div class="col-md-4">
{{confirm.booking.flightData[0].Segments[0].FlightNumber}}
</div>
<div class="col-md-4">
({{confirm.booking.flightData[0].Segments[0].DepartureAirport}})
</div>
<div class="col-md-4">
({{confirm.booking.flightData[0].Segments[0].ArrivalAirport}})
</div>
</div>
</div>
Nesting can be done in repeats, but repeating too much in ng-repeats can be costly in terms of performance as angular creates scopes for each element repeated. Hence, filtering data till the perfect abstracted values that you need in terms of html should be done in the js file.
For eg: if u need only segements in the html form do this, or if u need even flight data in html form follow #Rachel's post
<ul data-ng-repeat="item in confirm.booking.flightData[0].Segments">
<li>{{ item.FlightNumber}}</li>
</ul>
Let's say your data is in flightdetails, then you can go about it like this:
<div ng-repeat="a in flightdetails ">
<div ng-repeat="b in a.booking">
<div ng-repeat="c in b.flightdata">
<div ng-repeat="d in c.segments">
{{d.flightnumber}}
</div>
</div>
</div>
</div>
You can use nested ng-repeat to bind your data - see a demo below:
angular.module("app", []).controller("ctrl", function($scope) {
$scope.confirm = {
booking: {
flightData: [{
Segments: [{
FlightNumber: 1
}, {
FlightNumber: 2
}]
}, {
Segments: [{
FlightNumber: 3
}, {
FlightNumber: 4
}]
}]
}
}
// console.log($scope.confirm);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="wrapper" ng-app="app" ng-controller="ctrl">
<div ng-repeat="x in confirm.booking.flightData">
Data {{$index + 1}}:
<div ng-repeat="y in x.Segments">
<div>Flight No: {{y.FlightNumber}}</div>
</div>
<br/>
</div>
</div>
If you want to display only the following:
confirm.booking.flightData[0].Segments[0].FlightNumber
confirm.booking.flightData[0].Segments[1].FlightNumber
confirm.booking.flightData[0].Segments[2].FlightNumber
then you can use limitTo - see demo below:
angular.module("app", []).controller("ctrl", function($scope) {
$scope.confirm = {
booking: {
flightData: [{
Segments: [{
FlightNumber: 1
}, {
FlightNumber: 2
}]
}, {
Segments: [{
FlightNumber: 3
}, {
FlightNumber: 4
}]
}]
}
}
// console.log($scope.confirm);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="wrapper" ng-app="app" ng-controller="ctrl">
<div ng-repeat="x in confirm.booking.flightData | limitTo : 1">
Data {{$index + 1}}:
<div ng-repeat="y in x.Segments">
<div>Flight No: {{y.FlightNumber}}</div>
</div>
<br/>
</div>
</div>
I created an example here:
http://codepen.io/ackzell/pen/ENBymo
It ultimately looks like this, but check the pen as it has some more info:
<ul>
<li ng-repeat="flight in vm.flightData">
<ul>
<li ng-repeat="segment in flight.Segments">
<em>FlightNumber</em> {{ segment.FlightNumber }}
<br />
<em>Departure:</em> {{ segment.DepartureAirport }}
<br />
<em>Arrival:</em> {{ segment.ArrivalAirport }}
</li>
</ul>
</li>
</ul>
Nesting ng-repeats would help, but maybe you want to give your data some treatment first.
I want to use angular-drag-and-drop-lists with my own grid template to WYSIWYG editor. How to build my own HTML template without ng-repeat so it will be able to drop items in any predefined column and store information in $scope in which column item has been dropped?
I want to store dropped items in columns array:
.controller('DragDropGrid', ['$scope',
function($scope) {
$scope.layouts = {
selected: null,
templates: [
{name: "Plugin", type: "item", id: 2},
],
columns: [],
oldaproachcolumns: [
"A": [
],
"B": [
]
}
]
};
}
]);
This is currently not a working template. On drop it throws the error "undefined is not an object (evaluating 'targetArray.splice')":
<div ng-include="'grid.html'"></div>
<script type="text/ng-template" id="grid.html">
<div class="col-md-12 dropzone box box-yellow">
<div class="row template-grid" dnd-list="list">
<div class="col-xs-12 col-md-8" ng-repeat="item in list" dnd-draggable="item" ng-include="item.type + '.html'">Header</div>
<div class="col-xs-6 col-md-4">News</div>
</div>
</div>
</script>
<script type="text/ng-template" id="item.html">
<div class="item">Plugin {{item.id}}</div>
</script>
This is the standard working aproach:
<div class="row">
<div ng-repeat="(zone, list) in layouts.oldaproachcolumns" class="col-md-3">
<div class="dropzone box box-yellow">
<h3>{{zone}}</h3>
<div ng-include="'list.html'"></div>
</div>
</div>
</div>
<script type="text/ng-template" id="list.html">
<ul dnd-list="list">
<li ng-repeat="item in list" dnd-draggable="item" dnd-effect-allowed="move" dnd-moved="list.splice($index, 1)" dnd-selected="layouts.selected = item" ng-class="{selected: layouts.selected === item}" ng-include="item.type + '.html'">
</li>
</ul>
</script>
Based on this example: demo
How to build my own HTML template without ng-repeat
Use $templateCache and a for loop as an alternative:
var app = angular.module('foo', []);
function bop(model, data)
{
return data ? model : 'foo';
}
function baz()
{
return bop;
}
function foo($templateCache)
{
var i = 0, len = 5, bar = "";
for (i; i < len; i++)
{
bar = bar.concat("<li>",i,"<p ng-include=\u0022'foo'\u0022></p></li>");
}
$templateCache.put('listContent', bar);
}
angular.module('foo').filter('baz', baz);
app.run(foo);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="foo">
<script type="text/ng-template" id="foo">
<span>hi</span>
</script>
<input ng-model="dude">
<ul ng-include="'listContent' | baz:dude"></ul>
</div>
References
AngularJS: API: $templateCache
AngularJS: Is there a better way to achieve this than the one specified?
I am pretty new to angularJS, and obviously there are some simple things that i do not yet understand. What i want to do is the following:
I've got a de-DE.json (that e.g. has several language-keys for a planned multi-language site) that looks somewhat like this
{
"index": {
"headline": "The title of that view",
"tabmenu": [
{
"id": "home",
"class": "active in",
"title":"Title No. 1",
"description":"Some description"
},
{
"id": "profile",
"class": "",
"title":"Title No. 2",
"banner":"WallBanner.jpg",
"description":"Some description"
},
{
"id": "messages",
"class": "",
"title":"Title No. 3",
"description":"Some description"
},
{
"id": "settings",
"class": "",
"title":"Title No. 4",
"description":"Some description"
}
]
},
"media": {
...
}
}
Next have a look at my index.html that looks like:
<html ng-app id="ng-app">
<head>
<title>Title of the Site</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" href="../assets/bootstrap/css/bootstrap.min.css">
</head>
<body ng-controller="languageKey">
<div class="container" ng-model="language.index">
<h1>{{ headline }}</h1>
<div class="row">
<div class="col-lg-12">
<ul class="nav nav-tabs" id="myTab">
<li class="active">Tab1</li>
<li>Tab2</li>
<li>Tab3</li>
<li>Tab4</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade {{ lg.class }}" id="{{ lg.id }}" ng-repeat="lg in language.index.tabmenu">
<h3>{{ lg.title }}</h3>
<p>{{ lg.description }}</p>
</div>
</div>
</div>
</div>
</div>
<script src="../assets/jquery/jquery.js"></script>
<script src="../assets/bootstrap/js/bootstrap.min.js"></script>
<script src="../assets/angularjs/angular.min.js"></script>
<script>
$(function () {
$('#myTab a:first').tab('show')
})
function languageKey($scope, $http)
{
$http({method: 'POST', url: 'de-DE.json'}).success(function(data)
{
$scope.language = data; //response Data
});
}
</script>
</body>
</html>
So thanks to some google-knownledge the part with the <div ng-repeat="lg in language.index.tabmenu"> works fine.
But much more common are language-keys that are just used once, without repeating html structure like in the above
<h1>{{ headline }}</h1>
(I've also tried <h1 ng-bind="{headline}"
So is there a leightweight way to just call those expressions?
Obviously it doesn't work if i try ng-model="language.index" in that case.
You just have to set your JSON object in your $scope element inside your controller, and you can use it in the view:
$scope.myJSON = {...};
In HTML
<h1>{{myJSON.index.headline }}</h1>
By the way, if you're implementing a multi-language application take a look at angular-translate.
If this works
<div ng-repeat="lg in language.index.tabmenu">
then as long as you load the parsed JSON object into the $scope the same way, this should output the headline:
<h1>{{ language.index.headline }}</h1>
The docs suggest that ng-model only works with inputs:
ngModel directive binds an input,select, textarea (or custom form control) to a property on the scope
Simple thing - works in the jsfiddle but not in my file. I'm trying to add some data to "factory" of the module and then use it within my controllers.
This is the relevant code:
var challengesApp = angular.module('challengesApp', []);
challengesApp.factory('Challenges', function() {
var challenges = [
{
'program': {
"num": "1",
"name": "aaa"
},
'challengeDesc': "desss",
'items': [
{title:"aaa",
desc:"bbb",
link: "www.google.com",
fiction: true},
]
}
];
return challenges;
});
function ChallengeCtrl($scope, Challenges) {
$scope.challenges = Challenges;
etc...
}
function ChallengeListCtrl($scope, Challenges) {
$scope.challenges = Challenges;
etc..
}
and the HTML:
<body ng-app="challengesApp">
<div ng-controller="ChallengeCtrl">
<div id="question">
<h2>{{ challenge.challengeDesc }}</h2>
<ul>
<li ng-repeat="item in challenge.items">
<strong>{{ item.title }}</strong> - {{ item.desc }}
</li>
</ul>
</div>
</div>
<div ng-controller="ChallengeListCtrl">
<div id="programs_list">
<ul>
<li ng-repeat="program in challenges | orderBy:orderProp:reverse">
<a href="" ng-click="changeChallenge(program)">
{{ program.program.num }} - {{ program.program.name }}
</a>
</li>
</ul>
</div>
</div>
<script src="js/main.js"></script>
</body>
anything here that I'm missing?
So, as I suspected, it was a dumb mistake. the <html> tag was:
<html ng-app>
blocking the correct ng-app attribute at the <body> tag.