Vikram
Vikram

Reputation: 6877

Updating scope variable from directive

The scope variables updated by the directive are not reflected where we have {{variable}} on the page, however they do show up as being updated in when I do console.log(scope).

<script>
    var demoApp = angular.module('demoApp', []);

    demoApp.controller('demoController', function demoController($scope) {
      $scope.myElementId ="abcd";
      $scope.updateVals = function() {
        $scope.myElementClass = "";
      };
    });

    demoApp.directive('demoSelect', function() {
      return {
        restrict: 'A',
        controller: 'demoController',
        link: function(scope, element, attrs, controller) {
          element.on("click", function(event) {
            event.stopImmediatePropagation();
            event.preventDefault();
            scope.ele = angular.element(event.target);
            angular.element(".selected").removeClass("selected");
            $(scope.ele).addClass("selected");
            var mm = $(scope.ele).get(0);
            scope.myElementId = $(scope.ele).attr("id");
            scope.myElementClass = $(scope.ele).attr("class");
            scope.myElementType = mm.tagName;
          });
        }
      };
    });
  </script>

Here is the plunker for it. What am I missing?

Upvotes: 4

Views: 5921

Answers (3)

gkalpak
gkalpak

Reputation: 48212

There were a couple of errors in your demo:

  1. jQuery was loaded after Angular. You should always load jQuery before Angular, so the latter is aware of and can take advantage of the former.

  2. The automatic dash-delimited to camelCase convertion is applied only to directives, not the names of your apps or controllers. Thus, you should write demoApp and demoController, instead of demo-app and demo-controller in your HTML.

  3. You were calling some Angular-specific code (updating values in the Scope) from an non-Angular context (jQuery event callback), so in order for having the changes processed by Angular (and the results propagated to the view), you must enclose the relevant code into scope.$apply().

  4. (This is not an error technically, but): You were converting some jQuery objects to jQuery objects again. This instroduces unnecessary overhead and should be avoided.


Taking into account the above, your directive's link function's body should look something like this:

element.on('click' , function(evt) {
    evt.stopImmediatePropagation();
    evt.preventDefault();

    $('.selected').removeClass('selected');
    element.addClass('selected');
    scope.$apply(function () {
        scope.myElementId    = attrs.id;
        scope.myElementClass = attrs.class;
        scope.myElementType  = element.prop('tagName');
    });
});

See, also, this woking demo.

Upvotes: 6

Nikola Nikolić
Nikola Nikolić

Reputation: 366

Your link function should look like this:

link: function(scope, element, attrs, controller) {
      element.on("click", function(event) {

        event.stopImmediatePropagation();
        event.preventDefault();

        $(".selected").removeClass("selected");
        $(element).addClass("selected");

        var mm = $(element).get(0);
        scope.myElementId = $(element).attr("id");
        scope.myElementClass = $(element).attr("class");
        scope.myElementType = mm.tagName;

      });
    }

Also you have an error in your code. Take care of camelcase names for controller and app.

Upvotes: 2

karaxuna
karaxuna

Reputation: 26930

Use scope.$apply:

scope.$apply(function(){
    scope.ele = angular.element(event.target);
    angular.element(".selected").removeClass("selected");
    $(scope.ele).addClass("selected");
    var mm = $(scope.ele).get(0);
    scope.myElementId = $(scope.ele).attr("id");
    scope.myElementClass = $(scope.ele).attr("class");
    scope.myElementType = mm.tagName;
});

You need this because you are modifying scope variables inside event and angularjs does not update dom in this case

Upvotes: 4

Related Questions