Why it not working? following angularjs Example - angularjs

Here i created some Example.. In this Example 1 I put directly
//{{arr.Description}}
like this its working but via directive its not working what misstake i did
can please explain me?
Thanks friends
var app = angular.module('components', []);
app.directive('subpane', function() {
return {
restrict: 'E',
scope: {
array: '#'
},
template:'<li ng-repeat="arr in array">{{arr.Description}}</li>',
link: function(scope) {
}
};
})
app.controller('tabController', ['$scope', function ($scope) {
$scope.array =[{
"title": 0,
"Description": "Select your option"
},
{
"title": 1,
"Description": "Male"
},
{
"title": 2,
"Description": "Female"
},
{
"title": 3,
"Description": "Unknown"
}];
}])
<script data-require="angular.js#~1.3.15" data-semver="1.3.15" src="https://code.angularjs.org/1.3.15/angular.js"></script>
<body ng-app="components" ng-controller="tabController">
<span>Example 1 Working fine</span>
<li ng-repeat="arr in array">{{arr.Description}}</li>
<span>Example 2 Not Working.. Here also same thing only i did via directive.. why this is not working?</span>
<subpane array={{array}}></subpane>
</body>

Use '=' for the scope param and remove '{{}}' in the markup.
var app = angular.module('components', []);
app.directive('subpane', function() {
return {
restrict: 'E',
scope: {
array: '='
},
template:'<li ng-repeat="arr in array">{{arr.Description}}</li>',
link: function(scope) {
}
};
})
app.controller('tabController', ['$scope', function ($scope) {
$scope.array =[{
"title": 0,
"Description": "Select your option"
},
{
"title": 1,
"Description": "Male"
},
{
"title": 2,
"Description": "Female"
},
{
"title": 3,
"Description": "Unknown"
}];
}])
<script data-require="angular.js#~1.3.15" data-semver="1.3.15" src="https://code.angularjs.org/1.3.15/angular.js"></script>
<body ng-app="components" ng-controller="tabController">
<span>Example 1 Working fine</span>
<li ng-repeat="arr in array">{{arr.Description}}</li>
<span>Example 2 Not Working.. Here also same thing only i did via directive.. why this is not working?</span>
<subpane array=array></subpane>
</body>

You need to add "plain: true" in the directive if you don't use templateUrl
app.directive('subpane', function() {
return {
restrict: 'E',
scope: {
array: '=' // = not #, = is for object/array ; = is for text/number.
},
template:'<li ng-repeat="arr in array">{{arr.Description}}</li>',
plain: true,
link: function(scope) {
}
};
})
In the html dont put {{ }} in the parameter array
<subpane array="array"></subpane>

camden_kid has posted an acceptable answer but not probably the best one. In your template:
<subpane array={{array}}></subpane>
Must have the quotes:
<subpane array="{{array}}"></subpane>
Please also note that camden_kid suggested to change
scope: {
array: '#'
}
To
scope: {
array: '='
}
This is what is needed for double binding and it is only necessary if you have to edit in any way the original value (in the parent scope) from within the directive's isolated scope.
You probably should read more carefully the docs: https://docs.angularjs.org/guide/directive

Related

Angular Js | Lazy Load Directive based on ViewPort

Is it possible to lazy load directives?
Say we have 20 Directives on a single page, and on scroll, if the directive is in viewport it should get rendered.Otherwise no action should take take.
It should behave as lazy loading of images.
Can we achieve it??
You Question is unspecific but I'm willing to try:
Imagine your HTML like that
<div ng-app="app" ng-controller="myCtrl">
<ul id="myList">
<li ng-repeat="item in data">
<mydirective item="item"></mydirective>
</li>
</ul>
the directive is is doing whatever needed for your item
angular.module("mydirective", []).directive("mydirective", function() {
return {
templateUrl: 'templates/mytemplate.php',
replace: false,
transclude: false,
restrict: 'A',
scope: {
item: "="
}
};
});
The controller would look like that
app.controller("myCtrl", ["$scope", function ($scope) {
$scope.data = [
{id: 1, "name": "img1"},
{id: 2, "name": "img2"},
{id: 3, "name": "img3"}
];
$("#myList").bind("scrollend", function(e){
$scope.loadNextElements();
});
$scope.loadNextElements = function() {
// add new elements
$scope.data.push({id: 4, "name": "img4"});
$scope.data.push({id: 5, "name": "img5"});
$scope.data.push({id: 6, "name": "img6"});
...
}
}]);

Using directives in angularjs with templateUrl

