I have the following directive:
app.directive("actTemplate", function() {
return {
restrict: 'A',
templateUrl: "/views/myTemplate.html"
};
});
how can i pass additional parameter to myTemplate so:
<div>
{{aditionalParam}}
...
</div>
takes the value?
Define
app.directive("actTemplate", function() {
return {
restrict: 'A',
templateUrl: "/views/myTemplate.html"
scope: {
foo: '=boo'
}
};
});
Template
<div>
{{foo}}
</div>
Use
<actTemplate boo="lalala" />
You have to specify that your directive should create it's inner scope. Scope variable could then be shared in single or double binding way (see directive scope binding doc)
app.directive("actTemplate", function() {
return {
restrict: 'A',
scope: {
additionalParam: '='
},
template: "<div>{{additionalParam}}</div>"
};
});
Then "call" your directive with this dashed syntaxe:
<div act-template additional-param="foobar">
You can have one-way binding (controller -> directive) like in this jsfiddle example.
Or two way data binding (controller <-> directive) , like in this one.
Related
I have a directive treeview which contains a nested directive (being the branches) of each item rendered.
In the scope of both directives I have declared two parameters that should be talking to the parent controller.
filter: '&' //binds the method filter within the nested directive (branch) to the method doSomething() in the tree directive attribute which is bound to the html directive that binds to the controller.
iobj: '=' is the two way binding paramter that should be passing the scoped object to the controller. (but currently isn't)
Directive:
app.directive('tree', function () {
return {
restrict: 'E',
replace: true,
scope: {
t: '=src',
filter: '&',
iobj: '='
},
controller: 'treeController',
template: '<ul><branch ng-repeat="c in t.children" iobj="object" src="c" filter="doSomething()"></branch></ul>'
};
});
app.directive('branch', function($compile) {
return {
restrict: 'E',
replace: true,
scope: {
b: '=src',
filter: '&',
iobj: '='
},
template: '<li><input type="checkbox" ng-click="innerCall()" ng-hide="visible" /><a>{{ b.name }}</a></li>',
link: function (scope, element, attrs) {
var has_children = angular.isArray(scope.b.children);
scope.visible = has_children;
if (has_children) {
element.append('<tree src="b"></tree>');
$compile(element.contents())(scope);
}
element.on('click', function(event) {
event.stopPropagation();
if (has_children) {
element.toggleClass('collapsed');
}
});
scope.innerCall = function () {
scope.iobj = scope.b;
console.log(scope.iobj);
scope.filter();
}
}
};
});
HTML:
<div ng-controller="treeController">
<tree src="myList" iobj="object" filter="doSomething()"></tree>
<a ng-click="clicked()"> link</a>
</div>
Controller:
app.controller("treeController", ['$scope', function($scope) {
var vm = this;
$scope.object = {};
$scope.doSomething = function () {
var item = $scope.object;
//alert('call from directive');
console.log(item);
}
$scope.clicked = function () {
alert('clicked');
}
...
Currently I can invoke the function $scope.doSomething from the directive to the controller. So I know that I have access to the controllers scope from the directive. What I cannot figure out is how to pass an object as a parameter from the directive back to the controller. When I run this code, $scope.object
is always an empty object.
I'd appreciate any help or suggestions on how to go about this.
The & directive binding supports parameter passing. Given your example
scope.filter({message: 'Hello', anotherMessage: 'Good'})
The message and anotherMessage become local variables in the expression bound to directive:
<tree src="myList" iobj="object" filter="doSomething(anotherMessage, message)"></tree>
Here's a sample plunker where the callback parameters are set inside a template.
The documentation clearly states that:
Often it's desirable to pass data from the isolated scope via an
expression to the parent scope, this can be done by passing a map of
local variable names and values into the expression wrapper fn. For
example, if the expression is increment(amount) then we can specify
the amount value by calling the localFn as localFn({amount: 22}).
I have a custom element directive with the following template:
<div>
<input value="{{dataFromRootScope}}" />
</div>
And definition:
dirModule.directive('myDirective', function() {
return {
restrict: 'E',
templateUrl: '/Scripts/app/directives/myDirective.html'
};
}
);
I would like to use the directive as shown below:
<my-directive my-value="{{dataFromScope}}"></my-directive>
i.e. I want to use the evaluated dataFromScope value inside my custom directive as dataFromRootScope. How can I reach this?
You can use isolated scope two-way binding:
dirModule.directive('myDirective', function() {
return {
scope: {
model: '=myValue'
},
restrict: 'E',
templateUrl: '/Scripts/app/directives/myDirective.html'
};
});
Where directive template is
<div>
<input ng-model="model" />
</div>
and usage is
<my-directive my-value="dataFromScope"></my-directive>
Demo: http://plnkr.co/edit/Npiq2hCO4tQHmakG4IAe?p=preview
I want to use the evaluated dataFromScope value inside my custom
directive as dataFromRootScope. How can I reach this?
Well you have two options to achieve this.
Option-1: Create an isolated scope for your directive
This way, you would need to assign value of dataFromRootScope from myValue. The = operator ensures two-way binding.
app.directive('myDirective', function() {
return {
restrict: 'E',
scope:{
dataFromRootScope: '=myValue'
},
templateUrl: 'myDirective.html'
};
}
);
'dataFromScope' will not be available in myDirective because it has isolated scope. You can access it via dataFromRootScope(see how its getting its value from myValue)
<div>
<input value="{{dataFromRootScope}}" />
</div>
Demo-1
Option-2: Enjoy shared scope.
In this case, you dont need to create an isolated scope. You can simply use dataFromScope in your directive template OR, if you really want to access it as dataFromRootScope in your template, simply assign it in your link function.
app.directive('myDirective', function() {
return {
restrict: 'E',
templateUrl: 'myDirective.html',
link:function(scope,ele,attr){
scope.dataFromRootScope = scope.dataFromScope
}
};
}
);
<div>
<input value="{{dataFromRootScope}}" />
</div>
Demo-2
You can use the '#' sign :
dirModule.directive('myDirective', function() {
return {
scope: { myValue: '#' },
restrict: 'E',
templateUrl: '/Scripts/app/directives/myDirective.html'
};
});
The '#' sign binds the evaluated value of the DOM attribute to the directive.
You can then use the directive as you asked :
<my-directive my-value="{{dataFromScope}}"></my-directive>
Is it possible to call the method defined inside the directive controller from outside.
<div ng-controller="MyCtrl">
<map></map>
<button ng-click="updateMap()">call updateMap()</button>
</div>
app.directive('map', function() {
return {
restrict: 'E',
replace: true,
template: '<div></div>',
controller: function(){
$scope.updateMap = function(){
//ajax call here.
}
},
link: function($scope, element, attrs) {
$scope.updateMap();
//do some dom transformation
}
}
});
I want to call the method updateMap() function from my view.
If you expose the function on the controller, instead of the scope, you can expose the controller on the parent scope, such as:
controller: function($scope, $element, $attrs){
// Verify this. The controller has to be added to the parent scope, if the directive itself is creating a scope
$scope.$parent[$attrs["name"]]=this;
this.updateMap = function(){
//ajax call here.
}
},
Now in the main controller you will be able to access the controller:
<button ng-click="myMap.updateMap()">call updateMap()</button>
This is similar to how ng-model exposes its controller. Think of the controller as an API to your directive.
It would be a bad practice to access a function from the controller as you want. But still you can bind the updateMap function to $rootScope thus it can be used globally and still pass the current scope as a parameter to it.
Eg,
$rootScope.updateMap = function($scope) {
// use the scope to do the manipulation
}
<div ng-controller="MyCtrl">
<map></map>
<button ng-click="updateMap(this)">call updateMap()</button>
</div>
Here passing 'this' in updateMap function will refer to the scope in which the element is wrapped. In the above example, 'this' will refer to the MyCtrl's $scope
I would suggest two options. One simple option is to use events:
<div ng-controller="MyCtrl">
<map></map>
<button ng-click="updateMap()">call updateMap()</button>
</div>
app.directive('map', function() {
return {
restrict: 'E',
replace: true,
template: '<div></div>',
controller: function(){
$scope.updateMap = function(){
//ajax call here.
}
},
link: function($scope, element, attrs) {
$scope.$on('my.update.map.event', $scope.updateMap);
}
}
});
app.controller('MyCtrl', function ($scope) {
$scope.updateMap = function () {
$scope.$broadcast('my.update.map.event');
};
});
This isn't a bad solution. You're not polluting the root scope (#Krishna's answer) and your map directive isn't adding an arbitrary value to your controller's scope (#Chandermani's answer).
Another option, if you want to avoid events, is to to use the controllerAs syntax to expose your map directive's controller.
<div ng-controller="MyCtrl">
<map controller="mapController"></map>
<button ng-click="mapController.updateMap()">call updateMap()</button>
</div>
app.directive('map', function() {
return {
restrict: 'E',
replace: true,
scope: {
'controller': '=?'
},
template: '<div></div>',
//controllerAs creates a property named 'controller' on this
//directive's scope, which is then exposed by the
//'scope' object above
controllerAs: 'controller',
controller: function(){
this.updateMap = function(){
//ajax call here.
}
},
link: function($scope, element, attrs, ctrl) {
ctrl.updateMap();
}
}
});
This is similar to #Chandermani's answer, but the coupling between your controller and your directive is much more explicit. I can tell from the view that the map directive is exposing its controller and that it will be called mapController in MyCtrl's scope.
(I found this idea here).
I'm creating a reusable component/widget as a directive using a template and isolated scope. I'd like to be able to also send a callback into the directive and call it in the widget. Is this possible?
Something like...
mainView template:
<my-widget callback="someFunction"></my-widget>
directive:
return {
restrict: 'E',
scope: {
callback: '='
},
templateUrl: '/partials/widget.html',
}
And the template:
<input type="text" ng-change="callback()" />
So when the widget value is changed, it triggers the callback function that was passed in the main view
What you're looking for is &. Quoting the old angular docs: "& or &attr - provides a way to execute an expression in the context of the parent scope".
Try this as your directive code:
return {
restrict: 'E',
scope: {
callback: '&'
},
templateUrl: '/partials/widget.html',
}
You can also $watch for it in the link or controller.
.directive('myDirective', function() {
return {
restrict: 'E',
link: function(scope, element, attrs) { {
scope.$watch(attrs.myDirective, function(value){ ... });
}
...
Turns out I needed to do as suggested and use an & rather than an =, but also this still wouldn't work until I added ng-model as well to my input:
<input type="text" ng-model="myValue" ng-change="callback()" />
I have the following directive:
CorrelatorApp.directive('correlator', function ($WebApi) {
return {
restrict: 'A',
scope: {
crOptions: '=',
},
link: function (scope, element, attrs) {
var options = scope.crOptions;
}
}
});
then in my index.html I use it like this:
<form correlator cr-options="correlatorOptions" name="CorrelatorForm" ng-controller="PortalMerchantController">
and my correlatorOptions are defined in the controller:
CorrelatorApp.controller("PortalMerchantController", function
PortalMerchantController($scope, $http) {
$scope.correlatorOptions = {
dependant: {
controller: 'PortalMerchant',
model: 'portalMerchants',
nameField: 'PortalsMerchantName'
},
principal: {
controller: 'Merchant',
model: 'merchants',
nameField: 'Name'
}
};
});
when the directive links, the value of scope.crOptions is undefined. If I set crOptions to & and then call it (var options = scope.crOptions()), the code executes correctly and I get the object defined in the controller. What am I missing?
Move your ngController directive outside of the form element.
In 1.2.0 and greater, the ngController and form have sibling scopes (previously they would have shared the isolate scope). Here's the change that causes this
You want form to be a child of ngController so it can access it's scope:
<div ng-controller="PortalMerchantController">
<form correlator cr-options="correlatorOptions" name="CorrelatorForm"></form>
working fiddle