Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

AngularJS UI router named views loading based on user access rather than loading at the time of state route access.

Example:

$stateProvider
.state("login",
{
    url: "/login",
    templateUrl: getTemplateUrl("login/Index")
})    
.state("main",
{
    url: "/main",
    views: 
    {
        '': { templateUrl: getTemplateUrl('home/shell') },
        'test1@main': { templateUrl: 'home/test1' },
        'test2@main': { templateUrl: 'home/test2' },
        'test3@main': { templateUrl:  getTemplateUrl('home/test3') }                     
    }
});

In the above example, when a user accesses the state main the UI-router loads all the named views html from server.

Question:

Can we load named-views when required below? I mean whenever we add new tab dynamically then only loading respected view html from server.

<tab ng-repeat="tab in tabs">    
    <div>     
        <div ui-view='{{tab.view}}'></div>
    </div>
 </tab>
share|improve this question

This question has an open bounty worth +100 reputation from Venkat ending tomorrow.

Looking for an answer drawing from credible and/or official sources.

    
just to clarify, what you asking is it possible to only load respected view from server without it load everything ? –  kwan245 May 21 at 0:01
    
maybe this will help: stackoverflow.com/questions/28184616/… –  sirrocco May 22 at 16:54

1 Answer 1

up vote 2 down vote accepted

If you are looking to load your tab content dynamically from template urls based on the value of tabs available to the user as defined in $scope.tabs, you should consider using a simple directive rather than ui-router views.

As you have already discovered ui-router will try and load the subviews regardless of whether they are referenced in the main view for that state.

We can however use our own directive to load templates, and therefore because the directive only runs when present in the main view, the templates load on demand.

template Directive:

We create a template directive, that allows us to pull in a template into an html element.

.directive('template', ['$compile', '$http', function($compile, $http) {
    return {
        restrict: 'A',
        replace: false,
        link: function($scope, element, attrs) {
            var template = attrs['template'];
            var controller = attrs['controller'];
            if(template!==undefined){
                // Load the template
                $http.get(template).success(function(html){
                    // Set the template
                    var e = angular.element(controller === undefined || controller.length === 0 ? html : "<span ng-controller='" + controller + "'>" + html + "</span>");
                    var compiled = $compile(e);
                    element.html(e);
                    compiled($scope);
                });
            }
        }
    };
}]);

So this code uses the $http service to get the template from the server. Then it uses the $compile service to apply the scope to the angular template, and renders it into the target element.

Usage:

Update the format of your main tabs template as below. Note we no longer reference ui-view, instead we call our template directive passing in the url we want to load in the div. With the current content of the div being the loading indicator.

(If the controller attribute is set the template will be wrapped with an <span> having the ng-controller attribute, so a template controller can be applied. This is optional.)

in home/shell:

<tab ng-repeat="(tabName,tab) in tabs">
    <div template='{{tab.template}}' controller="{{tab.controller}}">Loading {{tabName}} ...</div>
 </tab>

Then set the tabs you want to display:

$scope.tabs = {
    'tab1': { template: 'home/tab1'},
    'tab2': { template: 'home/tab2', controller: 'Tab2Controller' },
    'tab3': { template: 'home/tab3'}
};

Full source:

This just puts the code given above, as an example AngularJS app. Assumes the template paths are valid i.e. home/shell, home/tab1 etc.

<!DOCTYPE html>
<html>
<head>
    <script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.15/angular-ui-router.js"></script>
    <meta charset="utf-8">
    <title>Angular Views</title>
</head>
<body ng-app="myTabbedApp">
    <div ui-view></div>
    <script>
        angular.module('myTabbedApp', ['ui.router'])

            /* Controller for the Main page ie. home/shell */
            .controller('MainPageTabController', ['$scope', function($scope) {
                // Set the page tabs dynamically as required by your code
                $scope.tabs = {
                    'tab1': { template: 'home/tab1'},
                    'tab2': { template: 'home/tab2', controller: 'Tab2Controller' },
                    'tab3': { template: 'home/tab3'}
                };
            }])

            /* Example controller for Tab 2 */
            .controller('Tab2Controller', ['$scope', function($scope) {
                $scope.hello = "world";
            }])

            /* State provider for ui router */
            .config(['$stateProvider', function($stateProvider){
                $stateProvider
                    .state("login",
                    {
                        url: "/login",
                        templateUrl: "login/index"
                    })
                    .state("main",
                    {
                        url: "/main",
                        templateUrl: 'home/shell',
                        controller: 'MainPageTabController'
                    });
            }])

            /* Directive to load templates dynamically */
            .directive('template', ['$compile', '$http', function($compile, $http) {
                return {
                    restrict: 'A',
                    replace: false,
                    link: function($scope, element, attrs) {
                        var template = attrs['template'];
                        if(template!==undefined){
                            // Load the template
                            $http.get(template).success(function(html){
                                // Set the template
                                var e = angular.element(html);
                                var compiled = $compile(e);
                                element.html(e);
                                compiled($scope);
                            });
                        }
                    }
                };
            }]);
    </script>
</body>
</html>

I hope this helps. If you have questions about something just ask.

share|improve this answer
    
By default named views not able to load dynamically after state route, directives working for us. –  Venkat 3 hours ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.