Use data in angular directive link? - angularjs

How i can use data , which passed from controller to directive from tag attribute ?? Its show undefined in console .
App.directive('applist', ['$rootScope', function($rootScope) {
'use strict';
return {
restrict: 'E',
scope: {
gamesList: '=',
}.
link: function(scope,attrs){
console.log(scope.gamesList); //undefined
}
}
}])
And html:
<applist games-List="games">
<div ng-repeat="(key, value) in gamesList | groupBy: 'game.id'"> ... </div>
</applist>

You must change your tag to:
<applist games-list="games">...</applist>
Also, in angular, the camelCase in your attributes is used with a '-' in the html tag. And you forgot the 's' to the 'game'
Edit: As stated, the dot before link is making the directive break. Try:
return {
restrict: 'E',
scope: {
gamesList: '='
}, //change dot to coma
link: function(scope,attrs){
console.log(scope.gamesList); //undefined
}
}

Use # for getting String Values:
Modified Code:
<!DOCTYPE html>
<html ng-app="myApp">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body>
<applist games-list="games"></applist>
<script>
var App=angular.module('myApp',[]);
App.directive('applist', ['$rootScope', function($rootScope) {
'use strict';
return {
restrict: 'E',
transclude:true,
scope: {
gamesList: '#',
},
link: function(scope,attrs){
console.log(scope.gamesList); //games
}
}
}])
</script>
</body>
</html>

To get data from directive attribute you can use below code
console.log(scope.gamesList);
Your directive will be
App.directive('applist', ['$rootScope', function($rootScope) {
'use strict';
return {
restrict: 'E',
scope: {
gamesList: '#',
},
link: function(scope,attrs){
console.log(scope.gamesList); //games
}
}
}])

Related

Calling function of controller from directive when using isolated scope?

I want to call a function of Controller from Directive, It is for validation. But i'm a bit confused about how to call it from Directive when i'm using isolated scope. Here is the code of directive:-
App.directive('test',function(){
return{
require: "ngModel",
scope:{
a:"=",
b:"=",
c:'=',
d:'='
},
link: function(scope, element, attributes,modelVal )
{
modelVal.$validators.test= function(val)
{
return false;
//isolated scope values will make if condition true or false.
if(scope.a=="true"){
//I need to call a function of controller here. But how can
//i call that function from directive? this is my problem
}
}
scope.$watch("a", function()
{
modelVal.$validate();
});
}//end of link function;
}//end of return;
});//end of directive;
Function is in my controller, i think i don't need to write the controller code. In my html , I'm calling this directive as:
<test a="1" b="2" c="3" d="4" ng-model="abc"></test>
What changes i need to do in my directive to call the controller function which is $scope.testFunction()?
var module = angular.module('myModule', []);
module.controller('TestController', function($scope){
$scope.text = 'test';
// Will be invoked from 'test' directive
$scope.alertMe = function(text){
alert(text);
};
});
module.directive('test', function(){
return {
restrict: 'E',
template: '<input ng-model="text" ng-change="onChange(text)" />',
scope: {
text: '='
},
link: function(scope, elem, attr){
scope.onChange = function(text){
// Invoking parent controller function
scope.$parent.alertMe(text);
}
}
}
})
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<body>
<div ng-app="myModule" ng-controller="TestController">
<test text="text"></test>
</div>
</body>
</html>
I have given a sample, try like this.
Controller:
module.controller('TestController', function($scope){
$scope.onTextChange = function(text){
alert(text);
};
})
HTML:
<test my-func="onTextChange(text)"></test>
Directive:
module.directive('test', function(){
return {
restrict: 'E',
template: '<input ng-model="text" ng-change="onChange(text)" />',
scope: {
myFunc: '&'
},
link: function(scope, elem, attr){
scope.onChange = function(text){
if(typeof scope.myFunc === 'function'){
// Calling the parent controller function
scope.myFunc({text: text});
}
}
}
}
})

Cannot receive value of isolated scope in directive

