Access isolated scope in angular directive template - angularjs

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.

Related

Cant use directive controller values in directive template

Im having a hard time accessing the attributes passed in to my directive from the template of that directive. I want to be able to access 'companyId' from album.tmpl.html but no matter what i try i can't get it. The strangest part is i can see it has made its way in to the controller, but somehow it's not getting from the controller to the template. I know the template is correctly calling the controller as it can succesfully print out the value of 'testVar' which is initialised inside the controller. Any advice would be appreciated.
directive + directive controller
(function () {
'use strict';
angular.module('erCommon')
.directive('erAlbum', albumDirective)
.controller('AlbumController', AlbumController);
function AlbumController() {
var vm = this;
vm.testVar = "test var initiated";
}
function albumDirective($log) {
function albumLink(scope, element, attrs, AlbumController) {
//watch vars in here
}
return {
restrict: 'E',
scope: {
companyId: '=companyId'
},
bindToController: true,
templateUrl: 'components/temp/album.tmpl.html',
controller: 'AlbumController',
controllerAs: 'albumCtrl',
link: albumLink
};
}
})();
template ( album.tmpl.html
<div ng-controller="AlbumController as albumCtrl">
testVar: {{albumCtrl.testVar}}<BR>
companyId:{{albumCtrl.companyId}}<BR>
</div>
usage
<er-album company-id="2"></er-album>
output
test var: test var initiated
companyId:
You need to remove ng-controller from your template:
<div>
testVar: {{albumCtrl.testVar}}<BR>
companyId:{{albumCtrl.companyId}}<BR>
</div>
To achieve the result you wanted i had to modify the structure of your code slightly. Hope this helps you to understand the issue. Look for materials about isolated scopes which Angular uses with directives.
HTML:
<div ng-app="erCommon" ng-controller="AlbumController as albumCtrl">
<er-album company-id="2" test = "albumCtrl.testVar"></er-album>
</div>
Controller:
angular.module('erCommon', [])
.directive('erAlbum', albumDirective)
.controller('AlbumController', AlbumController);
function AlbumController() {
var vm = this;
vm.testVar = "test var initiated";
}
function albumDirective() {
return {
restrict: 'E',
scope: {
test: '=test',
companyId: '#companyId'
},
template: '<div> testVar: {{test}}<BR> companyId:{{companyId}}<BR> </div>', // it will work fine with templateUrl as well, just didn't want to cr8 another file...
link: function(scope, element, attrs){
//do whatever else you might need;
}
};
}

Get transcluded text in directives controller

I can get some text from my directive into my directives controller like this:
The html:
<my-directive text="Some text"></my-directive>
In the directive, I can get hold of the text like this:
bindToController: {
text: "#"
};
And I could use it like this in the directive's controller:
controller: function() {
this.textUpperCase = this.text.toUpperCase();
}
But how could can I get hold of the text in the directives controller via transclusion? So that I can have the html like this:
<my-directive>Some text</my-directive>
As mentioned in the comments you could use element.html() or transclusion.
But I would prefer transclusion because that's easier to work with the data. You can use $transclude in your controller or transcludeFn in compile or link method.
Here I think the best would be the controller.
Please have a look at this fiddle or the demo below.
I think injecting the $element into controller won't work becasue you would get the uncompiled template with-out the data you're looking for.
angular.module('demoApp', [])
.controller('mainCtrl', function($scope) {
$scope.hello = 'hello world from scope';
})
.directive('upperCase', function() {
return {
restrict: 'E',
transclude: true,
scope: {
},
template: '<div>{{text}}</div>',
controller: function($scope, $transclude, $element) {
$transclude(function(clone, scope) {
//console.log(clone.text(), scope.hello);
console.log(clone);
$scope.text = clone.text().toUpperCase();
//transcludedContent = clone;
//transclusionScope = scope;
});
//console.log($element.html()); // not working will get the uncompiled template from directive
console.log($scope.text); // can be used here too
},
link: function(scope, element, attrs, ctrl, transclude) {
var text = element.html();
//console.log(transclude);
//element.html(text.toUpperCase()); // also working (add ng-transclude to your template)
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demoApp" ng-controller="mainCtrl">
<upper-case>hello world</upper-case>
<upper-case>hello angular</upper-case>
</div>

Databinding to a controller inside a directive in angular

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';

Isolated scope: value not updating

I am trying to expand on the bootstrap ui library with my own custom control. This control will be used in an AngularJS app. Currently, I'm getting stuck on the scoping.
My plunker is here
This plunker is a simplified version of a more complex control. The concept that I'm trying to highlight is the scoping. You will notice that the custom control, my-query, is pre-populated with the value of myController.$scope.query. You will also see that the query is put in the page underneath the custom control. As I type, the value does NOT get updated. Why? My code looks like the following:
myApp.directive('myQuery', [function() {
return {
restrict:'E',
transclude: true,
scope: {
query: '='
},
template: '<div ng-controller="myQueryController"><input type="text" ng-model="query" /><button ng-click="go_Click()">go</button></div>'
};
}]);
myApp.controller('myQueryController', ['$scope', function($scope) {
$scope.go_Click = function() {
$scope.$emit("goClicked");
};
}]);
What am I doing wrong?
In your directive template, you are adding an additional controller which is adding in another scope. That is what is causing the problem. Instead of doing it that way, move the controller logic into either a controller function or a link function defined on your directive, either will work.
Try this. Here's an example using a controller function. Note that I moved your original myQueryController inside the directive and removed the ng-controller directive from the myQuery directive's template.
'use strict';
var myApp = angular.module('myApp', []);
myApp.controller('myController', ['$scope', function($scope) {
$scope.queryValue = 'test';
$scope.$on('goClicked', function() {
$scope.performAction();
});
$scope.performAction = function() {
alert('Using ' + $scope.queryValue);
};
}]);
myApp.directive('myQuery', [function() {
return {
restrict:'E',
transclude: true,
scope: {
query: '='
},
template: '<div><input type="text" ng-model="query" /><button ng-click="go_Click()">go</button></div>',
controller : function ($scope) {
$scope.go_Click = function() {
$scope.$emit("goClicked");
};
}
};
}]);
<div ng-controller="myQueryController">
A controller creates a new scope. So <input type="text" ng-model="query" /> doesn't use query from the directive's scope but from the controller's scope. Instead of using a controller you can define the go_Clickfunction in the directive's link method.
Do you need this?:
http://plnkr.co/edit/6IrlnXvsi2Rneee0hGC8?p=preview
scope: {
model: '='
}
The problem was that you used a primitive type which was passed by value into your directive. Always use complex types which are passed by reference.

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