Databinding to a controller inside a directive in angular - angularjs

I'm new to angular and have the following directive:
angular.module('myApp')
.directive('myDirective', function () {
return {
templateUrl: '/views/partial-views/partial.html',
restrict: 'E',
controller : function(){
age : '5'
},
controllerAs : 'myCtrl'
};
});
I want to include the age on my page inside partial.html which looks like this:
<div ng-app="myApp" ng-controller="myCtrl as s">
{{s.age}}
</div>
However I am getting the following error:
Error: [ng:areq] Argument 'myCtrl' is not a function, got Object
Can anybody tell me what I'm doing wrong?

What Chandermani mentioned is absolutely correct. To be more precised, it can be written as,
Directive Definition
angular.module('myApp')
.directive('myDirective', function () {
return {
templateUrl: '/views/partial-views/partial.html',
restrict: 'E',
controller: ['$scope', function($scope){
$scope.age = '5'
}]
};
})
Usage
<div ng-app="myApp">
<my-directive>
{{age}}
</my-directive>
</div>
However, there's no meaning of defining a directive here. You can just use a controller definition to fulfill the same action.

There were two issues with you code. Firstly you don't to alias the controller again, by using ng-controller in your template so that needs to be removed.
Secondly the controller is a function not object, so use:
this.age = '5';

Related

Why ng-click not working on custom directive template?

