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>
Related
I'm using an angular directive to generate a reusable template and show some data in it. The directive also has an ng-click that should take an object and pass it to the parent controller. I'm kind of stuck, not really sure how to pass that data from the directive controller to the scope of the parent controller. I read here but the circumstances are a bit different.
The js code of the directive:
angular.module("app")
.directive('userData', function() {
return {
restrict: "E",
templateUrl: "directives/userData/userData.html",
scope: {
userObj: "="
},
controller: function($scope){
},
link: function(scope, elements, attrs, controller){
}
}
});
And this is the directive html:
<div class="style" ng-click="displayFullDetails(userObj)">{{userObj.first_name}}</div>
Parent controller:
angular.module("app").controller("parentCtrl", ['$scope', function ($scope) {
angular.element(document).ready(function () {
getDataService.getJsonData().then(function (data) {
$scope.users = data.data;
})
});
}]);
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.
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;
}
};
}
I have a directive with 2-way binding on the dataSourceModel scope variable, but for some reason, it is showing as undefined in the directive. Am I doing something wrong here?
Plunker: http://plnkr.co/edit/LxWMbY9qtDSBUPWNqWV7?p=preview
Code:
Html:
<div ng-controller='TestCtrl'>
<test-directive
selected-id='selectedId'
data-source-model='workOrderItems'> <!-- This does not work -->
</test-directive>
{{workOrderItems}} <!-- this works -->
</div>
Script:
var app = angular.module("testApp", []);
app.controller('TestCtrl', ['$scope', function ($scope) {
$scope.workOrderItems = 'abcd';
$scope.selectedId = '123';
}]);
app.directive('testDirective',function () {
return {
restrict: 'E',
scope: {
selectedId: '=',
dataSourceModel: '='
},
replace: true,
template: "<div></div>",
link: function (scope, element, attrs) {
console.log(scope.selectedId, scope.dataSourceModel);
}
}
});
data- is prefix for custom HTML5 attributes, so the data-source-model='workOrderItems' is translated to just sourceModel in your directive.
Try renaming your directive attribute to something that doesn't start with data (or reference it in HTML as data-data-source-model) and it should work.
I'm trying to pass a template through a directive to a dynamic controller (known at runtime from the directive perspective).
Something like this:
<my-dir ctrl="PersonCtrl">
<h1>{{person.name}} - {{person.age}}</h1>
</my-dir>
var data = {
name: "Alex",
age: "24"
};
function PersonCtrl($scope){
$scope.person = data;
}
myApp.directive('myDir', function($controller){
return {
restrict: "EA",
scope: {
ctrl: "#"
},
transclude: true,
controller: function($scope, $element, $attrs) {
},
template: "<div>{{ctrl}}</div><div ng-transclude></div>",
link: function($scope, $element, $attrs) {
$controller($attrs.foo, {$scope: {}});
}
};
});
see jsFiddle
The controller is found and instantiated, but somehow the binding of the transcluded template to it doesn't work. Do I miss some order requirement or is there a way to bind this controllers scope to the transcluded template?
Found it - should have binded the controller to the $$nextSibling scope!
$controller($attrs.ctrl, {$scope: $scope.$$nextSibling});
updated jsFiddle