mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-04-05 23:51:03 +00:00
The change to prevent <span> elements being wrapped around empty text nodes caused these empty text nodes to have scopes and controllers attached, through jqLite.data() calls, which led to memory leaks and errors in IE8. Now we exclude all but document nodes and elements from having jqLite.data() set both in the compiler and in ng-view. Fixes: #1968 and #1876
165 lines
5 KiB
JavaScript
165 lines
5 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* @ngdoc directive
|
|
* @name ng.directive:ngView
|
|
* @restrict ECA
|
|
*
|
|
* @description
|
|
* # Overview
|
|
* `ngView` is a directive that complements the {@link ng.$route $route} service by
|
|
* including the rendered template of the current route into the main layout (`index.html`) file.
|
|
* Every time the current route changes, the included view changes with it according to the
|
|
* configuration of the `$route` service.
|
|
*
|
|
* @scope
|
|
* @example
|
|
<example module="ngView">
|
|
<file name="index.html">
|
|
<div ng-controller="MainCntl">
|
|
Choose:
|
|
<a href="Book/Moby">Moby</a> |
|
|
<a href="Book/Moby/ch/1">Moby: Ch1</a> |
|
|
<a href="Book/Gatsby">Gatsby</a> |
|
|
<a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
|
|
<a href="Book/Scarlet">Scarlet Letter</a><br/>
|
|
|
|
<div ng-view></div>
|
|
<hr />
|
|
|
|
<pre>$location.path() = {{$location.path()}}</pre>
|
|
<pre>$route.current.templateUrl = {{$route.current.templateUrl}}</pre>
|
|
<pre>$route.current.params = {{$route.current.params}}</pre>
|
|
<pre>$route.current.scope.name = {{$route.current.scope.name}}</pre>
|
|
<pre>$routeParams = {{$routeParams}}</pre>
|
|
</div>
|
|
</file>
|
|
|
|
<file name="book.html">
|
|
controller: {{name}}<br />
|
|
Book Id: {{params.bookId}}<br />
|
|
</file>
|
|
|
|
<file name="chapter.html">
|
|
controller: {{name}}<br />
|
|
Book Id: {{params.bookId}}<br />
|
|
Chapter Id: {{params.chapterId}}
|
|
</file>
|
|
|
|
<file name="script.js">
|
|
angular.module('ngView', [], function($routeProvider, $locationProvider) {
|
|
$routeProvider.when('/Book/:bookId', {
|
|
templateUrl: 'book.html',
|
|
controller: BookCntl
|
|
});
|
|
$routeProvider.when('/Book/:bookId/ch/:chapterId', {
|
|
templateUrl: 'chapter.html',
|
|
controller: ChapterCntl
|
|
});
|
|
|
|
// configure html5 to get links working on jsfiddle
|
|
$locationProvider.html5Mode(true);
|
|
});
|
|
|
|
function MainCntl($scope, $route, $routeParams, $location) {
|
|
$scope.$route = $route;
|
|
$scope.$location = $location;
|
|
$scope.$routeParams = $routeParams;
|
|
}
|
|
|
|
function BookCntl($scope, $routeParams) {
|
|
$scope.name = "BookCntl";
|
|
$scope.params = $routeParams;
|
|
}
|
|
|
|
function ChapterCntl($scope, $routeParams) {
|
|
$scope.name = "ChapterCntl";
|
|
$scope.params = $routeParams;
|
|
}
|
|
</file>
|
|
|
|
<file name="scenario.js">
|
|
it('should load and compile correct template', function() {
|
|
element('a:contains("Moby: Ch1")').click();
|
|
var content = element('.doc-example-live [ng-view]').text();
|
|
expect(content).toMatch(/controller\: ChapterCntl/);
|
|
expect(content).toMatch(/Book Id\: Moby/);
|
|
expect(content).toMatch(/Chapter Id\: 1/);
|
|
|
|
element('a:contains("Scarlet")').click();
|
|
content = element('.doc-example-live [ng-view]').text();
|
|
expect(content).toMatch(/controller\: BookCntl/);
|
|
expect(content).toMatch(/Book Id\: Scarlet/);
|
|
});
|
|
</file>
|
|
</example>
|
|
*/
|
|
|
|
|
|
/**
|
|
* @ngdoc event
|
|
* @name ng.directive:ngView#$viewContentLoaded
|
|
* @eventOf ng.directive:ngView
|
|
* @eventType emit on the current ngView scope
|
|
* @description
|
|
* Emitted every time the ngView content is reloaded.
|
|
*/
|
|
var ngViewDirective = ['$http', '$templateCache', '$route', '$anchorScroll', '$compile',
|
|
'$controller',
|
|
function($http, $templateCache, $route, $anchorScroll, $compile,
|
|
$controller) {
|
|
return {
|
|
restrict: 'ECA',
|
|
terminal: true,
|
|
link: function(scope, element, attr) {
|
|
var lastScope,
|
|
onloadExp = attr.onload || '';
|
|
|
|
scope.$on('$routeChangeSuccess', update);
|
|
update();
|
|
|
|
|
|
function destroyLastScope() {
|
|
if (lastScope) {
|
|
lastScope.$destroy();
|
|
lastScope = null;
|
|
}
|
|
}
|
|
|
|
function clearContent() {
|
|
element.html('');
|
|
destroyLastScope();
|
|
}
|
|
|
|
function update() {
|
|
var locals = $route.current && $route.current.locals,
|
|
template = locals && locals.$template;
|
|
|
|
if (template) {
|
|
element.html(template);
|
|
destroyLastScope();
|
|
|
|
var link = $compile(element.contents()),
|
|
current = $route.current,
|
|
controller;
|
|
|
|
lastScope = current.scope = scope.$new();
|
|
if (current.controller) {
|
|
locals.$scope = lastScope;
|
|
controller = $controller(current.controller, locals);
|
|
element.children().data('$ngControllerController', controller);
|
|
}
|
|
|
|
link(lastScope);
|
|
lastScope.$emit('$viewContentLoaded');
|
|
lastScope.$eval(onloadExp);
|
|
|
|
// $anchorScroll might listen on event...
|
|
$anchorScroll();
|
|
} else {
|
|
clearContent();
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}];
|