Skip to content

State provider views

jeme edited this page Apr 4, 2013 · 14 revisions

We have already covered that each state can define multiple views and how the controller can be attached.

So lets look at the different ways you can define a template on a view.

Defining Templates

There is a number of ways to configure a template for a view, common for all of them is that you do it by the template property on a view.

Template as a String

The most common case might be to have a template defined as a simple string containing html or an URL to a file stored on the server.

To determine which is used, the regular expression ^(((http|https|ftp)://([\w-\d]+\.)+[\w-\d]+){0,1}(/?[\w~,;\-\./?%&+#=]*))$ with the case insensitive option is used, if it matches, the string is treated as an URL, otherwise it is returned as is. This may match more than what you wants it to, or maybe you actually wanted to use "http://github.com" as a value for the template.

If for any case, the string you provided isn't working as it should, try using the Template Object instead.

angular.module('phonecat', ['ui.routing']).
  config(['$stateProvider', function($stateProvider) {
  $stateProvider
      .state('phones', { 
          views: { 'main': { template: 'phones.html' } }
      })
}]);

Template as an Function

The most common case might be to have a template defined as an URL to a file stored on the server. If the template needs to be a bit more dynamic, or you wan't to select it based on parameters or something else, you can use a function (or an array with a function as the last element, and the preceeding elements to define dependencies, like we are use to in Angular)

The function can either return a string containing the template as html, or a promise that resolves to a string.

angular.module('phonecat', ['ui.routing']).
  config(['$stateProvider', function($stateProvider) {
  $stateProvider
      .state('phones', { 
          views: { 'main': { 
              template: ['$http', function($http) { return 'Hello Phones'; } ] } 
          }
      })
}]);

Template as an Object

The final way, which is also useful if you wish to be explicit in what type of template you provide, is a "template definition object". which defines one of 3 properties: html, url or fn.

angular.module('phonecat', ['ui.routing']).
  config(['$stateProvider', function($stateProvider) {
  $stateProvider
      .state('phones', { 
          views: { 
              'fnTpl': { template: { 
                  fn: ['$http', function($http) { return 'Hello Phones'; } ] } 
              },
              'urlTpl': { template: { url: 'phones.html'; } },
              'htmlTpl': { template: { html: 'Hello Phones' } },
          }
      })
}]);

This also helps you force the template provider to treat /some/string/that/looks/like/an/url as a pure html template. Where the automatic detection of what the template property was, would fail.

Views and the View Service

Defining views on a state is equivalent to calling the $view service.

Whenever a state opdate is triggered, the state machine checks all states from the root and down to the targeted state, for all non-changed states, down to the target, the $view.setIfAbsent function on the $view service is called, this ensures that if they view was removed it is reset.

For all states that have changed down to the target, the $view.setOrUpdate function is called. This will overwrite the view if it is currently defined.

All this is done in a transaction, so no changes take effect until all view changes has been determined, this ensure that if a parent state sets the view main and a child state overwrites it, we don't begin to render and then re-render when the child state overwrites.

Since it is done this way, it allows you to do additional view changes from transition handlers, like so:

angular.module('phonecat', ['ui.routing']).
  config(['$stateProvider', function($stateProvider) {
  $stateProvider
      .state('phones', { 
          views: { 
              'fnTpl': { template: { 
                  fn: ['$http', function($http) { return 'Hello Phones'; } ] } 
              },
              'urlTpl': { template: { url: 'phones.html'; } },
              'htmlTpl': { template: { html: 'Hello Phones' } },
          }
      })
      .transition('*', 'phones', function ($view) { $view.clear('htmlTpl'); $view.setIfAbsent('htmlTpl', 'Hello More Phones'); }
}]);

Which would overwrite the standard behavior in this case, and if we come from a state that already had the htmlTpl defined, we leave it alone. It is a bit cryptic here that we call ".clear". This will be covered in more detail in the View Provider section, where transactions are covered, and how they behave compared to direct updates.

Clone this wiki locally