I'm using ng-boilerplate and have to add the possibility to use different templates in production, based on the user configuration.

.config(function config( $stateProvider ) {
 $stateProvider.state( 'demo', {
    url: '/demo',
    views: {
      "main": {
        controller: 'DemoCtrl',
        templateUrl: 'demo/demo.tpl.html'
      }
    }
  });
})

My current idea is to make the templateUrl dynamic

templateUrl: 'demo/demo'+userService.getTemplate()+'.tpl.html'

and having multiple template files, like:

  • demo.tpl.html (default)
  • demo.b.tpl.html (version b)
  • demo.c.tpl.html (version c)

while the userService function does provide the template version to use, e.g. ".b"

Do you agree? Is there maybe a better/easier approach to this problem?

有帮助吗?

解决方案

AngularJS standard $routeProvider can accept function for templateUrl. But you can't inject services into this function.

ui-router has templateProvider parameter into which you can inject what you want and you should return something like this for remote template case:

$stateProvider.state('demo', {
    templateProvider: function ($http, $templateCache, $stateParams, userService) {
        var url = 'demo/demo' + userService.getTemplate() + '.tpl.html';
        return $http.get(url, { cache: $templateCache }).then(function (response) {
            return response.data;
        });
    }
})

其他提示

I will not keep it in service, because service will be a part of js file. Which will be static (under normal condition)

This is how I will do it, In html file I will put

window.abConfig = "defaultVersion";

In app.js I will put

.config(function config( $stateProvider ) {
 $stateProvider.state( 'demo', {
    url: '/demo',
    views: {
      "main": {
        controller: 'DemoCtrl',
        templateUrl: function() {
          return 'demo/demo' + window.abConfig + '.tpl.html';
        }
      }
    }
  });
})

Its kind of Hacky way, but it gives me flexibility to decide which version to display to user at server level. I might require to write logic before user download the content based on user's previous activity, which I can not do from client side javascript.

This can be achieved using standard angular, you just have to look at it from another angle!

I would suggest using the $templateCache. When you load the app you can pre-populate the $template cache with the selected version of the user templates.

You can do something like

$templateCache.put("page-header.html", '<h1>MyAwesomeStartup</h1><h2>Buy now!?!?!</h2>');

Also if your not opposed to the idea, you can place the templates into the page using the script tag syntax, where the id == the templateURL you use in your $routeProvider.

<script type="text/ng-template" id="page-header.html">
  <h1>MyAwesomeStartup</h1><h2>Buy now!?!?!</h2>
</script>

And ng will load it directly from the script tag.

I've a different way based on the same principle

Except you don't have to actually request the view yourself with $http.

So you can let ui-router handle that part.

Which is easier when you have a complex view architecture.

.state('public.index', {
            url: '/',
            views: {
                "": {
                    template: '<div ui-view="abTestDummyView"></div>',
                    controller: ['landing', '$http', function(landing, $http) {
                        alert('Showing AB Test Landing #' + landing);
                        // increment landing stats
                        $http.get('http://stats.domain.com', {landing: landing});
                    }],
                    controllerAs: 'landingCtrl',
                },
                "abTestDummyView@public.index": {
                    templateProvider: ['landing', function(landing) {
                        // inject a view based on its name
                        return "<div ui-view=\"ab" + landing + "\"></div>";
                    }]
                },
                "ab1@public.index": {
                    template: "INJECTED AB1"
                    // replace by templateUrl: "/real path/"
                },
                "ab2@public.index": {
                    template: "INJECTED AB2"
                    // replace by templateUrl: "/real path/"
                }
            },
            resolve: {
                landing: function() {
                    return Math.floor((Math.random() * 2) + 1);
                }
            }
        })
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top