I want to create a drop down filter in my project. So, I created the drop down list using directive, in which the list contains ng-click event in the template. I don't know where I was wrong. Kindly, provide solution. Thanks in Advance.
My HTML file
<div ng-controller="drop">
<a ng-click="toggleList">Select</a>
<div ng-if="toggleDrop">
<drop-down></drop-down>
</div>
</div>
My Controller Code
angular.module('myApp', [])
.controller('drop', ['$scope', function($scope){
$scope.toggleDrop = false;
$scope.filterList = ['One','Two','Three'];
$scope.toggleList = function() {
$scope.toggleDrop = !$scope.toggleDrop;
}
$scope.filterContent = function() {
alert('dfdf')
}
}]);
My Directive Code
angular.module('myApp', [])
.directive('dropDown', function() {
return {
restrict: 'E',
templateUrl: 'drop.html'
controller: drop
}
});
My Directive Template File
<ul>
<li ng-repeat="items in filterList" ng-click="filterContent()">{{items}}</li>
</ul>
Everything works fine except the ng-click behaviour. Thanks in Advance.
There are few issues with your code,
(i) Your directive should not have a new module with empty dependencies, change it as,
angular.module('myApp')
.directive('dropDown', function()
(ii) You are missing a comma after the controller inside directive,
angular.module('myApp')
.directive('dropDown', function() {
return {
restrict: 'E',
templateUrl: 'drop.html',
controller: 'drop'
}
});
(iii)Should be toggleList() which is a function,
<a ng-click="toggleList()">Select</a>
DEMO
You're missing parenthesis to call function on ng-click
ng-click="toggleList()"
Also in directive code don't declare angular module once again. If you that it will wipe out old registered component from that module. Use angular.module('moduleName')(that will return create module) while registering new component to module
angular.module('myApp', [])
should be
//module getter
angular.module('myApp')
Additionally directive has wrong DDO, correct it to below
return {
restrict: 'E',
templateUrl: 'drop.html', //added `,` here
//I don't think so you need controller here as you shared the parent controller
//wrap with `'` but it will create `drop` controller instance inside directive again
//controller: 'drop'
}
You have given the function name 'toggleList' but you have not called the function. It should work when you call the function as follows:
<a ng-click="toggleList()">Select</a>
You are missing parenthesis in the function.
Thanks

Access isolated scope in angular directive template

I am currently writing an angular directive that uses a template in a different HTML file and an isolated template. The directive gets some string via # to its scope and that value is available in teh controller function.
Somehow its not available via {{}} in the HTML template. Why is that so? How can I change that? I read something about the template using the parent scope but I don't fully understand that.
Here is a code example:
angular.module('moduleName')
.directive('aGreatDirective', function () {
return {
restrict: 'E',
scope: {
mapid: '#'
},
templateUrl: "path/to/template.html",
controller: ['$scope', function (scope) {
console.log($scope.mapid); // is defined
}
}
});
And the html code for the template:
<div id="{{mapid}}"></div>
The result in the browser is exactly the same where it should be:
<div id="theValueOfmapid"></div>
Thanks for your help!
PS Here is a jsfiddle: fiddle
Your fiddle was incorrect since you didn't have your controller defined or $scope injected properly. The following will work just fine:
template:
<div ng-controller="MyCtrl">
<a-great-directive mapid="thisisthemapid"></a-great-directive>
Some other code
</div>
js:
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function () {
});
myApp.directive('aGreatDirective', function() {
return {
restrict: 'E',
scope: {
mapid: '#'
},
template: "<div id='{{mapid}}'> {{mapid}} </div>",
controller: ['$scope', function($scope) {
console.log($scope.mapid); // is defined
}
]}
});
Fiddle
Note that in my example, the injected variable in your directive's controller should be $scope, not scope, for consistency reasons.

Pass function from controller scope to directive isolate scope

I am using AngularJS and am trying to pass a function on my controller's scope to a directive's isolate scope.
I know I have done this before, but am having issues this time.
The function takes two inputs, and logs them to the console.
However, when I pass it to my directive as
<div my-dir my-function="functionName"></div>
or
<div my-dir my-function="functionName()"></div>
And attempt to call it from my directives controller, I actually get a function that takes no arguments and returns my function.
that is, instead of calling
ctrl.functionName(a,b)
I have to call
ctrl.functionName()(a,b)
Any help would be greatly appreciated.
I have seen some reference to syntax like this:
<div my-dir my-function="functionName({})"></div>
html:
<div my-dir my-function="functionName()"></div>
directive:
angular.directive('myDir', function() {
return {
scope: {
callback: '&myFunction'
},
controller: function($scope) {
$scope.callback({param1: val1, param2: val2});
};
});
Try the following code with scope isolation:
angular.module("Demo", [])
.controller("ChildCtrl", function($rootScope, $scope) {
$scope.testFunc = function (a, b) {
return a + b;
}
})
.directive("isoElement", function() {
return {
restrict: "E",
scope: {
testFunc: '&'
},
link: function(scope) {
console.log(scope.testFunc()(1, 2));
}
};
});
Directive usage will be:
<div ng-app="Demo" ng-controller="ChildCtrl">
<iso-element test-func="testFunc"></iso-element>
</div>
You will need to do scope.testFunc()(..) because scope.testFunc() will return the function itself. IMO this is more understandable than approaching the problem from another side.

AngularJS can't pass in different function when directive coupled with controller

I have a directive which I want to tightly couple with a controller as a component. I assumed I was following best practice by explicitly passing ion my functions even though I was declaring the controller to use. Here is an example:
app.js
var app = angular.module('plunker', [])
app
.controller('myCtrl', function($scope) {
$scope.output = '';
$scope.foo = function () {
$scope.output = 'foo';
}
$scope.bar = function () {
$scope.output = 'bar';
}
})
.directive('myDirective', function() {
return {
scope: {
output: '=',
foo: '&',
},
templateUrl: 'template.html',
replace: true,
controller: 'myCtrl',
};
})
template.html
<div>
<button ng-click="foo()">Click Foo</button>
<p>You clicked: <span style="color:red">{{output}}</span></p>
</div>
index.html
<body>
<my-directive
output="output"
foo="bar()"> <!-- pass in the *bar* function instead of the *foo* function -->
</my-directive>
</body>
Plunkr: http://plnkr.co/edit/Y4lhxuXbK9YbjAklR7v1?p=preview
Here, even though I'm passing in the bar() function, the output is 'foo' when the button is clicked. If I uncouple the controller by commenting out controller: 'myCtrl' in the directive, the output becomes 'bar'.
I thought I could declare the controller but still be free to pass in which functions I desire to the directive. It also seems that explicitly passing these functions in is a little redundant if the directive just looks up to the controller to find it (I can pass nothing into the directive and it still works).
This is especially problematic when testing as I would like to pass in my own stub functions to the directive, which at the moment I cannot do.
Is there some way to achieve what I want or am I doing something fundamentally wrong?
EDIT I meant to not have the controller declared in the HTML.
Remove the controller property on the directive:
.directive('myDirective', function() {
return {
scope: {
output: '=',
foo: '&',
},
templateUrl: 'template.html',
replace: true,
// controller: 'myCtrl',
};
})
You're wiring up the same controller to the directive as the parent, which is overwriting all the properties you're trying to pass in via isolate scope. The controller is wired up twice, once on the parent scope and then again on the directive. Removing this will allow you to pass in the function bar() and it will not be overwritten.
Here's the Plunker Demonstration
When running inside a directive, the $scope is initialized with output and foo variables before the controller constructor is called. Your controller is essentially overwriting these properties.
A simple check in your controller
if(!$scope.foo)
{
$scope.foo = function () {
$scope.output = 'foo';
}
}
Would work.
PS. I'm assuming your example is a simplification of your problem. If it's not, then the other answer's advice to simply remove the controller from the directive is the best approach.

Angularjs: Can transcluded elements "live" in the parent controller's scope?

I would like directives in the transcluded content to "live" in the directive's parent controller
ex: in the view below, I would like the binding "varInMyController" to
be bound to the variable of the same name in MyController.
I could explicitely pass variables in the directive scope:{aVar: '='},
but I want to avoid this, because the directive needs to be generic.
is this possible ?
<div ng-controller="MyController">
<div my-directive>
{{varInMyControllerScope}}
</div>
</div>
angular.module('myModule')
.directive('myDirective', [function() {
return {
transclude: true,
replace: true,
templateUrl: '<div><div ng-transclude></div></div>',
scope: {
options: '='
},
link: function(scope, element, attrs) {}
}
}])
angular.module('MyModule')
.controller('myController', ['$scope'function($scope) {
$scope.varInMyControllerScope = "hello"
}])
See Associated Plunker.
The most crucial problem of your above is this line in the directive
templateUrl: '<div><div ng-transclude></div></div>'
use template instead since it isn't a URL.
If this isn't a partial code, then another problem might be the initialization of your module. It should look like this from the start:
angular.module('myModule', [])
Another problem is the spelling typo of your second invocation for the angular.module() method:
angular.module('MyModule');
It should be
angular.module('myModule');
Lastly is the comma between the array of passed in the controller function is not separated by ,
['$scope'function($scope) {
$scope.varInMyControllerScope = "hello"
}]
It should be
['$scope', function($scope) {
$scope.varInMyControllerScope = "hello"
}]

Resources