I have directive that dynamically sets the header bar content for a given application state.
I would like to be able to access the functions and variables in the Controller of the current view, but I am only ever able to access my RootCtrl.
The directive looks like this.
return {
restrict: 'EA',
template: "<div ng-include='getState()'></div>",
transclude: true,
scope: false,
controller: ['$scope', '$state', function($scope, $state) {
//some logic to retrieve and return the correct header template html
}],
link: function(scope, element, attrs){
console.log(scope.test);
console.log(scope.test2);
}
}
And the controllers.
.controller('RootCtrl', function($scope, $state, $location, $rootScope) {
$scope.test = 'hello';
//...
})
.controller('ContactsCtrl', function($scope, $state, CustomerService) {
console.log('Contacts init');
$scope.test2 = 'hello 2';
//...
})
And when I navigate to the contacts state, the output looks like this.
hello
undefined
Contacts init
What should I do if I want to be able to access the test2 variable?
You will need to use the require property inside your directive.
This will make the scope of the defined controllers available inside the link function as 4th argument. You can access the scopes as an array inside the link function then.
Your code may look like:
return {
restrict: 'EA',
template: "<div ng-include='getState()'></div>",
transclude: true,
scope: false,
require:['^RootCtrl', '^ContactsCtrl'],
controller: ['$scope', '$state', function($scope, $state) {
//some logic to retrieve and return the correct header template html
}],
link: function(scope, element, attrs, requiredControllers){
console.log(requiredControllers[0].test);
console.log(requiredControllers[1].test2);
}
}
See the Angular documentation for Directives for some more examples (under the title Creating Directives that Communicate) and the explanation of the ^controller syntax.
Related
I am very new to Angular. I am trying to read/pass some data to my angular directive from the template.
<div class="col-md-6" approver-picker="partner.approverPlan.data" data-pickerType="PLAN"></div>
I have this in my angular template and I have this in different places. So I want to know in my Angular code, which picker is being clicked.
I am thinking to read the data-pickerType value in my directive.(I am able to read this in jQuery but do not know how to in Angular)
This is my directive code.
Partner.Editor.App.directive('approverPicker', [
'$compile', function ($compile) {
return {
scope: {
"approvers": "=approverPicker"
},
templateUrl: '/template/assets/directive/ApproverPicker.html',
restrict: 'EA',
link: function ($scope, element) {
...........
}
};
}
]);
How can I read the data-pickerType value in the directive or is there a better way of doing this?
The data attributes can be accessed in Angular directive by passing attrs variable in the link function.
Partner.Editor.App.directive('approverPicker', [
'$compile', function ($compile) {
return {
scope: {
"approvers": "=approverPicker"
},
templateUrl: '/template/assets/directive/ApproverPicker.html',
restrict: 'EA',
link: function ($scope, element, attrs) { //passing attrs variable to the function
//accessing the data values
console.log(attrs.pickertype);
//you can access any html attribute value for the element
console.log(attrs.class);
}
};
}
]);
question regarding constants within angularjs. I have the following constants created within app.js:
... angular
.module('blocTime', ['firebase', 'ui.router'])
.config(config)
.constant('STOP_WATCH', {
"workTime": 1500,
"breakTime": 300
});
})();
I've injected the constant inside my directive as follows:
(function() {
function clockTimer($interval, $window, STOP_WATCH) {
return {
templateUrl: '/templates/directives/clock_timer.html',
replace: true,
restrict: 'E',
scope: {},
link: function(scope, element, attributes) {
console.log(STOP_WATCH.workTime); ...
...
angular
.module('blocTime')
.directive('clockTimer', clockTimer);
I can console log the constant from my directive just fine. However, my view is not rendering the constant. HTML:
<div>
<div class="stop-watch">{{ STOP_WATCH.workTime }}</div>
It comes back as undefined. Thoughts as to why or how to make it display in the view? Thanks
Figured it out. Within my directive I had to add scope.STOP_WATCH = STOP_WATCH:
(function() {
function clockTimer($interval, $window, STOP_WATCH) {
return {
templateUrl: '/templates/directives/clock_timer.html',
replace: true,
restrict: 'E',
scope: {},
link: function(scope, element, attributes) {
scope.STOP_WATCH = STOP_WATCH;
...
I'm trying to pass a boolean value from my controller into my isolated scope directive. When I console.log(attrs) from the directive's link function, the someBoolean attribute is a string, rendering the actual text "main.bool" instead of a true or false value. When I toggle the boolean value from the outer controller, I want it to be updated in the directive.
https://plnkr.co/edit/80cvLKhFvljnFL6g7fg9?p=preview
app.directive('myDirective', function() {
return {
restrict: 'E',
replace: true,
scope: {
someBoolean: '='
},
templateUrl: 'myDirective.html',
link: function(scope, element, attrs) {
console.log(scope);
console.log(attrs);
},
controller: function($scope, $element, $attrs) {
console.log(this);
},
controllerAs: 'directiveCtrl',
bindToController: true
};
});
Controller
app.controller('MainCtrl', function($scope) {
var vm = this;
vm.bool = true;
vm.change = function() {
vm.bool = !vm.bool;
}
});
The template
<div>
Inside directive: {{someBoolean}}
</div>
As you have attached your directive Controller to directiveCtrl instead of mainCtrl, you'll access the variable someBoolean using directiveCtrl.someBoolean.
In this case, change the HTML to:
<div>
Inside directive: {{directiveCtrl.someBoolean}}
</div>
Plunker.
Another solution would be to remove the bindToController property inside your directive. With this, you don't need to use the controller name before the variable. Working Plunker.
Read more about this bindToController feature here.
first time asker. Apologies if my jargon isn't quite right I'm new to angularjs
I have a controller which gets a list of products with a HTTP call
contractManagementControllers.controller('PriceBandsCtrl', ['$scope', '$routeParams', '$http', '$location',
function ($scope, $routeParams, $http, $location)
{
$http.get('products').success(function (products)
{
$scope.productList = products
})
}
And a directive which I would like to have access to that product list.
contractManagementControllers.directive("priceBands",function($http)
{
return {
scope: true,
restrict: 'AE',
replace: 'true',
templateUrl: 'Partials/PriceBand.html',
link: function ($scope, ele, attrs, c)
{
// use $scope.productList
}
});
My issue is with the order in which things happen. The controller function runs first, followed by the directive link function, followed by the callback which sets the product list. As such $scope.productList is undefined in the directive link function and gives an error
Is there a way to force the link function to wait until the callback has completed?
Set default value to productList in order not get error about undefined variable
contractManagementControllers.controller('PriceBandsCtrl', ['$scope', '$routeParams', '$http', '$location',
function ($scope, $routeParams, $http, $location)
{
$scope.productList = [];
$http.get('products').success(function (products)
{
$scope.productList = products
})
}
and then watch for changes of the productList in directive:
contractManagementControllers.directive("priceBands",function($http)
{
return {
scope: true,
restrict: 'AE',
replace: 'true',
templateUrl: 'Partials/PriceBand.html',
link: function ($scope, ele, attrs, c)
{
$scope.watch('productList', function(newValue, oldValue) {
//Perform here if you need
});
}
});
no need of waiting for callback in angularjs. just put the $scope.productList=[]; in your controller as first line. it will not give undefined to directive.
In your directive link function just write the $watch function to watch changes in element.
I have 2 simple directives...
the parent directive:
.directive('modal', [function () {
return {
replace: true,
scope: {
/* attributes */
},
templateUrl: 'modal.tpl.html',
transclude: true,
link: function (scope) {
/* code */
}
};
the child directive
.directive('keypad', function () {
'use strict';
return {
templateUrl: 'keypad.tpl.html',
scope: {
value: '=',
},
link: function (scope, element, attrs) {
/* code */
}
};
and finally the controller:
.controller('ctrl', ['$scope', '$timeout', function ($scope, $timeout) {
$scope.$watch('howMuch', function(){
console.log('wont work ;-(');
});
}
and my template looks like this:
<div modal>
<div keypad class="keypad" value="howMuch"></div>
</div>
Any idea why the child directive can't change the howMuch value on the controller?
The same code but WITHOUT the parent directive works PERFECT.
The parent directive has an isolate scope. You didn't show the scope attributes, but howMuch needs to be accessed via a property in your isolated scope in order to update the value in the controller's scope.