How to access isolated scope property from static directive template in Angular? - javascript

Controller:
app.controller('MainCtrl', ['$scope', function($scope) {
$scope.temp = {
'name': 'Test'
};
}]);
Template:
<custom-field ng-model="temp.name">
<md-input-container class="addon-menu">
<label>Name</label>
<input ng-model="ngModel" type="text" ng-focus="setLastFocusedElement($event)" />
</md-input-container>
</custom-field>
Directive:
app.directive('customField', function($timeout) {
return {
restrict: 'E',
scope: {
ngModel: '='
},
link: function($scope, $element, $attrs) {
console.log($scope.ngModel); // prints "test"
}
};
});
The problem is that once template is rendered, I can't see the value attached to input - it's empty, but I'm expecting to works, because inside link function it's printed correctly.

You are trying to access the directive scope in your template as the controller's scope. Move the markup inside the directive's template instead.
Directive:
app.directive('customField', function($timeout) {
return {
restrict: 'E',
scope: {
ngModel: '='
},
link: function($scope, $element, $attrs) {
console.log($scope.ngModel); // prints "test"
},
template: '<md-input-container class="addon-menu"><label>Name</label><input ng-model="ngModel" type="text" ng-focus="setLastFocusedElement($event)" /></md-input-container>'
};
Template:
<custom-field ng-model="temp.name"></custom-field>
You can also use separate html files as directive templates, which is good practise.

Are you trying to see the value in controller?
Please try $parent.$scope to see if value exist.

Related

AngularJS Custom directives - Issue accessing controllerAs variables/objects in directive link

I've just started refactoring my code to do DOM manipulation and functions in directives instead of inside controllers as I had previously been doing, but I'm having issues accessing variables/objects defined using controllerAs 'this' syntax within the controller from which I need them to be inherited.
I've tried using bindToController as below, where I've added the different objects that are used in the directive function, but when I try to access these withink the 'link', they're all returning as undefined in the console.
Example here. 'this.test' defined in controller, tried accessing this in the directive in a console log message.
Controller:
app.controller('notificationsController', function($scope, $state, $http, $document, $mdDialog, $filter, $timeout, $mdToast) {
this.test = 'TEST';
Directive:
app.directive('clearNotifications', function($mdDialog, $mdToast, $timeout) {
return {
controller: 'notificationsController',
controllerAs: 'notifications',
scope: {},
bindToController: {
notifications: '=',
filters: '=',
test: '#'
},
restrict: 'A',
link: function(scope, element, attrs) {
element.bind('click', function() {
console.log('notifications.test string test: ' + notifications.test);
this in controller is different with controllerAs in directive , in directive you should use ctrl or model to binding.
var app = angular.module("app", []);
app.controller("notificationsController", function($scope) {
this.test = "foo!";
})
app.directive("clearNotifications", function() {
return {
controller: 'notificationsController',
controllerAs: 'notifications',
scope: {},
bindToController: {
notifications: '=',
filters: '=',
test: '#'
},
restrict: 'A',
link: function(scope, element, attrs, ctrl) {
element.bind('click', function() {
console.log('notifications.test string test: ' + ctrl.test);
})
}
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<button clear-notifications>clearNotifications</button>
</div>

AngularJS: Passing function to directive

I got a problem by passing a function to a directive ( familiar to this post: AngularJS - pass function to directive but i can´t get it working)
Here is my Code:
Directive:
.directive('testdirective', function(){
return{
restrict: 'E',
scope: {
onClick: '&'
},
controller: 'TestController',
controllerAs: 'tc',
bindToController: true,
template: '<div><button ng-click="onClick()">What UP</button></div>',
replace: true
}
})
Controller:
TestController.$inject = ["$scope"];
function TestController($scope) {
$scope.testFunction = function(){
alert("I´m the alert of the TestContoller");
};
$scope.test = 'test';
}
HTML:
<div>
<testdirective on-click="testFunction()"></testdirective>
</div>
What I want sounds very simple, I just want to pass the function to the directive and execute it with the ng-click on the button.
For me my code looks exactly like this fiddle
but mine is not working :/
Would be awesome if someone got some hints for me.
EDIT
My directive will need his own controller !
Later the function to be passed in will come from another controller !!!
The fiddle is not the same as your code.
You have set the controller of your directive to be "TestController". I assume what you wanted to do was:
.directive('testdirective', function(){
return{
restrict: 'E',
scope: {
onClick: '&'
},
template: '<div><button ng-click="onClick()">What UP</button></div>',
replace: true
}
});
and in your HTML,
<div ng-controller="TestController">
<testdirective on-click="testFunction()"></testdirective>
</div>
EDIT: Based on OP's comment
app.directive('testdirective', function(){
return{
restrict: 'E',
scope: {
onClick: '&'
},
template: '<div><button ng-click="tc.onClick()">What UP</button></div>',
replace: true,
controller: 'TestController',
controllerAs: 'tc',
bindToController: true
}
});
app.controller('TestController', function ($scope) {
console.log($scope);
}) ;
app.controller('AnotherController', function ($scope) {
$scope.testFunction = function(){
alert("I´m the alert of the TestContoller");
};
$scope.test = 'test';
});
And, your HTML
<div ng-controller="AnotherController">
<testdirective on-click="testFunction()"></testdirective>
</div>
You are telling the directive to bindToController. So within the directive's template, onClick is bound to the controller and not the scope. So, you access the onclick via the controller as tc.onClick() in the directive's template.
You may want to pass a method as a reference:
1.Pass the function as a reference and not a call:
<div>
<testdirective on-click="testFunction"></testdirective>
</div>
2.Update the directive:
.directive('testdirective', function(){
return{
restrict: 'E',
scope: {
onClick: '='
},
template: '<div><button ng-click="onClick()">What UP</button></div>',
replace: true
}
});
JSFIDDLE.
Well, in your testdirective,you defined controller TestController.
The testFunction() that you try to calling via onClick directive scope parameter is defined in controller TestController which is directive controller.
So, rather than calling via onClick you can call directly like
template: '<div><button ng-click="testFunction()">What UP</button></div>'.
Its very confusing ,you defining controller in directive and again referring it's one function via same directive's scope parameter which look like recursive.
If you want to call via directive scope parameter then you should do belowe changes.
for e.g.
JS :
<div ng-controller="TestController" ng-app="dr">
<testdirective on-click="testFunction()"></testdirective>
</div>
app.directive('testdirective', function() {
return{
restrict: 'E',
scope: {
onClick: '&'
},
template: '<div><button ng-click="onClick()">What UP</button></div>',
replace: true
}
});
Directivie:
.directive('testdirective', function(){
return{
restrict: 'E',
scope: {
onClick: '=onClick'
},
controller: 'TestController',
controllerAs: 'tc',
bindToController: true,
template: '<div><button ng-click="onClick()">What UP</button></div>',
replace: true
}
})
use '=' instead of '&' so you can fetch the html function in your directive. and you can simply pass onClick parameter through HTML
HTML:
<div>
<testdirective on-click="testFunction()"></testdirective>
</div>

How to access the scope of a parent's controller's in a directive's controller?

I have a custom directive nested in a parent div who's controller sets a variable value to its scope, such as:
html
<div ng-controller="mainCtrl">
<p>{{data}}</p>
<myDirective oncolour="green" offcolour="red" data="data"></myDirective>
</div>
javascript
app.controller("mainCtrl", function($scope){
$scope.data= 1;
});
app.directive("myDirective", function() {
return {
restrict: 'E',
scope: {
oncolour: '#',
offcolour: '#',
data: '='
},
template: '<p>{{data}} is {{state}}</p>',
controller: function($scope){
console.log($scope.data); //undefined!
/* logic to set $scope.state depending on $scope.data */
};
};
});
I can pass the value of data to the directive as I can see the {{data}} off the template being parsed correctly.
However, $scope.data is undefined in the directive's controller. I need to apply some logic there depending on this variable like if data==1, then state="on", else state="off", so I can then apply the oncolour and offcolour appropriately.
Any idea how this can be achieved?
"transclude" options is necessary:
transclude: true,
controller: ['$scope', function($scope) {
console.log($scope.data);
}],
You miss the $ before the scope in your directive. The reason you will have undefined is because in the directive $scope is not the same as return scope. You have to match them.
app.directive("myDirective", function() {
return {
restrict: 'E',
$scope: {
oncolour: '#',
offcolour: '#',
data: '='
},
template: '<p>{{data}} is {{state}}</p>',
controller: function($scope){
console.log($scope.data); //undefined!
/* logic to set $scope.state depending on $scope.data */
};
};
});
change $scope to scope, take a look to angular directive documentation, goto end of page and check sample code
app.directive("myDirective", function() {
return {
restrict: 'E',
scope: {
oncolour: '#',
offcolour: '#',
data: '='
},
template: '<p>{{data}} is {{state}}</p>',
controller: function(scope){
console.log(scope.data); //undefined!
/* logic to set $scope.state depending on $scope.data */
};
};
});
Check AngluarJS normalization.
The directive elements name is wrong:
<myDirective ... >
It should be
<my-directive ...>
And make sure to access scope instead of $scope.
My bet is that the binding is failing as data is a primitive, see https://github.com/angular/angular.js/wiki/Understanding-Scopes
Try and change:
app.controller("mainCtrl", function($scope){
$scope.data= 1;
});
And
<div ng-controller="mainCtrl">
<p>{{data}}</p>
<myDirective oncolour="green" offcolour="red" data="data"></myDirective>
</div>
Into:
app.controller("mainCtrl", function($scope){
$scope.data= {
value: 1
};
});
And
<div ng-controller="mainCtrl">
<p>{{data.value}}</p>
<myDirective oncolour="green" offcolour="red" data="data.value"></myDirective>
</div>

Prevent angular directive from compiling more than once

I have a directive that I manually render once:
let html = '<div>'
let scope = $rootScope.$new(true)
scope.foo = 42
let element = $compile(html)($scope)
element.appendTo(container)
After that, I don't want it to ever re-render, even if there is a $digest on the $rootScope. Is that possible with Angular?
If you mean you wish to remove all bindings on your directive, you can call $destroy to remove any bindings on you have. Consider this example, where both directives bind message
<input ng-model="message" id="dirA" dir-a />
<input ng-model="message" id="dirB" dir-b />
<input ng-model="message" />
app.directive('dirA', [function () {
return {
scope: true,
restrict: 'A',
link: function (scope, elem, attrs) {
}
}
}]);
app.directive('dirB', [function () {
return {
scope: true,
restrict: 'A',
link: function (scope, elem, attrs) {
}
}
}]);
app.controller('ctrl', ['$scope', '$timeout', function($scope, $timeout) {
$scope.message = 'hello'
$timeout(function(){
// destroy scope for dirA
angular.element(document.getElementById('dirA')).scope().$destroy()
})
}]);
JSFiddle Link

Creating an angular directive that binds a service?

Not sure if I am misunderstanding how directives are created here. Say for example I have a controller such as:
angular.module('myApp.controllers').controller('MyController', ['$scope', 'MyService', function($scope, MyService) {
$scope.restangularService = MyService;
}
I then have a directive such as:
angular.module('myApp.directives').directive('myGrid', function() {
return {
restrict: 'A',
templateUrl: 'some/path/here.html',
scope: {
restangularService: '&'
},
controller: ['$scope', function($scope) {
//access $scope.restangularService to run some queries
}
};
});
I then use my directive as such:
<div data-my-grid data-restangular-service='restangularService'></div>
I would expect that in my directive I could access $scope.restangularService and make calls however it's not being populated correctly. Am I doing this totally wrong? Any input? I have a feeling I need to be using the ngModel directive somehow.
The "&" prefix of an isolate scope value in a directive provides "one-way binding" which makes available a getter function in the directive's scope.
Any changes you make to the object will not make their way back up to the parent controller of the directive (it is "read-only"). So you can't access your 'restangularService' variable as you would in the controller's scope, without calling the getter function:
angular.module('myApp.directives', []).directive('myGrid', function() {
return {
restrict: 'A',
templateUrl: 'some/path/here.html',
scope: {
restangularService: '&'
},
controller: ['$scope', function($scope) {
console.log($scope.restangularService()); // outputs service value
}]
};
})
Alternatively, you could use "=", which would allow you directly access the scope object you pass in:
angular.module('myApp.directives', []).directive('myGrid', function() {
return {
restrict: 'A',
templateUrl: 'some/path/here.html',
scope: {
restangularService: '='
},
controller: ['$scope', function($scope) {
console.log($scope.restangularService); //outputs service value
}]
};
})
Plunk demonstrating both types

Categories