aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/services.js2
-rw-r--r--src/widgets.js78
-rw-r--r--test/widgetsSpec.js59
3 files changed, 138 insertions, 1 deletions
diff --git a/src/services.js b/src/services.js
index 3543b2ea..7742b174 100644
--- a/src/services.js
+++ b/src/services.js
@@ -616,7 +616,7 @@ function switchRouteMatcher(on, when, dstName) {
* Watches $location.hashPath and tries to map the hash to an existing route
* definition. It is used for deep-linking URLs to controllers and views (HTML partials).
*
- * $route is typically used in conjunction with ng:include widget.
+ * $route is typically used in conjunction with {@link angular.widget.ng:view ng:view} widget.
*
* @example
<p>
diff --git a/src/widgets.js b/src/widgets.js
index 3b0ffab7..4585629a 100644
--- a/src/widgets.js
+++ b/src/widgets.js
@@ -944,3 +944,81 @@ angularWidget("@ng:repeat", function(expression, element){
});
*/
angularWidget("@ng:non-bindable", noop);
+
+
+/**
+ * @ngdoc widget
+ * @name angular.widget.ng:view
+ *
+ * @description
+ * # Overview
+ * `ng:view` is a widget that complements the {@link angular.service.$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.
+ *
+ * This widget provides functionality similar to {@link angular.service.ng:include ng:include} when
+ * used like this:
+ *
+ * <ng:include src="$route.current.template" scope="$route.current.scope"></ng:include>
+ *
+ *
+ * # Advantages
+ * Compared to `ng:include`, `ng:view` offers these advantages:
+ *
+ * - shorter syntax
+ * - more efficient execution
+ * - doesn't require `$route` service to be available on the root scope
+ *
+ *
+ * # Example
+ * Because of the nature of this widget, we can't include the usual live example for it. Instead
+ * following is a code snippet showing the typical usage:
+ *
+ <pre>
+ <script>
+ angular.service('routeConfig', function($route) {
+ $route.when('/foo', {controller: MyCtrl, template: 'foo.html'});
+ $route.when('/bar', {controller: MyCtrl, template: 'bar.html'});
+ }, {$inject: ['$route'], $eager: true});
+
+ function MyCtrl() {};
+ </script>
+ <div>
+ <a href="#/foo">foo</a> | <a href="#/bar">bar</a> | <a href="#/undefined">undefined</a><br/>
+ The view is included below:
+ <hr/>
+ <ng:view></ng:view>
+ </div>
+ </pre>
+ */
+angularWidget('ng:view', function(element) {
+ var compiler = this;
+
+ if (!element[0]['ng:compiled']) {
+ element[0]['ng:compiled'] = true;
+ return injectService(['$xhr.cache', '$route'], function($xhr, $route, element){
+ $route.onChange(function(){
+ var src, scope;
+
+ if ($route.current) {
+ src = $route.current.template;
+ scope = $route.current.scope;
+ }
+
+ if (src) {
+ $xhr('GET', src, function(code, response){
+ element.html(response);
+ compiler.compile(element)(element, scope);
+ scope.$init();
+ });
+ } else {
+ element.html('');
+ }
+ });
+ });
+ } else {
+ this.descend(true);
+ this.directives(true);
+ }
+});
diff --git a/test/widgetsSpec.js b/test/widgetsSpec.js
index 48b9f8a1..27c5cb82 100644
--- a/test/widgetsSpec.js
+++ b/test/widgetsSpec.js
@@ -785,5 +785,64 @@ describe("widget", function(){
expect(element.text()).toEqual('');
});
});
+
+
+ describe('ng:view', function() {
+ var rootScope, partialScope, $route, $location, $browser;
+
+ beforeEach(function() {
+ rootScope = angular.scope();
+ partialScope = angular.compile('<ng:view></ng:view>', rootScope);
+ partialScope.$init();
+ $route = rootScope.$service('$route');
+ $location = rootScope.$service('$location');
+ $browser = rootScope.$service('$browser');
+ });
+
+ afterEach(function() {
+ dealoc(partialScope);
+ });
+
+
+ it('should do nothing when not routes are defined', function() {
+ $location.updateHash('/unknown');
+ rootScope.$eval();
+ expect(partialScope.$element.text()).toEqual('');
+ });
+
+
+ it('should load content via xhr when route changes', function() {
+ $route.when('/foo', {controller: angular.noop, template: 'myUrl1'});
+ $route.when('/bar', {controller: angular.noop, template: 'myUrl2'});
+
+ expect(partialScope.$element.text()).toEqual('');
+
+ $location.updateHash('/foo');
+ $browser.xhr.expectGET('myUrl1').respond('<div>{{1+3}}</div>');
+ rootScope.$eval();
+ $browser.xhr.flush();
+ expect(partialScope.$element.text()).toEqual('4');
+
+ $location.updateHash('/bar');
+ $browser.xhr.expectGET('myUrl2').respond('angular is da best');
+ rootScope.$eval();
+ $browser.xhr.flush();
+ expect(partialScope.$element.text()).toEqual('angular is da best');
+ });
+
+ it('should remove all content when location changes to an unknown route', function() {
+ $route.when('/foo', {controller: angular.noop, template: 'myUrl1'});
+
+ $location.updateHash('/foo');
+ $browser.xhr.expectGET('myUrl1').respond('<div>{{1+3}}</div>');
+ rootScope.$eval();
+ $browser.xhr.flush();
+ expect(partialScope.$element.text()).toEqual('4');
+
+ $location.updateHash('/unknown');
+ rootScope.$eval();
+ expect(partialScope.$element.text()).toEqual('');
+ });
+ });
});