I wrote a code with angularjs that uses a directive to bring a list of categories from show-category.html file and show them on the index page, I did everything as I've learned but still can't get the categories to be displayed when index.html is loaded.
inside app.js file
app.directive('showCategories', function() {
return {
restrict: 'E',
templateUrl: 'show-categories.html'
};
});
you can see the full code on plunker here:
http://plnkr.co/edit/FSsNAq?p=preview
You placed your directive definition right in the middle of the controller, take it outside and it works (barring some other non-existing functions you have there):
app.controller("BookCtrl", function($scope) {
$scope.categories = [{
"id": 0,
"name": "Type"
}, {
"id": 1,
"name": "Date"
}, {
"id": 1,
"name": "Name"
}
];
...
});
app.directive('showCategories', function() {
return {
restrict: 'E',
templateUrl: 'show-categories.html'
};
});
Plunker

Angular Directive param value array

How can I use an array which is given as an attribute of a directive in the linker of the directive
[
{
"state": "bootstrap.formwizard.ethernet",
"placeHolder": "lNetworkConfWizardMenu",
"stepNumber": 1,
"next": "bootstrap.formwizard.datetime"
},
{
"state": "bootstrap.formwizard.datetime",
"placeHolder": "lDateSetWizardMenu",
"previous": "bootstrap.formwizard.ethernet",
"stepNumber": 2,
"next": "bootstrap.formwizard.countrysetting"
},
]
Template
<formprogressbar steps="wizardSteps" />
Directive
angular.module('smaModules.formProgressbar', [])
.directive('formprogressbar', function ($log) {
function linker(scope, element, attrs) {
console.log(scope);
test = attrs.steps[0]
console.log(test);
}
return {
restrict: 'E',
scope: {
steps: '='
},
template: 'Steps: {{ steps[0] }}',
link: linker
};
});
In the template I have access but not in the linker function. What's wrong?
You want to access the steps off of your scope for it to be the same as in your template. Also you should declare your variable for best practice.
.directive('formprogressbar', function ($log, $filter) {
function linker(scope, element, attrs) {
console.log(scope);
var test = scope.steps[0];
console.log(test);
}
return {
restrict: 'E',
scope: {
steps: '='
},
template: 'Steps: {{ steps[0] }}',
link: linker
};
});
attrs.steps[0] was probably giving you the result of 'w', this is because attrs.steps is the string "wizardSteps", the first index of the string being 'w'.

scope of event arguments in angular directive

