diff options
| author | Igor Minar | 2013-03-13 16:29:26 -0700 | 
|---|---|---|
| committer | Misko Hevery | 2013-06-27 21:30:24 -0700 | 
| commit | 15e1a29cd08993b599f390e83a249ec17f753972 (patch) | |
| tree | caa9eb0204d123b0c3c2d2a427bc580beddfefda | |
| parent | 344e195c60731f18529dacd35b478afb9dbeddf1 (diff) | |
| download | angular.js-15e1a29cd08993b599f390e83a249ec17f753972.tar.bz2 | |
fix(compiler): corrects component transclusion on compilation root.
Closes# 2155
| -rw-r--r-- | src/ng/compile.js | 20 | ||||
| -rwxr-xr-x | test/ng/compileSpec.js | 10 | ||||
| -rw-r--r-- | test/ng/directive/ngRepeatSpec.js | 95 | 
3 files changed, 112 insertions, 13 deletions
| diff --git a/src/ng/compile.js b/src/ng/compile.js index caa4e8ce..36043a15 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -749,7 +749,7 @@ function $CompileProvider($provide) {                      newTemplateAttrs                  )              ); -            mergeTemplateAttributes(templateAttrs, newTemplateAttrs); +            mergeTemplateAttributes(templateAttrs, newTemplateAttrs, directive.name);              ii = directives.length;            } else { @@ -1007,15 +1007,16 @@ function $CompileProvider($provide) {       *       * @param {object} dst destination attributes (original DOM)       * @param {object} src source attributes (from the directive template) +     * @param {string} ignoreName attribute which should be ignored       */ -    function mergeTemplateAttributes(dst, src) { +    function mergeTemplateAttributes(dst, src, ignoreName) {        var srcAttr = src.$attr,            dstAttr = dst.$attr,            $element = dst.$$element;        // reapply the old attributes to the new element        forEach(dst, function(value, key) { -        if (key.charAt(0) != '$') { +        if (key.charAt(0) != '$' && key != ignoreName) {            if (src[key]) {              value += (key === 'style' ? ';' : ' ') + src[key];            } @@ -1030,7 +1031,7 @@ function $CompileProvider($provide) {            dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;          } else if (key == 'style') {            $element.attr('style', $element.attr('style') + ';' + value); -        } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) { +        } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key) && key != ignoreName) {            dst[key] = value;            dstAttr[key] = srcAttr[key];          } @@ -1073,14 +1074,19 @@ function $CompileProvider($provide) {              tempTemplateAttrs = {$attr: {}};              replaceWith($rootElement, $compileNode, compileNode);              collectDirectives(compileNode, directives, tempTemplateAttrs); -            mergeTemplateAttributes(tAttrs, tempTemplateAttrs); +            mergeTemplateAttributes(tAttrs, tempTemplateAttrs, origAsyncDirective.name);            } else {              compileNode = beforeTemplateCompileNode;              $compileNode.html(content);            }            directives.unshift(derivedSyncDirective); -          afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs, childTranscludeFn); +          afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs, childTranscludeFn, $compileNode); +          forEach($rootElement, function(node, i) { +            if (node == compileNode) { +              $rootElement[i] = $compileNode[0]; +            } +          });            afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn); @@ -1089,7 +1095,7 @@ function $CompileProvider($provide) {                  beforeTemplateLinkNode = linkQueue.shift(),                  linkRootElement = linkQueue.shift(),                  controller = linkQueue.shift(), -                linkNode = compileNode; +                linkNode = $compileNode[0];              if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {                // it was cloned therefore we have to clone as well. diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js index 672a704d..0ef7e8bf 100755 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -534,7 +534,7 @@ describe('$compile', function() {            expect(div.hasClass('log')).toBe(true);            expect(div.css('width')).toBe('10px');            expect(div.css('height')).toBe('20px'); -          expect(div.attr('replace')).toEqual(''); +          expect(div.attr('replace')).toEqual(undefined);            expect(div.attr('high-log')).toEqual('');          })); @@ -856,7 +856,7 @@ describe('$compile', function() {            $rootScope.$digest();            expect(sortedHtml(element)). -            toEqual('<div><b class="hello"><span replace="">Hello, Elvis!</span></b></div>'); +            toEqual('<div><b class="hello"><span>Hello, Elvis!</span></b></div>');          })); @@ -868,7 +868,7 @@ describe('$compile', function() {                $rootScope.$digest();                expect(sortedHtml(element)). -                  toEqual('<span replace="">Hello, Elvis!</span>'); +                  toEqual('<span>Hello, Elvis!</span>');              })); @@ -1077,7 +1077,7 @@ describe('$compile', function() {              var div = element.find('div');              expect(div.attr('i-first')).toEqual(''); -            expect(div.attr('i-second')).toEqual(''); +            expect(div.attr('i-second')).toEqual(undefined);              expect(div.attr('i-third')).toEqual('');              expect(div.attr('i-last')).toEqual(''); @@ -1127,7 +1127,7 @@ describe('$compile', function() {              var div = element.find('div');              expect(div.attr('i-first')).toEqual(''); -            expect(div.attr('i-second')).toEqual(''); +            expect(div.attr('i-second')).toEqual(undefined);              expect(div.attr('i-third')).toEqual('');              expect(div.attr('i-last')).toEqual(''); diff --git a/test/ng/directive/ngRepeatSpec.js b/test/ng/directive/ngRepeatSpec.js index 9fc445ba..925a93ce 100644 --- a/test/ng/directive/ngRepeatSpec.js +++ b/test/ng/directive/ngRepeatSpec.js @@ -1,7 +1,11 @@  'use strict';  describe('ngRepeat', function() { -  var element, $compile, scope, $exceptionHandler; +  var element, $compile, scope, $exceptionHandler, $compileProvider; + +  beforeEach(module(function(_$compileProvider_) { +    $compileProvider = _$compileProvider_; +  }));    beforeEach(module(function($exceptionHandlerProvider) { @@ -448,6 +452,95 @@ describe('ngRepeat', function() {    }); +  describe('nesting in replaced directive templates', function() { + +    it('should work when placed on a root element of attr directive with SYNC replaced template', +        inject(function($templateCache, $compile, $rootScope) { +      $compileProvider.directive('replaceMeWithRepeater', function() { +        return { +          replace: true, +          template: '<span ng-repeat="i in items">{{log(i)}}</span>' +        } +      }); +      element = jqLite('<span replace-me-with-repeater></span>'); +      $compile(element)($rootScope); +      expect(element.text()).toBe(''); +      var logs = []; +      $rootScope.log = function(t) { logs.push(t); }; + +      // This creates one item, but it has no parent so we can't get to it +      $rootScope.items = [1, 2]; +      $rootScope.$apply(); + +      // This cleans up to prevent memory leak +      $rootScope.items = []; +      $rootScope.$apply(); +      expect(angular.mock.dump(element)).toBe('<!-- ngRepeat: i in items -->'); +      expect(logs).toEqual([1, 2, 1, 2]); +    })); + + +    iit('should work when placed on a root element of attr directive with ASYNC replaced template', +        inject(function($templateCache, $compile, $rootScope) { +      $compileProvider.directive('replaceMeWithRepeater', function() { +        return { +          replace: true, +          templateUrl: 'replace-me-with-repeater.html' +        } +      }); +      $templateCache.put('replace-me-with-repeater.html', '<div ng-repeat="i in items">{{log(i)}}</div>'); +      element = jqLite('<span>-</span><span replace-me-with-repeater></span><span>-</span>'); +      $compile(element)($rootScope); +      expect(element.text()).toBe('--'); +      var logs = []; +      $rootScope.log = function(t) { logs.push(t); }; + +      // This creates one item, but it has no parent so we can't get to it +      $rootScope.items = [1, 2]; +      $rootScope.$apply(); + +      // This cleans up to prevent memory leak +      $rootScope.items = []; +      $rootScope.$apply(); +      expect(sortedHtml(element)).toBe('<span>-</span><!-- ngRepeat: i in items --><span>-</span>'); +      expect(logs).toEqual([1, 2, 1, 2]); +    })); + + +    it('should work when placed on a root element of element directive with SYNC replaced template', +        inject(function($templateCache, $compile, $rootScope) { +      $compileProvider.directive('replaceMeWithRepeater', function() { +        return { +          restrict: 'E', +          replace: true, +          template: '<div ng-repeat="i in [1,2,3]">{{i}}</div>' +        } +      }); +      element = $compile('<div><replace-me-with-repeater></replace-me-with-repeater></div>')($rootScope); +      expect(element.text()).toBe(''); +      $rootScope.$apply(); +      expect(element.text()).toBe('123'); +    })); + + +    it('should work when placed on a root element of element directive with ASYNC replaced template', +        inject(function($templateCache, $compile, $rootScope) { +      $compileProvider.directive('replaceMeWithRepeater', function() { +        return { +          restrict: 'E', +          replace: true, +          templateUrl: 'replace-me-with-repeater.html' +        } +      }); +      $templateCache.put('replace-me-with-repeater.html', '<div ng-repeat="i in [1,2,3]">{{i}}</div>'); +      element = $compile('<div><replace-me-with-repeater></replace-me-with-repeater></div>')($rootScope); +      expect(element.text()).toBe(''); +      $rootScope.$apply(); +      expect(element.text()).toBe('123'); +    })); +  }); + +    describe('stability', function() {      var a, b, c, d, lis; | 
