I require a custom DOM element that accepts mouse clicks and whose state is dependant on the model:-
<card ng-repeat="card in cards" x="card.x"
y="card.y" color="card.color" on-click="test_click('b')">
</card>
I am able to build a custom directive that binds to a controller's scope variables through its DOM attributes and use them to alter its view. I have this working by allowing the directive to inherit its parents scope:
app.directive('card', function ($timeout) {
return {
restrict:'E',
link:function (scope, element, attrs) {
element.addClass('card');
element.click(function(){
scope.onClick()
});
scope.$watch(attrs.x, function (x) {
element.css('left', x + 'px');
});
scope.$watch(attrs.y, function (y) {
element.css('top', y + 'px');
});
scope.$watch(attrs.color, function (color) {
element.css('backgroundColor', color);
});
}
/*
,scope:{
x:'=',
y:'=',
color:'=',
onClick: "&"
}
*/
};
});
I am able to get a mouse click event to propagate up to the controller by creating an isolated scope and doing some rewiring (by commenting the scope in above).
However, I am unable to get both behaviours working at the same time.
I presume I need to get the x variable bound to the attribute value, which is what I have tried to do. But even by trying every combination of syntax I can think of, I just can't seem to get it working.
Here is the complete case jsfiddle
If I understand what you're trying to do, you can use ng-style instead of $watch()es, and ng-click instead of element.click():
<card ng-repeat="card in cards" ng-click="test_click('b')"
ng-style="{left: card.x, top: card.y, 'background-color': card.color}" >
When we use any of the pre-built Angular directives -- e.g., ngStyle, ngRepeat, ngClass, ngSwitch, ngShow -- and tie them to models, Angular does the watch()ing for us.
(I don't understand why it only works if I include jQuery. I don't see any jQuery-specific methods being called.)
Update: I figured out how to make it work without jQuery -- add 'px' to the ng-style:
<card ng-repeat="card in cards" ng-click="test_click('b')
ng-style="{left: card.x + 'px', top: card.y + 'px', 'background-color': card.color}" ">
I guess jQuery is more forgiving somehow if we leave off the 'px'.
To the second fiddle, I also added a "move card #1 down 200px" ng-click/hyperlink, to prove that changing the model results in Angular automatically updating the view for us.
Ahhhhh, I had the correct approach, the watchers had broken though. Clearly I don't fully understand the semantics of $watch, as I am not totally understanding the solution. I only realised it by printing out the scope and detecting the right variables were present in the isolated scope case.
anyway, the solution: I changed the $watch calls to:-
scope.$watch("x", function (x) {
element.css('left', scope.x + 'px');
});
and this tracked changes to the bound variables