AngularJS: Nested Directives - passing data not working - angularjs

I'm trying to create a directive inside another directive while the first directive gets an array and for each item in the array call the other directive.
i'm having trouble with passing the data correctly.
Plunker
Here is my code:
angular.module('app', [])
.controller('MainCtrl', function($scope) {
$scope.data = {
items: [{
id: 1,
name: "first"
}, {
id: 2,
name: "second"
}, {
id: 3,
name: "third"
}]
}
})
.directive('firstDirective', function() {
return {
replace: true,
restrict: 'A',
compile: function(element, attrs) {
var template = '';
angular.forEach(attrs.data, function(item, key) {
var tmp = '<div>' +
// '<h4>First Directive</h4>' +
'{{dataFirst}}' +
'<div second-directive data="' + item + '"></div>' +
'</div>';
element.append(tmp);
});
}
}
})
.directive('secondDirective', function() {
return {
replace: true,
restrict: 'A',
compile: function(element, attrs) {
var template = '<div class="second-directive">' +
'<h4>Directive 2</h4>' +
'ID :' + attrs.data + '<br />' +
'Name : ' + attrs.data +
'</div>';
element.replaceWith(template);
}
};
});
.second-directive{
border:1px solid green;
padding:4px;
text-align:center;
width:100px;
height:auto;
overflow:hidden;
float:left;
margin:2px;
}
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<h2>MainCtrl</h2>
{{data}}
<div first-directive data="data.items">
</div>
</body>
</html>
Thanks a lot
Avi

As you mentioned you want to call other directive for each item in the array.
you can do it in this way .
HTML :
<body ng-controller="MainCtrl">
<div first-directive>
<div ng-repeat="oneEle in data.items">
<div second-directive dirval="oneEle">
</div>
</div>
</div>
</body>
directive('secondDirective', function() {
var tmp = '<div>' +
'<div class="second-directive" >'+
'<h4>Directive 2</h4>' +
'ID : {{dirval.id}} <br />' +
'Name : {{dirval.name}}</div>' +
'</div>';
return {
replace: true,
restrict: 'A',
scope: {
dirval: '='
},
template : tmp
}
})
if you want load dynamic template for different object, you can pass in $scope.data object.
Here is the Plunker

