We can pass scope parameter to a directive
app.directive('appInfo', function() {
return {
restrict: 'E',
scope: {
info: '='
},
templateUrl: 'js/directives/appInfo.html'
};
});
and use it as follows in a view:
<app-info info="app"></app-info>
A component can be used as a directive too:
<component-info></component-info>
But can we pass to it a scope parameter same as info="app" ?
Yes, for a component you'll use bindings instead of scope. So your component definition will look somewhat like this:
app.component('componentInfo', {
bindings: {
info: '='
},
// ... and so on
});
Related
I have following directive structure.
<test-widget-body>
<test-task-list-filter>
</test-task-list-filter>
<test-task-list>
<test-datatable config="dtConfig" columns="dtColumns" api="dtApi"></test-datatable>
</test-task-list>
</test-widget-body>
Here are respective directives:
test-datatable
angular.module('testDatatable').directive('testDatatable', function () {
var directive = {
controller: 'testDatatableController',
restrict: 'E',
replace: true,
scope: {
config: '=',
columns: '=',
api: '=',
},
link: lnkFunction,
template: '<table class="table"></table>',
};
return directive;
}
testTaskList
angular.module('testTask').directive('testTaskList', function () {
return {
transclude: true,
restrict: 'E',
controller: 'testListController',
controllerAs: 'vm',
templateUrl: '/app/test/directives/test-list/test-list.html',
link: {
pre: preLink
}
};
function preLink(){
var dtColumns = [{
----
}];
var dtConfig =[];
var dtApi =[];
}
}
testTaskListFilter
angular.module('testTask').directive('testTaskListFilter', function () {
return {
restrict: 'E',
controller: 'testListFilterController',
templateUrl: '/app/test/directives/test-list/test-list-filter.html'
};
});
testWidgetBody
angular.module('testWidgetGrid').directive('testWidgetBody', function () {
return {
templateUrl: 'test.html',
link: function ($scope, element) {
}
}
Here I'm able to access dtConfig dtColumns dtApi objects inside testListFilterController controller.
How is this possible as <test-task-list-filter> and <test-task-list> are siblings.
Can anyone explain what is happening in this scenario.
Note: I'm able to access that object when I perform some click action not while directive rendering.
If you look at the declarations for testTaskListFilter directive and the testTaskList directive, neither of them have isolate scopes. You can declare isolate scopes by doing one of the following in the directive: scope: true or scope: {} (like in your testDatatable) directive.
Thus, any directive that does not declare its own scope inherits its parent's. So, testTaskListFilter and testTaskList are both using the same scope. This means that you're then able to
access dtConfig dtColumns dtApi objects inside testListFilterController controller
Here's the Angular wiki post for understanding scopes and scope inheritance
I have a (simplified) directive
angular.module('myApp')
.directive('myButton', function () {
return {
restrict: 'E',
scope: {
callbackFn: '&'
},
template: '<button ng-click=ca;;backFn($evenb)'
}
});
Now, in some parent controller I have defined a callback function:
this.myCallback = function ($event) {
this.doIt($event);
}
and the HTML:
<my-button callback-fn="page.myCallback()"></my-button>
(I'm using things like bindToController and controllerAs)
The issue is that the $event is never passed to myCallback, which most likely has to do with how I bind this function (&). But on the other hand, inside myCallback I would like to use this.
Is there some way to fix this ? without doing things like
var self = this;
this.myCallback = function ($event) {
self.doIt($event);
}
You haven't completely set up your bindings correctly. You can pass back arguments from the directive to the parent controller via a key-value map. According to the angular docs (emphasis mine):
& or &attr - provides a way to execute an expression in the context of the parent scope. If no attr name is specified then the attribute name is assumed to be the same as the local name. Given <widget my-attr="count = count + value"> and widget definition of scope: { localFn:'&myAttr'}, then isolate scope property localFn will point to a function wrapper for the count = count + value expression. 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}).
So that means in your consuming HTML you need to add parameters:
<my-button callback-fn="page.myCallback(parentEvent)"></my-button>
And then in the directive:
......
restrict: 'E',
scope: {
callbackFn: '&'
},
template: '<button ng-click="ctrl.callbackFn({parentEvent: $event})">Callback</button>'
,
According to me you should do it this way :
In your HTML page :
<my-button callback-fn="page.myCallback(event)"></my-button>
In your directive :
angular.module('myApp')
.directive('myButton', function () {
return {
restrict: 'E',
controller: 'Controller',
bindToController: true,
scope: {
callbackFn: '&'
},
template: '<button ng-click=foo($event)'
}
});
function Controller() {
this.foo = function (event) {
this.callbackFn({event: event});
}
}
But I'm not sur what's the point of your question.
Trying to call a function inside the directive:
angular.module('abc').directive('autocomp', function () {
return {
replace: true,
scope: true,
controller: 'Controller',
controllerAs: 'ctrl',
srchtxt: '#',
scope: {
src: '&'
},
templateUrl: '/dom/abc/auto.html',
link: function (scope, element, attrs) {
scope.$watch('srchtxt', function () {
scope.src(scope.srchtxt});
});
}
}
});
==========================================================================
Method inside the controller:
function search(srchtxt) {
console.log('srchText:', srchText);
}
===========================================================================
HTML:
<abc src="rc.search()"></abc>
I am writing a directive for the md-autocomplete control to which method name can be passed as attributes from the HTML pagee, and then try to execute the method inside the directive.
There's a watch on the textchange in the control in which I call the method to be executed (scope.src(scope.srchText}))
When I type in something into the autocomplete control I get the following error:
TypeError: Cannot use 'in' operator to search for 'rc' in g
Could any one please suggest on what am I missing or doing wrong ?
When you use & to bind controller method into directive, you have to declare exact parameter in your html like
<sml-auto-complete datasrc="cr.query(searchText)"></sml-auto-complete>
// ^
Then when you call this method from directive you need to pass the parameter as object like
scope.$watch('searchText', function () {
scope.datasrc({searchText: scope.searchText}); //not simply scope.datasrc(scope.searchText)
});
Check this demo
I have a directive defined as such:
angular.module("main.directives").directive("todo", function() {
return {
restrict: "A",
scope: {
todo: "=entity"
},
replace: false,
templateUrl: "todo.html",
link: function(scope, element, attributes) {
}
};
});
which I use like this from templates:
<div todo entity="todoData"></div>
todoData comes from a controller or some other the local scope. Anyway it all works like a charm, so that's cool!
My question is the following: How do I have to modify the directive definition so that it also works with a markup of this type:
<div todo="todoData"></div>
As you can see the data is now passed in as the value of the attribute marking the directive. Just like ng- directives do:
<p ng-repeat="bit in data"></p>
<p ng-click="whatever()"></p>
How can that be achieved?
Thanks
Replace
scope: {
todo: "=entity"
},
by
scope: {
todo: "=todo"
},
or simply
scope: {
todo: "="
},
When you write an attribute directive in angularjs you might want to have it fed by an attribute value.
For example, something like this:
<div my-attribute="somevalue"></div>
How then do you create a new scope that takes that in? It's not obvious. Any here's how you do it:
app.directive('myAttribute', function() {
return {
restrict: 'A',
scope: {
myAttribute: '='
},
template: '<div style="font-weight:bold">{{ myAttribute | number:2}}</div>'
};
});
The trick to notice is that the "self attribute" because of the name of the attribute in camel case.
Here is the Reference to This Answer!
you must eval the value of the attribute inself. The isolate scope is not one of my favorites kind of scopes for a directive. Instead you can use, scope = true, to inherit from the parent controller. This will allow you to use all the variable exposes on the parents scopes.
in your case.
angular.module("main.directives").directive("todo", function() {
return {
restrict: "A",
scope: true,
replace: false,
templateUrl: "todo.html",
link: function(scope, element, attributes) {
scope.todo = scope.$eval(attributes[todo]);
}
};
});
now your todo directive could be used. Like any other ng- directive.
example:
<div todo="getTodoList()"></div>
<div todo="[{description:'hahahha'}]"></div>
My HTML looks like this
<td currency-convert idrVal="{{(btcAsk.btcValue * btcAsk.btcAmnt).toFixed(2)}}"></td>
The AngularJS code
The controller has the method:
$scope.convertIDRtoUSD = function(idrValue) {
return CurrencyConversions.convertToUSD(idrValue, 'IDR');
};
And the directive looks like..
bitcoinApp.directive("currencyConvert", function() {
return {
restrict: 'A',
scope: {
idrval: '#'
},
template: '<span class="has-tip" tooltip="convertIDRtoUSD({{idrval}})" tooltip-animation="false">{{idrval}}</span>'
};
});
This is currently not calling the convertIDRtoUSD method.
Reading online, I think I'm supposed to use the Isolate Scope "&" but have not had success so far.
I'll try to word this as best I can, so bear with me! Your template contains a method. At run time, it expects this method to be present on the current scope. However, at that point, the scope is the isolated scope you created with the directive, and simply contains the value of idrval, so that method is undefined.
You need to either add the function convertIDRtoUSD() to the scope of the directive, or pass the function into your directive along with idrval. If you choose the former, you'r directive might look like this:
bitcoinApp.directive("currencyConvert", function() {
return {
restrict: 'A',
scope: {
idrval: '#'
},
template: '<span class="has-tip" tooltip="convertIDRtoUSD({{idrval}})" tooltip-animation="false">{{idrval}}</span>',
link: function(scope) {
scope.convertIDRtoUSD = function(idrValue) {
return CurrencyConversions.convertToUSD(idrValue, 'IDR');
};
}
};
});
If you want to pass the function in, and the function exists on the controller, your html would look something like this:
<td currency-convert my-func="convertIDRtoUSD(val)" idrVal="{{(btcAsk.btcValue * btcAsk.btcAmnt).toFixed(2)}}"></td>
And your directive:
bitcoinApp.directive("currencyConvert", function() {
return {
restrict: 'A',
scope: {
idrval: '#',
myFunc: '&'
},
template: '<span class="has-tip" tooltip="myFunc({val: idrval})" tooltip-animation="false">{{idrval}}</span>'
};
});
Some things to note - the attribute name of the function should be 'dash-named' not camel-case named, and parameters to the function passed into the directive have to be passed an an object with named values.
Hope this helps!