6

How could I use a name fetched from my database as a templateUrl filename?

I've tried this:

$stateProvider.state('/', {
  url: '/',
  views: {
    page: {
      controller: 'HomeCtrl',
      templateProvider: function($templateFactory, $rootScope) {
        console.log("$rootScope.template")
        return $templateFactory.fromUrl('/templates/' + $rootScope.template);
      }
    }
  }
});

Which doesn't seem to work work if my $rootScope.template comes from a database query. Don't know why, but it doesn't work.

If in my controller I do $rootScope.template = "whatever.html" everything works ok, but if I query the template from database nothing happens at all. console.log("$rootScope.template") in templateProvider gives me nothing (the query itself works just fine).

Does the query simply take too long and it's therefore not ready for the router or what's happening here?

That am I doing wrong and how can I fix it?

QlliOlli
  • 637
  • 3
  • 13
  • 25
  • Perhaps you're confused as to how to handle asynchronous requests? If you change your logging line to this: `console.log("$rootScope.template=" + $rootScope.template)` is it empty? – wvdz Nov 11 '14 at 15:55
  • Nah, sorry those ""'s where there by accident as I just quickly typed the last lines here without copy/pasting.. I do have it written correctly in my code but it doesn't change anything (as you can see it's correctly written in the next line... – QlliOlli Nov 11 '14 at 16:01

2 Answers2

9

As discussed in this Q & A: Angular UI Router: decide child state template on the basis of parent resolved object, we can do that like this

This could be a service playing role of "from Server/DB loading template name":

.factory('GetName', ['$http', '$timeout',
    function($http, $timeout) {
      return {
        get : function(id) {
          // let's pretend server async delay
          return $timeout(function(){
            // super simplified switch... but ...
            var name = id == 1
                  ? "views.view2.html"
                  : "views.view2.second.html"
                  ;
            return {templateName : name}; 
          }, 500);
        },
      };
    }
]);

Then the templateProvider defintion would look like this:

  views: {
    "page": {
      templateProvider: function($http, $stateParams, GetName) {

        // async service to get template name from DB
        return GetName
            .get($stateParams.someSwitch)
            // now we have a name
            .then(function(obj){
               return $http
                  // let's ask for a template
                  .get(obj.templateName)
                  .then(function(tpl){
                      // haleluja... return template
                      return tpl.data;
               });      
            })

      }, 

The code should be self explanatory. Check this answer and its plunker for more details

Community
  • 1
  • 1
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • Ok, this work - I'm almost there. Now my problem is how to get that piece of text I need (my template name) from my database to the templateProvider... I do return $http.get("/api/mysites") in the 'GetName' service. Then in templateProvider obj = GetSite.get(). Now, how can I access that data inside this promise? if I console.log obj I get the promise stuff (and find my data under $$state or whatever). So I cant turn that timeout stuff from your services to a real call from a database which would return my needed value. – QlliOlli Nov 12 '14 at 11:05
  • This updated plunker should show you how to: http://plnkr.co/edit/kGvrPdINl7M0WoHZGnyU?p=preview. The point is, that we load data from server (trick here is some call for a `dataFromServer.json`). It should be some method `GetById`... returning the string in life... but here it is good. Once it comes, we take it and return the matching template name. Does it help? – Radim Köhler Nov 12 '14 at 11:15
  • 1
    I tried to explain the point in another answer, targeting the "issue" with how to handle real $http reponse. Does that helped? – Radim Köhler Nov 12 '14 at 11:23
  • Thank you! Everything works perfectly now. This was big help! – QlliOlli Nov 12 '14 at 11:34
  • Great to see that, sir! ;) Enjoy amazing UI-Router ;) – Radim Köhler Nov 12 '14 at 11:34
2

I created an example, which does use some json to be load as data from the server, check it here. This what the $http will recieve (in our simplifed examle)

// dataFromServer.json
{
  "1": "views.view2.html",
  "2": "views.view2.second.html"
}

So this will come via $http and we will use it to return the name

.factory('GetName', ['$http', '$timeout',
    function($http, $timeout) {
      return {
        get : function(id) {
          // let's get data via $http
          // here it is the list, but 
          // should be some GetById method
          return $http
            .get("dataFromServer.json")
            .then(function(response){

              // simplified converter
              // taking the $http result and 
              // by id gets the name
              var converter = response.data;
              var name = converter[id];

              return {templateName : name}; 
          });
        },
      };
}

As we can see, this time, we really go for server data, using $http the trick again is to return that promise

return $http // see the return
  .get....

and later, we return again... inside of the then

....
.then(function(response){
   ...
   return {templateName : name}; 
});

That Example is here

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335