I created this directive
angular.module('panel')
.directive('sigPanel', sigPanel)
function sigPanel() {
return {
restrict: 'E',
scope:{
imgData:"="
},
templateUrl: 'app/widgets/signature/signature.html',
link: function (scope, element, attrs) {
console.log(scope.imgData);
}
}
}
This is the templateURL:
<canvas style="border:1px solid black;"></canvas>
And added this into the HTML:
<sig-panel imgData="test"></sig-panel>
The console log only outputs "undefined", shouldn't it log "test"? I know the directive html tag is working properly because the canvas appears on the page, but why won't the directive pick up the value of "imgData"?
If I try setting the scope.imgData inside the directive I get the error
[$compile:nonassign] Expression 'undefined' used with directive 'signaturePanel' is non-assignable!
Not sure why this is happening.
You need to change imgData (camelCase normalized) to img-data (dash-delimited). Also if you want to pass the string "test" to the scope you need to put quotes around it.
angular.module('app', []).directive('sigPanel', sigPanel);
function sigPanel() {
return {
restrict: 'E',
scope: {
imgData: "="
},
template: '<canvas style="border:1px solid black;"></canvas>',
link: function(scope, element, attrs) {
console.log(scope.imgData);
}
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app='app'>
<sig-panel img-data="'test'"></sig-panel>
</div>
assignable example:
angular.module('app', [])
.controller('myController', function($scope) {
$scope.test = 'test';
})
.directive('sigPanel', sigPanel);
function sigPanel() {
return {
restrict: 'E',
scope: {
imgData: "="
},
template: '<canvas style="border:1px solid black;"></canvas>',
link: function(scope, element, attrs) {
console.log(scope.imgData);
scope.imgData = 'bob';
console.log(scope.imgData);
}
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app='app' ng-controller='myController'>
<sig-panel img-data="test"></sig-panel>
{{ test }}
</div>

Isoleted scope also for transclude?

I want to add my custom directive within my other directive.
Second directive should use scope from first directive.
Problem is that first directive has isolated scope and apperently it is also isolated for second directive and in my opinion it shouldn't because I'm using transclude.
Here is example. When I comment scope: {test:"#"} all wroks as it should.
How to fix it?
angular.module("myApp", [])
.controller("initCtrl", function ($scope) {
});
angular.module('myApp')
.directive('firstDirective', ['$timeout', function ($timeout) {
return {
restrict: 'E',
scope: {test: "#"}, //everything is OK when I comment that.
transclude: true,
template: '<div> First Directive {{myVar}} {{test}}<div ng-transclude></div></div>',
controller: "firstDirectiveCtrl",
link: function (scope, element, attributes) {
}
};
}])
.controller("firstDirectiveCtrl", ['$scope', '$timeout', function ($scope, $timeout) {
$scope.myVar = "Var from first directive";
$timeout(function () {
$scope.myVar = "Var from first directive has changed";
}, 1000);
}])
.directive('secondDirective', [function () {
return {
restrict: 'E',
scope: false,
require: "^firstDirective",
template: '<div> Second Directive {{myVar}}</div>',
link: function (scope, element, attributes) {
//scope.myVar = "Var from second directive";
}
};
}]);
<!DOCTYPE html>
<html data-ng-app="myApp">
<head lang="en">
<meta charset="UTF-8">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<title></title>
</head>
<body>
<div ng-controller="initCtrl" class="container">
<first-directive test="test">
<second-directive></second-directive>
{{myVar}}
<br><i>no var unless I comment scope: {test:"#"} i first directive.</i>
</first-directive>
</div>
</body>
</html>
You can access $parent scope ex. $parent.myVar.
Works only in angular 1.3
angular.module("myApp", [])
.controller("initCtrl", function ($scope) {
});
angular.module('myApp')
.directive('firstDirective', ['$timeout', function ($timeout) {
return {
restrict: 'E',
scope: {
test:"#",
//myVar:"="
},
transclude: true,
template: '<div> First Directive {{myVar}} {{test}}<div ng-transclude></div></div>',
controller: "firstDirectiveCtrl",
link: function (scope, element, attributes) {
}
};
}])
.controller("firstDirectiveCtrl", ['$scope', '$timeout', function ($scope, $timeout) {
$scope.myVar = "Var from first directive";
$timeout(function () {
$scope.myVar = "Var from first directive has changed";
}, 1000);
this.getMyVar = function () {
return $scope.myVar;
};
//console.log($scope.getMyVar());
}])
.directive('secondDirective', [function () {
return {
restrict: 'E',
scope: false,
require: "^firstDirective",
template: '<div> Second Directive {{$parent.myVar}}</div>',
link: function (scope, element, attributes, ctrl) {
//console.log(scope.$parent);
//console.log(ctrl);
// console.log(ctrl.myVar);
// console.log(ctrl.getMyVar());
//scope.myVar = "Var from second directive";
}
};
}]);
<!DOCTYPE html>
<html data-ng-app="myApp">
<head lang="en">
<meta charset="UTF-8">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.min.js"></script>
<title></title>
</head>
<body>
<div ng-controller="initCtrl" class="container">
<first-directive test="test">
{{$parent.myVar}}
<second-directive></second-directive>
</first-directive>
</div>
</body>
</html>
It is because the first directive uses isolated scope that myVar is not visible inside of the directive's template. myVar is visible inside of the transcluded contents because it is linked to the transclusion scope, which is a child scope of your parent controller scope. The transclusion scope, and firstDirective's isolated scope are sister scopes - but separate from eachother.
Note: This is only true for 1.2+. In 1.3, it looks like things have changed, and transclusion scope is a child scope of the next scope higher up the chain.
To fix this, you just have to pass myVar to your isolated scope:
.directive('firstDirective', ['$timeout', function ($timeout) {
return {
restrict: 'E',
scope: {test: "#", myVar: "="}, //pass myVar into your isolated scope.
transclude: true,
template: '<div> First Directive {{myVar}} {{test}}<div ng-transclude></div></div>',
controller: "firstDirectiveCtrl",
link: function (scope, element, attributes) {
}
};
}])
HTML
<div ng-controller="initCtrl" class="container">
<first-directive test="test" my-var="myVar">
<second-directive></second-directive>
{{myVar}}
...
</first-directive>
</div>
angular.module("myApp", [])
.controller("initCtrl", function ($scope) {
});
angular.module('myApp')
.directive('firstDirective', ['$timeout', function ($timeout) {
return {
restrict: 'E',
scope: {test: "#", myVar:"="}, //everything is OK when I comment that.
transclude: true,
template: '<div> First Directive {{myVar}} {{test}}<div ng-transclude></div></div>',
controller: "firstDirectiveCtrl",
link: function (scope, element, attributes) {
}
};
}])
.controller("firstDirectiveCtrl", ['$scope', '$timeout', function ($scope, $timeout) {
$scope.myVar = "Var from first directive";
$timeout(function () {
$scope.myVar = "Var from first directive has changed";
}, 1000);
}])
.directive('secondDirective', [function () {
return {
restrict: 'E',
scope: false,
require: "^firstDirective",
template: '<div> Second Directive {{myVar}}</div>',
link: function (scope, element, attributes) {
//scope.myVar = "Var from second directive";
}
};
}]);
<!DOCTYPE html>
<html data-ng-app="myApp">
<head lang="en">
<meta charset="UTF-8">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<title></title>
</head>
<body>
<div ng-controller="initCtrl" class="container">
<first-directive test="test" my-var="myVar">
<second-directive></second-directive>
{{myVar}}
<br><i>no var unless I comment scope: {test:"#"} i first directive.</i>
</first-directive>
</div>
</body>
</html>

Why isn't this field binding in my directive?

I have a directive with 2-way binding on the dataSourceModel scope variable, but for some reason, it is showing as undefined in the directive. Am I doing something wrong here?
Plunker: http://plnkr.co/edit/LxWMbY9qtDSBUPWNqWV7?p=preview
Code:
Html:
<div ng-controller='TestCtrl'>
<test-directive
selected-id='selectedId'
data-source-model='workOrderItems'> <!-- This does not work -->
</test-directive>
{{workOrderItems}} <!-- this works -->
</div>
Script:
var app = angular.module("testApp", []);
app.controller('TestCtrl', ['$scope', function ($scope) {
$scope.workOrderItems = 'abcd';
$scope.selectedId = '123';
}]);
app.directive('testDirective',function () {
return {
restrict: 'E',
scope: {
selectedId: '=',
dataSourceModel: '='
},
replace: true,
template: "<div></div>",
link: function (scope, element, attrs) {
console.log(scope.selectedId, scope.dataSourceModel);
}
}
});
data- is prefix for custom HTML5 attributes, so the data-source-model='workOrderItems' is translated to just sourceModel in your directive.
Try renaming your directive attribute to something that doesn't start with data (or reference it in HTML as data-data-source-model) and it should work.

Assigning value to scope in directive not working

I have a custom directive that may or may not have an attribute with a value. If the user doesn't specify a value for the attribute, I want to assign a default. However, when I do that the value is always null on my scope, as with this Plunkr
What am I doing wrong?
Directive:
var app = angular.module('app', []);
app.directive('variable', function(){
return {
restrict: 'E',
replace: true,
template: '<h2>Directive value: {{ test }}</h2>',
scope: {
test: '#'
},
controller: function($scope){
$scope.test = 'code assignment';
}
};
});
HTML:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body ng-app="app">
<variable></variable>
<variable test="html assignment"></variable>
</body>
</html>
The $scope.test assignment is happening before the template is built with the directive attributes you are passing in. Because you are not declaring any test attribute, the directive is rendered with $scope.test as undefined.
If you just want a default value you should do the following and you will not have the need to define the controller, making your code cleaner and smaller.
app.directive('variable', function(){
return {
restrict: 'E',
replace: true,
template: '<h2>Directive value: {{ test || "default value" }}</h2>',
scope: {
test: '#'
}
};
});
See this working demo
But if you really need to assign default values to directive's scope you can use compile function like this:
app.directive('variable', function() {
return {
restrict: 'E',
replace: true,
template: '<h2>Directive value: {{ test }}</h2>',
scope: {
test: '#'
},
compile: function(element, attrs) {
if (!attrs.test) {
attrs.test = 'default value';
}
}
};
});
See this working demo
I believe you need to use the link() method. That way you can check if the scope variable is null and assign a default, and then manually create the template and add it to the element. Note that the scope variable is still binded.
app.directive('variable', function(){
return {
restrict: 'E',
replace: true,
scope: {
test: '#'
},
link: function(scope, element) {
if(scope.test === null) {
scope.test = 'default value';
}
var template = "<h2>Directive value: {{ test }}</h2>";
element.html(template);
}
};
});

Resources