Reputation: 919
I have a directive which needs to display data from an object in a controller. The piece of data that must be displayed is determined by an attribute of the directive and some other calculations based on other dom elements.
Here is a simplified example.
I have this data:
app.controller('EditorCtrl', function($scope) {
$scope.blocks = {
header: 'text1',
body: 'text2',
};
});
And I want it to be displayed with this directive:
app.directive('editable', function() {
return {
template: 'data: {{val}}',
link: function(scope, element, attrs) {
element.wrap('<div class="editable"></div>');
data = scope.blocks[attrs.editable];
val = data;
}
}
});
And in HTML:
<h1 editable="header">text1 should be displayed here</h1>
<h1 editable="body">text2 should be displayed here</h1>
How can I accomplish this ? Am I approaching the problem in a right way ?
Upvotes: 1
Views: 2842
Reputation: 3850
The 'data: {{val}}' instruction in the directive is expecting "val" to be defined in the scope (and it isnt).
You can create a local scope with "scope:true" to hold the val variable. (see http://docs.angularjs.org/guide/directive scope section).
Something like this would work:
app.directive('editable', function() {
return {
template: 'data: {{val}}',
scope: true,
link: function(scope, element, attrs) {
element.wrap('<div class="editable"></div>');
data = scope.blocks[attrs.editable];
scope.val = data;
}
}
});
In AngularJS, a child scope prototypically inherits from its parent scope, so even though you are creating a new scope, you can still access the blocks object.
Having said that, the previous solution would make it hard for changes in the parent blocks object to be instantly reflected in the DOM h1 nodes. I would instead, do something like this:
<div ng-app="app" ng-controller="EditorCtrl">
<h1 editable="blocks.header">text1 should be displayed here</h1>
<h1 editable="blocks.body">text2 should be displayed here</h1>
</div>
And JS:
angular.module('app', []).controller('EditorCtrl', function($scope) {
$scope.blocks = {
header: 'text1',
body: 'text2',
};
}).directive('editable', function() {
return {
template: 'data: {{text}}',
scope: {
'text': '=editable'
},
link: function(scope, element, attrs) {
element.wrap('<div class="editable"></div>');
}
}
});
With the 'text': '=editable' scope declaration you are setting up a bi-directional binding between the local scope text variable and parent "blocks.header/body" (the content of the editable DOM attribute). Any change in blocks variable will be automatically reflected in the DOM.
Upvotes: 3