morgs32
morgs32

Reputation: 1459

Resolve on Angular UI Router appStates not Delivering Scope Data

I need data in a "sub" state and I am pulling my hair out trying to get it. The problem is I want the data to come from the $rootScope every time.

So here goes - an outline of my problem.

I'm using state provider. So here is my first state:

    .state('dashboard.create', {
        // parent: 'dashboard',
        url: '/create',
        views: {
          '': {
            templateUrl: "/app/partials/create.html",
            controller: "CreateCtrl",
          }
        }
      })

In the CreateCtrl all I do is call this dashboardAPI.lessons();

services.factory('dashboardAPI', ['$rootScope', '$q', '$http', function(rootScope, $q, $http) {

  function load(path) {
    return $http.get("/app/data" + path);
  }

  return {
    lessons: function() {
      var deferred = $q.defer();

      if (rootScope.lessons == undefined) {
        load("/getLessons.json").success(function (data) {
          rootScope.lessons = data.result;
          deferred.resolve(data.result);
        }).
        error( function() {
          console.log("Problem getting lessons");
        });
      }
      else
        deferred.resolve(rootScope.lessons);
      return deferred.promise;
    }
  };

}]);

This works to fill the rootScope.lessons object so I can populate the view.

Then, there's a sub state like this:

    .state('dashboard.create.lessons', {
        // parent: 'create',
        url: '/lessons',
        views: {
          'curriculum': {
            templateUrl: "/app/partials/create.lessons.html",
            controller: ['curriculumHash', function(curriculumHash){
              curriculumHash.sstHash();
            }],
          },
        }
      })

In this controller it's calling another service:

services.factory('curriculumHash', ['$rootScope', '$q', 'dashboardAPI', function(rootScope, $q, dashboardAPI) {

  return {
    sstHash: function() {
      var deferred = $q.defer();

      if (rootScope.sstopicsArray == undefined) {
        //Get a promise back from API call
        dashboardAPI.lessons().then(function(data) {
          rootScope.sstopicsArray = [];
          var x = data.Topics;
          for (var i=0; i<x.length; i++) {
            var y = x[i].Subtopics;
            for (var j=0; j<y.length; j++) {
              var z = y[j].Subsubtopics;
              for (var k=0; k<z.length; k++) {
                rootScope.sstopicsArray.push({
                  Id: z[k].Id,
                  Name: z[k].Name,
                  Description: z[k].Description,
                  List: z[k].Lessons
                });
              }
            }
          }
          return deferred.resolve();
        });
      }
      else
        return deferred.resolve();
    }
  };
}]);

And this also works. At filling the array so I can use it to populate the view with some sortable jquery lists. In other words, I have to take a very lengthy object (lessons, from above) and break it into simpler hash arrays.

NOW, here is where I want to chuck my computer out the window:

I need one more sub(sub)state where I can find one object in that new hash.

     .state('dashboard.create.lessons.detail', {
        // parent: 'lessons',
        url: '/{lessonId}',
        views: {
          '[email protected]': {
            templateUrl: "/app/partials/create.detail.html",
            resolve: {
              getData: "curriculumHash"
            },
            controller: ['$scope', '$stateParams', 'getData', function(scope, stateParams, getData){
                getData.sstHash().then(function() {

                  for (var i=0; i<scope.sstopicsArray.length; i++) {
                    var b = a[i];
                    for (var j=0; j<b.length; j++) {
                      if (b[j].Id == stateParams.lessonId)
                        scope.activeItem = b[j];
                    };
                  }
                });
              })
            }],
          }
        }
      })

I have searched high and low for a decent example of how to use resolve. No matter, when I put a stop break in the controller of the dashboard.create.lessons.detail state it says getData is undefined and chrome throws an error because you can't get the length of an undefined object.

Can anyone suggest a tip. I really need this stuff to be in the scope because I want to play with the model. If someone could also just refer me to some more thorough resolve documentation than is on the angular ui site, that could be helpful. Thanks!

Upvotes: 3

Views: 5524

Answers (1)

morgs32
morgs32

Reputation: 1459

What I ended up doing was returning a promise in my curriculumHash service. Then putting a resolve into appStates.js so that the controller won't start up til the promise is resolved.

Like so:

.state('dashboard.create', {
    // parent: 'dashboard',
    url: '/create',
    views: {
      '': {
        templateUrl: "/app/partials/create.html",
        resolve:{
          'curriculumHashPromise':function(curriculumHash){
            return curriculumHash.promise;
          }
        },
        controller: ['$rootScope', function(rootScope){
          //I will have access to all curriculumHash methods as well as dashBoard 
        }],
      }
    },

I referred to this question here to find my answer. Let me know if anyone needs more details, but the reference is incredibly useful.

Upvotes: 3

Related Questions