I have the following angular app to create a menu of sections/products.
at present when rendered and hitting the 'add' button that is rendered within each li I want to add a section/product as a sub of that section however multiple new children are created.
ultimately I wish to display a form which when submitted will create the child but that is the next step. Right now I need to limit the scope to the current section and not have multiple bound clicks.
If you need more information please state and I will post in an edit.
Some sample data data.
{
"sections":[
{
"name":"Flags",
"sections":[
{
"name":"Europe",
"sections":[],
"products":[
{ "name": "France" },
{ "name": "Germany" },
{ "name": "Ireland" },
{ "name": "England" }
]
},
{
"name": "Africa",
"sections":[],
"products":[
{ "name": "Egypt" },
{ "name": "Nigeria" },
{ "name": "Chad" }
]
},
{
"name": "South America",
"sections":[],
"products": [
{ "name": "Brasil" },
{ "name": "Argentina" },
{ "name": "Peru" }
]
}
],
"products":[]
},
{
"name": "Maps",
"sections":[
{
"name": "Africa",
"sections":[],
"products":[
{ "name": "Egypt" },
{ "name": "Nigeria" },
{ "name": "Chad" }
]
},
{
"name": "South America",
"sections":[],
"products": [
{ "name": "Brasil" },
{ "name": "Argentina" },
{ "name": "Peru" }
]
}
],
"products":[]
}
],
"products":[]
}
The app.
'use strict';
var menuApp = angular.module('menuApp', []);
menuApp
.directive('sections', function () {
return {
restrict: "E",
replace: true,
scope: {
sections: '='
},
template: '<ul><section ng-repeat="section in sections" section="section" /></ul>'
};
})
.directive('section', function ($compile) {
return {
restrict: "E",
replace: true,
scope: {
section: '=section'
},
template: '<li class="section">{{section.name}} <button ng-click="addSub(section)">Add</button></li>',
link: function (scope, element, attrs, controller) {
if (angular.isArray(scope.section.sections)) {
element.append("<sections sections='section.sections'></sections>");
$compile(element.contents())(scope);
}
if(angular.isArray(scope.section.products)){
element.append("<products products='section.products'></products>");
$compile(element.contents())(scope);
};
},
controller : function($scope){
console.log($scope);
$scope.addSub = function (section){
//console.log(section,'Adding Sub');
section.sections.push({"name":"Section","sections":[],"products":[]});
};
}
};
})
.directive('products', function () {
return {
restrict: "E",
replace: true,
scope: {
products: '='
},
template: '<ul><product ng-repeat="product in products" product="product"></product></ul>'
};
})
.directive('product', function ($compile) {
return {
restrict: "E",
replace: true,
scope: {
product: '='
},
template: '<li class="product">{{product.name}}</li>'
};
});
menuApp.controller('menuCtrl', function menuCtrl($scope,$http) {
$http.get('/ajax/getvenuesmenu?venueID='+venueMenu.venueId).success(function(resp) {
$scope.sections = resp;
});
$scope.add = function(data){
data.push({"name":"Section","sections":[]});
};
});
Took me a bit to figure it out but here's the basic problem, you are compiling the full contents of section 2 extra times and each compile seems to add a new event handler.
Instead of compiling the contents of element each time you make an append of new template, compile the template itself (outside of the DOM) and then append the compiled template. This way the ng-click handler doesn't get compiled again other than initial scope creation
Here's an abbreviated version with one template appended:
link: function (scope, element, attrs, controller) {
if (angular.isArray(scope.section.sections)) {
/* compile outside of the DOM*/
var subsections = $compile("<sections sections='section.sections'></sections>")(scope);
/* append compilation*/
element.append(subsections);
}
DEMO
Another approach would be to create a complete template string in link by checking for subsections and products, then compiling everything all at once....instead of using template option
Code for alternate approach compiling complete section at once:
.directive('section', function ($compile, $timeout) {
return {
restrict: "E",
scope: {
section: '=section'
},
link: function (scope, element, attrs, controller) {
var template = '<li class="section">{{section.name}} <button ng-click="addSub(section)">Add</button>';
if (angular.isArray(scope.section.sections)) {
template += "<sections sections='section.sections'></sections>";
}
if (angular.isArray(scope.section.products)) {
template += "<products products='section.products'></products>";
};
template += '</li>';
var compiledTemplate = $compile(template)(scope);
element.replaceWith(compiledTemplate);
scope.addSub = function (section) {
section.sections.push({ "name": "Section", "sections": [], "products": []
});
};
}
};
})
DEMO-Alt

Create an unordered list n-levels deep using AngularJS

While going through some AngularJS examples, I see how easy it is to repeat and create structures. However, I couldn't figure out how to do the following.
Assume we have a json structure like
{
"Asia": {
"India": {
"Bangalore": {},
"Mumbai": {},
"New Delhi": {}
},
"China": {
"Beijing": {},
"Shanghai": {}
}
},
"Europe": {
"France": {
"Paris": {}
},
"Germany": {
"Berlin": {}
}
}
}
What I want to do is - Convert this JSON structure to an Unordered list - The depth of this kind of structure is not known, and can possibly go deeper. How do I perform repeats dynamically using Angular JS?
Your JSON is poorly structured, you're using property names to carry data.
What you really want is something like this:
$scope.continents = [
{
name: 'Asia',
countries: [
{
name: 'India',
cities: [
'Bangalore',
'Mumbai',
'New Delhi'
]
},
{
name: 'China',
cities: [
'Beijing',
'Shanghai'
]
},
]
},
{
name: 'Europe',
countries: [
{
name: 'France',
cities: [
'Peris'
]
},
{
name: 'Germany',
cities: [
'Berlin'
]
},
]
}
];
That said... what it sounds like you're looking to do is create a recursive tree directive of some sort. That gets a little tricky. You'll need to normalize your structure a bit so you can recursively examine it. Then you'll have to create two directives. One for a list, and one for an item:
Here is an example of what I mean...
function Item(name, items) {
this.name = name;
this.items = items || [];
}
app.controller('MainCtrl', function($scope) {
$scope.items = [
new Item('test'),
new Item('foo', [
new Item('foo-1'),
new Item('foo-2', [
new Item('foo-2-1'),
new Item('foo-2-2')
])
]),
new Item('whatever')
];
});
app.directive('tree', function() {
return {
template: '<ul><tree-node ng-repeat="item in items"></tree-node></ul>',
restrict: 'E',
replace: true,
scope: {
items: '=items'
}
};
});
app.directive('treeNode', function($compile) {
return {
restrict: 'E',
template: '<li>{{item.name}}</li>',
link: function(scope, elm, attrs) {
//MAGIC HERE!!!: this will do the work of inserting the next set of nodes.
if (scope.item.items.length > 0) {
var children = $compile('<tree items="item.items"></tree>')(scope);
elm.append(children);
}
}
};
});
In case anyone is interested in the "least-effort" way to do this without creating a directive (not that you shouldn't, but just offering a variation), here is a simple example:
http://jsbin.com/hokupe/1/edit
Also here's a blog post and a 10-15 minutes video on how it works:
http://gurustop.net/blog/2014/07/15/angularjs-using-templates-ng-include-create-infinite-tree/
Sample Code:
<script type="text/ng-template" id="treeLevel.html">
<ul>
<li ng-repeat="item in items">
<input type="checkbox"
name="itemSelection"
ng-model="item._Selected" />
{{item.text}}
<div ng-include=" 'treeLevel.html'"
onload="items = item.children">
</div>
</li>
</ul>
</script>
<div ng-include=" 'treeLevel.html' "
onload="items = sourceItems">
</div>

Resources