angular / angular.js

AngularJS - HTML enhanced for web apps!
https://angularjs.org
MIT License
58.85k stars 27.52k forks source link

Surprising behavior (and regression) when $compiling ngInclude directives #4505

Closed wizardwerdna closed 10 years ago

wizardwerdna commented 10 years ago

$compiling a naked ng-include directive fails in 1.2.0-rc.*, although it has worked in earlier versions. In a test along the following lines:

describe('Integration',function(){
  var app;
  beforeEach(module('app', 'views/main.html'));
  beforeEach(inject(function($compile, $rootScope){
    app = $compile(
      '<ng-include src="\'views/main.html\'"></ng-include>'
    )($rootScope.$new());
    $rootScope.$digest();
    console.log(angular.version);
    console.log(app);
  }));
  it('should run angular', function(){
    expect(app.find('h1').text()).toBe('Super2');
  });
});

where views/main.html is:

<h1>Super{{1+1}}</h1>

I get the following results, for v1.0.5, which works fine:

LOG: Object{full: '1.0.5', major: 1, minor: 0, dot: 5, codeName: 'flatulent-propulsion'}
LOG: {0: <ng-include src="'views/main.html'" class="ng-scope"><h1 class="ng-scope ng-binding">Super2</h1>

and the test passes, but for 1.2.0.rc-*:

LOG: Object{full: '1.2.0-rc.3', major: 1, minor: 2, dot: 0, codeName: 'ferocious-twitch'}
LOG: {0: <!-- ngInclude: undefined -->, length: 1}

the test fails, with the actual result being '' instead of Super2. Interestingly, the code works just fine in both versions if you surround the <ng-include> directive with a naked <div>.

If this is an intended regression, I haven't seen any documentation (which doesn't mean its not there). Can you explain the reasons why this directive fails in current versions, while others do not, so I can anticipate the problem? Or should I simply make a routine practice of surrounding all code delivered to compile with a naked div?

caitp commented 10 years ago

repro yeah, that's not good working with containing element


Is the reason for this because of the inclusion of the comment element, which causes the ng-include template to not contain a single element?

https://github.com/angular/angular.js/blob/master/src/ng/compile.js#L833 is where the comment is coming from, because of the transclude: 'element' in ngInclude (and other directives which insert comments). Anyways, I'm not sure that this isn't desirable behaviour, but some possible fixes:

  1. return a jqlite collection of each DOM node in the template, rather than requiring templates to have a single parent element.
  2. automatically create a parent element if multiple top-level elements in a template are detected (I don't like this).
  3. ...? I don't have all the ideas.
petebacondarwin commented 10 years ago

Your analysis is correct @caitp - the ng-include element is replaced by a comment. The contents of the include are then inserted "after" the comment. This should make little difference in most cases but if you are doing direct DOM manipulation you should be aware that there will now be two sibling elements.

caitp commented 10 years ago

been a while since I wrote that one =)

petebacondarwin commented 10 years ago

I am going to document this either in a testing section or in the $compile docs.

btford commented 10 years ago

Taking over this since Jeff is out (unless pete or caitlin want at it).