Thank's everyone.
This is the solution i cam up with.
angular.module('app', [])
.controller('MainCtrl', function($scope) {
$scope.data = {
items: [{
id: 1,
name: "first"
}, {
id: 2,
name: "second"
}, {
id: 3,
name: "third"
}]
}
})
.directive('firstDirective', function($compile) {
return {
replace: true,
restrict: 'A',
scope: {
data: '='
},
link: function(scope, element, attrs) {
var template = '';
angular.forEach(scope.data, function(item, key) {
var sss = JSON.stringify(item).replace(/"/g, "'");
var tmp = '<div>' +
'<div second-directive data="' + sss + '"></div>' +
'</div>';
template = template + tmp;
});
element.html(template);
$compile(element.contents())(scope);
}
}
})
.directive('secondDirective', function() {
var comp = function(element, attrs){
var data = JSON.parse(attrs.data.replace(/'/g, "\""));
var template = '<div class="second-directive">' +
'<h4>Directive 2</h4>' +
'ID :' + data.id + '<br />' +
'Name : ' + data.name +
'</div>';
element.replaceWith(template);
}
return {
replace: true,
restrict: 'A',
compile: comp
};
});
.second-directive{
border:1px solid green;
padding:4px;
text-align:center;
width:100px;
height:auto;
overflow:hidden;
float:left;
margin:2px;
}
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<h2>MainCtrl</h2>
{{data}}
<div first-directive data="data.items">
</div>
</body>
</html>

Related

How to get value from a directive input field using angular

I am new to angular.js. I have two directives in my main.js file and every directive has an input text field in the template. There is a Html page (index.html) where I want to use these directive's text fields with another input text field which is a Html input text field.
Now I want whatever input user gives in both the directive's text fields the character count should be calculated and the sum should be printed in the third text field which is a Html text field.
Code is given below:-
Main.js file code :
/// <reference path="angular.min.js" />
var app = angular.module("myApp", []);
app.directive("textbox1", function() {
return {
restrict: 'E',
scope: {
timezone : "#"
},
template: "<div> <input type='text' style='background-color:orange; height=21px; width:151px;' ng-model='txtval1' ng-change='updateval()' />{{txtval1.length}} </div>"
}
});
app.directive("textbox2", function() {
return {
restrict: 'E',
scope: {
timezone: "#"
},
template: "<div> <input type='text' style='background-color:orange; height=21px; width:151px;' ng-model='txtval2' ng-change='updateval()'/>{{txtval2.length}} </div>"
}
});
app.controller("myCtrl", function ($scope) {
$scope.updateval = function () {
console.log($scope.txtval1.value);
$scope.txtThird = ($scope.txtval1.length) + ($scope.txtval2.length);
}
});
HTML Page Code :
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />
</head>
<body>
<div ng-app="myApp">
<textbox1></textbox1>
<textbox2></textbox2>
<br/><br/>
<input type="text" ng-model="txtThird"/>
</div>
<script src="scripts/angular.min.js"></script>
<script src="scripts/main.js"></script>
</body>
</html>
You need to do something like this:
var app = angular.module("myApp", []);
app.directive("textbox1", function() {
return {
restrict: 'E',
scope: {
timezone : "#",
updateval: "&updateval"
},
template: "<div> <input type='text' style='background-color:orange; height=21px; width:151px;' ng-model='txtval1' ng-change=\"updateval({inputNr:'1', textval: txtval1})\" />{{txtval1.length}} </div>",
}
});
app.directive("textbox2", function() {
return {
restrict: 'E',
scope: {
timezone: "#",
updateval: "&updateval"
},
template: "<div> <input type='text' style='background-color:orange; height=21px; width:151px;' ng-model='txtval2' ng-change=\"updateval({inputNr:'2', textval: txtval2})\" />{{txtval2.length}} </div>"
}
});
app.controller("myCtrl", function ($scope) {
$scope.inputValues = [
{
input: '1',
value: ''
},
{
input: '2',
value: ''
}
];
$scope.updateval = function (inputNr, txtval) {
var updatedInput = _.find($scope.inputValues, {input: inputNr});
updatedInput.value = txtval;
var lengthSum = 0;
angular.forEach($scope.inputValues, function(inputObj){
lengthSum += inputObj.value.length;
});
console.log(lengthSum);
}
});
Here is working: https://codepen.io/neptune01/pen/bWzLvq
Note that I used lodash.
If I understand you need something this:
//index.html
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />
</head>
<body ng-app="myApp">
<div ng-controller="myCtrl">
<textbox length="length1"></textbox>
<textbox length="length2"></textbox>
<br/><br/>
<input type="text" ng-model="txtThird"/>
<p>Sum = {{length1+length2}}</p>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<script src="script.js"></script>
</body>
</html>
//script.js
'use strict';
var app = angular.module("myApp", []);
app.directive("textbox", function() {
return {
restrict: 'E',
scope: {
length: '='
},
controller: function($scope){
},
template: "<div> <input type='text' style='background-color:orange; height=21px; width:151px;' ng-model='txtval' ng-change='length = txtval.length'/>{{txtval.length}} </div>"
}
});
app.controller("myCtrl", function ($scope) {
$scope.txtThird = "some text";
$scope.length1 = 0;
$scope.length2 = 0;
$scope.updateval = function () {
console.log($scope.txtval1.value);
$scope.txtThird = ($scope.txtval1.length) + ($scope.txtval2.length);
}
You can try it on plunker: https://plnkr.co/edit/XE6OcQX5GOJIPMcVHWum?p=preview

AngularJS: Nested Directives - Data binding ishu

I have nested directives.
I send data from the first one the the second.
The problem is that I lose the the binding to the main scope.
This is my code:
Plunker
(clicking the button changes the value in the main scope but not in the directive)
angular.module('app', [])
.controller('MainCtrl', function($scope) {
$scope.change = function(){
var id = Math.floor((Math.random() * 4) + 0);
var val = Math.floor((Math.random() * 100) + 1);
$scope.data.items[id].id = val;
}
$scope.data = {
items: [{
id: 1,
name: "first"
}, {
id: 2,
name: "second"
}, {
id: 3,
name: "third"
}, {
id: 4,
name: "forth"
}]
}
})
.directive('firstDirective', function($compile) {
return {
replace: true,
restrict: 'A',
scope: {
data: '='
},
link: function(scope, element, attrs) {
var template = '';
angular.forEach(scope.data, function(item, key) {
var sss = JSON.stringify(item).replace(/"/g, "'");
var tmp = '<div>' +
'<div second-directive data="' + sss + '"></div>' +
'</div>';
template = template + tmp;
});
element.html(template);
$compile(element.contents())(scope);
}
}
})
.directive('secondDirective', function() {
var comp = function(element, attrs){
var data = JSON.parse(attrs.data.replace(/'/g, "\""));
var template = '<div class="second-directive">' +
'<h4>Directive 2</h4>' +
'ID :' + data.id + '<br />' +
'Name : ' + data.name +
'</div>';
element.replaceWith(template);
}
return {
replace: true,
restrict: 'A',
compile: comp
};
});
/* Put your css in here */
.second-directive{
border:1px solid green;
padding:4px;
text-align:center;
width:100px;
height:auto;
overflow:hidden;
float:left;
margin:2px;
}
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.3.x" src="https://code.angularjs.org/1.3.15/angular.js" data-semver="1.3.15"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<h2>MainCtrl</h2>
{{data}}
<BR />
<button ng-click="change()">change value</button>
<div first-directive data="data.items">
</div>
</body>
</html>
Thanks a lot
Avi
Not sure why you need nested directives. Seems to overcomplicate things. Why not just pass the data object to one directive and any changes you make in the parent controller will update in the directive as well.
http://plnkr.co/edit/gR3qBRmDotiUesS6DuyN?p=preview
index.html
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.3.x" src="https://code.angularjs.org/1.3.15/angular.js" data-semver="1.3.15"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<h2>MainCtrl</h2>
{{data}}
<BR />
<button ng-click="change()">change value</button>
<div first-directive data="data.items">
</div>
</body>
</html>
template1.html
<div>
<div class="second-directive" ng-repeat="item in data">
<h4>Directive</h4>
ID :{{ item.id }} <br />
Name : {{item.name }}
</div>
</div>
app.js
angular.module('app', [])
.controller('MainCtrl', function($scope) {
$scope.change = function(){
var id = Math.floor((Math.random() * 4) + 0);
var val = Math.floor((Math.random() * 100) + 1);
$scope.data.items[id].id = val;
}
$scope.data = {
items: [{
id: 1,
name: "first"
}, {
id: 2,
name: "second"
}, {
id: 3,
name: "third"
}, {
id: 4,
name: "forth"
}]
};
})
.directive('firstDirective', function() {
return {
replace: true,
templateUrl: 'template1.html',
restrict: 'A',
scope: {
data: '='
},
link: function(scope, element, attrs) {
}
}
});
If you really need nested directives then you will need to look into the require option on the directive definition object where you can specify a parent directive controller which will be injected in the link function of the child directive. You can then access any properties on the parent directive scope in the child directive.
See: https://docs.angularjs.org/api/ng/service/$compile#directive-definition-object
Hope that helps.

custom directive function not working angularjs

I have this piece of code , but when the user writes the color in the input, the background color of the new element is suposed to change but is not working, what am I doing wrong?
<div ng-app="mainApp" ng-controller="MainCtrl">
<input type="text" ng-model="color" placeholder="Enter a color" />
<hello-world/>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script>
var mainApp = angular.module("mainApp", []);
mainApp.directive('helloWorld', function() {
return {
restrict: 'AE',
replace: true,
template: '<p style="background-color:{{color}}">Hello World',
link: function(scope, elem, attrs) {
elem.bind('click', function() {
elem.css('background-color', 'white');
scope.$apply(function() {
scope.color = "white";
});
});
elem.bind('mouseover', function() {
elem.css('cursor', 'pointer');
});
}
};
});
</script>
Close your template tag and delete the inline style from there.
Also you should use elem.on() instead elem.bind()
var mainApp = angular.module("mainApp", []);
mainApp.directive('helloWorld', function() {
return {
restrict: 'AE',
template: '<input type="text" placeholder="Enter a color" ng-model="color"/><p>Hello World</p>',
link: function(scope, elem, attrs) {
scope.color = elem.find('input').val();
scope.$watch('color', function(newVal, oldVal){
if(oldVal === newVal) return;
elem.find('p').addClass(scope.color +'');
});
elem.on('mouseover', function() {
elem.find('input').css('cursor', 'pointer');
});
}
};
});
.red {
background-color: red;
}
.blue {
background-color: blue;
}
<!doctype html>
<html ng-app="mainApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</head>
<body>
<hello-world></hello-world>
</body>
</html>
Please for the example type 'red' or 'blue'.

AngularJS - Transcluding multiple directives

I have a situation where I need to transclude multiple child directives inside of my outer directive. I've got it working, but I'm wondering if there is a better, more "angular" way to do it?
The working example is here: http://plnkr.co/edit/pmukXJPxUGd2gnMvEN1a?p=preview
Plunker code:
<!DOCTYPE html>
<html>
<head>
<script src="//code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</head>
<body ng-app="myApp">
<outer-directive>
<inner-directive1>Some Html I want placed elsewhere</inner-directive1>
<inner-directive2>Yet more Html that should be somewhere else</inner-directive2>
</outer-directive>
<script>
var app = angular.module("myApp", []);
app.directive("outerDirective", function($compile) {
return {
restrict: 'E',
transclude: true,
scope: {},
template: '<div>' +
' <h1>This is a title</h1>' +
' <div class="inner1"></div><br />' +
' Some other code that is in the directive<br /><br />' +
' <div class="inner2"></div><br />' +
'</div>',
link: function(scope, element, attrs, emptyCtrl, transclude) {
transclude(scope, function(clone) {
clone.each(function (i, ele) {
if (ele.nodeName === "INNER-DIRECTIVE1") {
$(element).find(".inner1").replaceWith($compile(ele)(scope));
}
if (ele.nodeName === "INNER-DIRECTIVE2") {
$(element).find(".inner2").replaceWith($compile(ele)(scope));
}
});
});
}
}
});
</script>
</body>
</html>

How to access a controller function in directives with isolated scope?

I have a function in my controller name as enableEditor it is working if i call the function from direct HTML i.e(add). But, if I call the function for a element which is created through the directives i.e(edit) is not working. Please look at my code and advice me if any ideas.
<!doctype html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="UTF-8">
<title>Example - example-example53-production</title>
<script src="js/angular.min.js"></script>
</head>
<body ng-controller="MainCtrl">
<div user-name=""></div>
<div>
add
</div>
<script>
var myApp = angular.module('myApp', []);
myApp.controller('MainCtrl', ['$scope','$filter', function ($scope,$filter) {
$scope.enableEditor = function() {
alert("123");
};
}]);
myApp.directive("userName", function() {
return {
restrict: "A",
scope: {
value: "=userName"
},
template: '<div class="click-to-edit">' +
'Edit' +
'</div>'
};
});
</script>
</body>
</html>
Since you have an isolated scope the function belongs to the scope of the directive not your controller. Try using & in your directives scope like this:
<body ng-controller="MainCtrl">
<div user-name="" callme="enableEditor()"></div>
<div>
add
</div>
<script>
var myApp = angular.module('myApp', []);
myApp.controller('MainCtrl', ['$scope','$filter', function ($scope,$filter) {
$scope.enableEditor = function() {
alert("123");
};
}]);
myApp.directive("userName", function() {
return {
restrict: "A",
scope: {
value: "=userName",
callme:"&"
},
template: '<div class="click-to-edit">' +
'Edit' +
'</div>'
};
});
The attribute callme="enableEditor()" is used to pass the method to the scope directive, the directive scope uses & to indicate it is method callme:"&". Another example:
method2="someMethod()" like
scope: {
value: "=userName",
callme:"&",
method2:"&"
},template: '<div class="click-to-edit">' + 'Edit' + 'Save' + '</div>'

Resources