2

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

2 Answers 2

3

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}" >

Fiddle

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}" ">

Updated fiddle.

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.