Reputation: 681
I'm trying to change the fill color of attributes in an in-line SVG using Angular and TypeScript. The idea is that the SVG have a "TA" attribute; any svg element with one of these "TA" attriubtes, I want to change the fill color to be bound to a user-defined color from the dropdown. However, I'm having a hard time figuring out how to change this attribute to be dynamicall bound.
Here is how I'm trying to do it:
export class TaDirective implements ng.IDirective {
static create_instance() : ng.IDirective {
return new TaDirective();
}
constructor(){
}
public bindToController = true;
public controllerAs = "ctrl";
public scope = { name: '=' };
public compile(element: ng.IAugmentedJQuery, attrs: ng.IAttributes, transclude: ng.ITranscludeFunction) {
var ta = attrs.$attr["ta"] as string
var ele = element[0];
attrs.$set
// Make all visable (works as expected)
attrs.$set('visibility', "visible")
// Attempt to bind to the controller's fill
attrs.$set('fill', "{{ ctrl.fill }}")
//attrs.$set('fill', 'cyan') // Verify idea works
}
public link(scope: ng.IScope, element: ng.IAugmentedJQuery, attrs: ng.IAttributes, controller: any, transclude: ng.ITranscludeFunction) {
//Tried code here
}
public controller(scope: ng.IScope, element: ng.IAugmentedJQuery, attrs: ng.IAttributes){
// Tried code here
}
}
app.directive('ta', TaDirective.create_instance);
Here is a Plunker with the TypeScript and complied JavaScript.
EDIT So I figured out how to do it but it's still not elegant, as the name of the scope is hard coded. I'm open to suggestions for how to decouple to two. (Plunker also updated)
export class TaDirective implements ng.IDirective {
static create_instance() : ng.IDirective {
return new TaDirective();
}
constructor(){
}
public link(scope: ng.IScope, element: ng.IAugmentedJQuery, attrs: ng.IAttributes, controller: any, transclude: ng.ITranscludeFunction) {
var ta = attrs.$attr["ta"] as string
var ele = element[0];
// Make all visable
attrs.$set('visibility', "visible")
// Attempt to bind to the controller's fill
scope.$watch('vm.fill', function(newFill) {
attrs.$set('fill', newFill)
})
}
}
Upvotes: 1
Views: 258
Reputation: 1156
A common practice for decoupling the controller with the directive watch expression is to instead watch a specified attribute.
Instead of the following:
JS:
scope.$watch('vm.fill', function (fill) {
attrs.$set('fill', fill);
});
HTML:
<text ta="1">Text</text>
You should have:
JS:
scope.$watch(attrs.ta, (fill: string): void => {
attrs.$set('fill', fill);
});
HTML:
<text ta="vm.fill">Text</text>
This practice ensures that your directive is more scalable since the vm.fill
watch expression isn't bound to the directive link function, but is instead passed into the directive through the angular template. Here is an updated plunkr.
Upvotes: 1