Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS Scope differences between 1.0.x and 1.2.x

As of the release of the next stable AngularJS, I am migrating my application from version 1.0.8 to 1.2.

In AngularJS 1.0.8 it was possible to set up an isolated scope for directives like follow. The directive would then use its own test() function instead of the controller's test() function.

HTML

<my-dialog property="something">
    <button ng-click="test()">Load Test</button>
    Check out the test: "{{ testMessage }}"
</my-dialog>

Javascript

  .controller('Ctrl', function(scope) {
    scope.test = function () {
       scope.testMessage = 'CTRL Test loaded! Whooops.';
    }
  })

  .directive('myDialog', function() {
    return {
      restrict: 'E',
      scope: {
          property: '='
      },
      link: function(scope) {
          scope.test = function () {
            scope.testMessage = 'Isolated Test loaded. Yes!';
          }
      }
    };

In AngularJS 1.2 this behavior doesn't work anymore. Clicking the button fires the controller's test() function now.

See this jsFiddle comparison:

  • Angular 1.0.8
  • Angular 1.2.0

What exactly has changes and how can I reproduce the old behavior?

Note

I figured out I could place the directives template inside an extra HTML file or compile it as a string to get it working (jsFiddle) but it seems to be too much in my case, as the template is fixed and splitting the HTML over several partial HTML files is a hassle.

EDIT

@elclanr's answer works fine when there are no other properties to share. I updated the jsFiddle to pass some arbitrary property. How should I proceed now?

like image 744
F Lekschas Avatar asked Nov 13 '13 02:11

F Lekschas


2 Answers

It looks like this is an intended result of the breaking change: github.com/angular/angular.js/commit/… Which was pulled in 1.2.0 (after rc3) (https://github.com/angular/angular.js/blob/master/CHANGELOG.md - see the first breaking change for 1.2.0 - $compile):

Fixes issue with isolate scope leaking all over the place into other directives on the same element.

Isolate scope is now available only to the isolate directive that requested it and its template.

A non-isolate directive should not get the isolate scope of an isolate directive on the same element,instead they will receive the original scope (which is the parent scope of the newly created isolate scope).

Also check out this discussion: github.com/angular/angular.js/issues/4889

Notably: "The isolate scope is only applied to the template, but not to markup that was not contributed by the directive. Before 1.2 isolate scopes had a bug that caused this kind of leakage. The point of the isolate scope is that it only applies to the directive that declared it, and not to other directives or markup." (from tbosch)

Previous to 1.2.0 everything on the same DOM element shared the same scope. So 1.2.0 makes a substantial change to how directives with isolate scopes work.

like image 50
KayakDave Avatar answered Oct 01 '22 14:10

KayakDave


Setting scope: true should solve the issue. http://jsfiddle.net/rug3J/1. I would also advise to follow convention and name it scope and not $scope when it's not dependency injected:

.directive('myDialog', function() {
  return {
    restrict: 'E',
    scope: true,
    link: function(scope) {
      scope.test = function () {
        scope.testMessage = 'Isolated Test loaded. Yes!';
      }
    }
  };
like image 42
elclanrs Avatar answered Oct 01 '22 14:10

elclanrs