I'm using angular 1.5 to build a directive that I can use in different situations. I want to be able to pass in data from the controller to the directive as an object. My set up is something like this:
Controller:
function ControllerWrapper($scope, $location, $window){
$scope.depth= 99;
$scope.filter = {filters: [{column: 'stage', values: ['Closed']}]};
}
HTML:
<div ng-controller="ControllerWrapper">
<my-great-directive max-depth="{{depth}}" filters="filter"></my-great-directive>
</div>
Directive return
return {
restrict: 'E',
templateUrl: function(element, attributes) {
return attributes.templateUrl;
},
link: function(scope, element, attributes) {
var obj = scope.$eval(attributes.filters);
var dir = scope.$eval(attributes.dir);
scope.$watch("filters",function(newValue,oldValue) {
if(scope.vm.dir != null){
scope.vm.dir.rows = scope.filterTreeGrid();
}
}, true);
},
controller: DirectiveController,
controllerAs: 'vm',
bindToController: true,
scope: {
maxDepth: '#',
filters: '=?'
}
};
From what I've read the filters: '=' should be enough to pass the data through but I'm getting a null after it tries to resolve it. Any suggestions?
Related
I am creating a custom directive in angularjs, but for some attributes i am receiving undefined value.
function processinfo(ProcessInfoService, $timeout) {
console.log("processInfo directive");
return {
restrict: 'E',
scope: {
start: '=',
end: '=',
uuid: '='
},
templateUrl: 'k2-modules/js/directives/templates/processInfoTemplate.html',
controller: function($scope) {
var self = this;
console.log($scope.uuid); // undefined
console.log($scope.end); // 164982555555
console.log($scope.start); // 0
self.processData = ProcessInfoService.getInfo($scope.start, $scope.end);
}
}
}
<processinfo start="0" end="164982555555" uuid="a57cf6f8"></processinfo>
For uuid I am getting undefined but for end and start values everything is working fine. I don't know why this is happening since syntax is same for all three. Any help will be appreciated
Your mixing directive syntax with component/controller syntax, in directives $scope is called scope (no dollar). Here's the correct syntax to build a angularjs directive:
angular.module('app').directive('myDirective', MyDirective);
MyDirective.$inject = ['$timeout'];
function MyDirective($timeout) {
return {
scope: {
'propBinding1': '<',
'propBinding2': '&'
},
replace: true,
restrict: 'EA',
templateUrl: 'path to html',
link: function link(scope, element, attrs) {
//... do stuff here ...
}
};
}
Using Angular 1.6 I am defining an directive like so:
angular
.module('myApp')
.directive('lyEntity', lyEntity);
function lyEntity() {
return {
restrict: 'E',
scope: {
model: '=',
type: '#'
},
controller: 'lyEntityController',
controllerAs: 'vm',
bindToController: true,
templateUrl: function (elem, attrs) {
return 'components/_templates/' + attrs.type + '.html'
}
};
}
But using it in another template like so:
<ly-entity model="vm.entity" type="{{vm.type}}"></ly-entity>
will result in templateURL components/_templates/{{vm.type}}.html
How can I hand over the value of vm.type to be used in my templateUrl function?
Yeah, it can't be done the way you're trying to do it because templateUrl function is called before the attributes are interpolated. One way to achieve this would be using ng-include.
return {
restrict: 'E',
scope: {
type: '#'
},
link: function(scope, element, attrs){
$scope.templateUrl = 'components/_templates/' + attrs.type + '.html';
},
template: '<ng-include src="templateUrl"/>'
};
So, construct the template url in controller, have ng-include as the template and point the src to the constructed template url.
Here's a good article on how to have dynamic templates: https://medium.com/angularjs-meetup-south-london/angular-directives-using-a-dynamic-template-c3fb16d03c6d#.mizywdk6s
Thanks to #Chantu, I found a solution which is working for me:
Directive:
angular
.module('myApp')
.directive('lyEntity', lyEntity);
function lyEntity() {
return {
restrict: 'E',
scope: {
model: '=',
type: '='
},
controller: 'lyEntityController',
controllerAs: 'vm',
bindToController: true,
template: '<ng-include src="templateUrl"/>'
};
}
Controller:
$scope.templateUrl = 'components/_templates/' + vm.type + '.html';
and call it:
<ly-entity model="vm.entity" type="vm.type"></ly-entity>
I have created an AngularJS directive as shown below.
In the associated controller, I compute the value of a variable text as "SomeText". I want this text to replace Hello World!! in the template attribute of the directive. How can I do it?
My HTML:
<myp-directive myarg="myObject"></myp-directive>
My Directive:
myApp.directive('mypDirective',function(){
return {
restrict:'E',
scope: {
myarg: '='
},
controller: 'DirectiveCtrl',
controllerAs: 'directiveCtrl',
bindToController: true,
template: 'Hello World!!'
};
}
);
My Controller:
myApp.controller('DirectiveCtrl', function($scope){
var self = this;
$scope.$watch(function() {return self.prediction;}, function (newVal, oldVal)
{
if (newVal !== oldVal && newVal !== null){
var text = "SomeText";
}
});
});
Since you use the controllerAs: 'directiveCtrl' configuration you can simply assign "SomeText" as a variable of the controller (self) and it will be available in the template.
Pascal Precht wrote quite an extensive explanation about controllerAs.
Controller
myApp.controller('DirectiveCtrl', function($scope){
var self = this;
self.text = "Hello World!!";
$scope.$watch(function() {return self.prediction;}, function (newVal, oldVal)
{
if (newVal !== oldVal && newVal !== null){
self.text = "SomeText";
}
});
});
Directive
myApp.directive('mypDirective',function(){
return {
restrict:'E',
scope: {
myarg: '='
},
controller: 'DirectiveCtrl',
controllerAs: 'directiveCtrl',
bindToController: true,
template: '{{directiveCtrl.text}}'
};
}
);
Use scope. Bind the text 'Hello World' to a scope variable (data) and bind it in the template as {{data}}. The change the value of the scope variable from the controller.
Take a look at this fiddle
Directive
myApp.directive('mypDirective', function() {
return {
restrict: 'E',
scope: {
myarg: '='
},
controller: 'DirectiveCtrl',
controllerAs: 'directiveCtrl',
bindToController: true,
template: '{{data}}',
link: function(scope, elem, attr, directiveCtrl) {
scope.data = "Hello World!!!"
}
};
});
I need some help on how to pass controllers definitions to inner directive nested in outer directive. Please see http://plnkr.co/edit/Om2vKdvEty9euGXJ5qan for a (not)working example.
Is there any way to make angular interpolate what is passed on script.js#46 as item.ctrlName?
How to use controllerAs syntax in inner directive?
1) if you need the inner directive to have the parent controller you can use the require params on the inner directive. Something like this
angular.module('docsTabsExample', [])
.directive('outer', function() {
return {
restrict: 'E',
transclude: true,
scope: {},
templateUrl: '...', // or template
controllerAs: 'outer',
bindToController: true, // This bind the scope with the controller object
controller: function(scope, element, attrs) {
}
}
})
.directive('inner', function() {
return {
require: '^outer',
restrict: 'E',
transclude: true,
scope: {
title: '#'
},
controllerAs: 'inner',
bindToController: true, // This bind the scope with the controller object
templateUrl: '...', // or template
controller: function(scope, element, attrs, tabsCtrl) {
// tabsCtrl and all the methods on the outer directive
},
};
});
2) You have set controller: controller and controller is a empty function, but you can set there a function like i did before and make sure of put the bindToController: true
I found the solution going step down (up ?) with the abstraction. I'm dynamically constructing the whole directive configuration object and then lazy registering it.
See http://plnkr.co/edit/pMsgop6u51zPLqkfWaWT
angular.module('app', ['moduleLazyLoader'])
.controller('mainCtrl', ['$log', function ($log) {
this.list = [
{
name: 'asd',
ctrl: [
'ItemAsdCtrl',
function () {
$log.debug('ItemAsdCtrl');
}
]
},
{
name: 'xyz',
ctrl: [
'ItemXyzCtrl',
function () {
$log.debug('ItemXyzCtrl');
}
]
}
];
}])
.directive('outer', ['factoryLazyLoader', '$log', '$compile', function (factoryLazyLoader, $log, $compile) {
function controller () {}
return {
restrict: 'E',
controller: controller,
controllerAs: 'outer',
bindToController: true,
scope: {
list: '=list'
},
link: function (scope, element, attributes) {
var directives = [];
scope.outer.list = scope.outer.list.map(function (ele, idx) {
var directiveSuffix = ele.ctrl[0];
directiveSuffix[0].toUpperCase();
var directiveName = 'item' + directiveSuffix,
directiveAttrName = directiveName.split(/(?=[A-Z])/).join("-").toLowerCase();
directives.push(directiveAttrName);
factoryLazyLoader.registerDirective([
directiveName,
function () {
return {
restrict: 'E',
replace: true,
controller: ele.ctrl[1],
controllerAs: ele.ctrl[0],
bindToController: true,
template: '<div>{{' + ele.ctrl[0] + ' | json}}</div>',
scope: {
item: '=item'
}
}
}
])
return ele;
});
var tpl = '<div>';
angular.forEach(directives, function (val, idx) {
tpl += '<' + val +' item="outer.list[' + idx + ']">' + '</' + val + '>';
});
tpl += '</div>'
// debugger;
element.replaceWith($compile(tpl)(scope))
}
};
}])
I have an element directive and I want to know if I can get parameters from routeProvider to render my template and set it up in my controller.
adminDash.directive('hospitals', function() {
return {
restrict: 'E',
templateUrl: 'www/partials/admin/hospitals.html',
controller: 'AdminHospitalsController',
controllerAs: 'hospitalsCtrl',
};
});
How can I get any parameters in my element directive?
You can isolate the scope of the directive, like this:
adminDash.directive('hospitals', function() {
return {
restrict: 'E',
templateUrl: 'www/partials/admin/hospitals.html',
controller: 'AdminHospitalsController',
controllerAs: 'hospitalsCtrl',
scope: {
paramValue: '&',
paramVariable: '=',
},
};
});
check this to understand better https://thinkster.io/egghead/isolate-scope-am/
There are 2 ways to do it: both involve using $routeParams service that allows you to retrieve current set of route parameters.
Given that you have an url: http://example.com/#/hospitals/foobar and a route /hospitals/:hospital/ configured in your $routeProvider, you can:
1.Inject $routeParams into your directive:
adminDash.directive('hospitals', function($routeParams) {
return {
restrict: 'E',
templateUrl: 'www/partials/admin/hospitals.html',
controller: 'AdminHospitalsController',
controllerAs: 'hospitalsCtrl',
link: function(scope, element){
scope.hospital = $routeParams.hospital;
}
};
});
2.Inject $routeParams into AdminHospitalsController
adminDash.controller('AdminHospitalsController', function($scope, $routeParams) {
$scope.hospital = $routeParams.hospital;
}
Both method will result in having hospital=foobar in your directive's scope;