user884542
user884542

Reputation:

UI Resolve is not injecting into controller (data is undefined)

I've looked at similar questions but I can't seem to understand what I am missing. Basically, I have a service that gets data from the server, and I am trying to get that data into a controller through UI-Router's resolve property. However, after following numerous tutorials and documentations, I can't get the controller to find the data, so to speak. Everything comes up as undefined. I am hoping someone can help me understand what is happening. My code is below.

services.js

myServices.factory('SoundCloudService', ['$http', '$log', '$sce', function($http, $log, $sce) {
    function getPlayerHtml() {
        return $http.get('/get-site-data').then(function(oEmbed) {
            return $sce.trustAsHtml(oEmbed.data.player);
        });
    };

    function getSiteAbout() {
        return $http.get('/get-site-data').then(function(oEmbed) {
            return $sce.trustAsHtml(oEmbed.data.about);
        });
    }

    function getAllTracks() {
        return $http.get('/get-all-tracks').then(function(tracks) {
            return JSON.parse(tracks.data);
        });
    };

    function getAllPlaylists() {
        return $http.get('/get-playlists').then(function(playlists) {
            return JSON.parse(playlists.data);
        })
    };

    function getPlaylist(pid) {
        return $http.post('/get-playlist', pid, $http.defaults.headers.post).then(function(playlist) {
            return playlist.data;
        });
    };

    function getXMostTrendingFrom(x, playlist) {
        var i, trending = [];
        playlist.sort(function(a, b) { return b.playback_count - a.playback_count} );
        for(i=0;i<x;i++) {
            trending.push(all_tracks[i]);
        }
        return trending;
    };

    return {
        getAllTracks: getAllTracks,
        getAllPlaylists: getAllPlaylists,
        getPlayerHtml: getPlayerHtml,
        getSiteAbout: getSiteAbout,
        getXMostTrendingFrom: getXMostTrendingFrom,
        getPlaylist: getPlaylist,
    };
}]);

app.js

myApp.config(['$stateProvider', '$urlRouterProvider', 'ngMetaProvider',
    function($stateProvider, $urlRouterProvider, ngMetaProvider) {
        $urlRouterProvider.otherwise('/');
        $stateProvider
            .state('main', {
                url: '',
                template: '<ui-view/>',
                abstract:true,
                controller: 'MainController',
                resolve: {
                    player: function(SoundCloudService) { return SoundCloudService.getPlayerHtml(); },
                    about: function(SoundCloudService) { return SoundCloudService.getSiteAbout(); },
                }
            })
            .state('main.home', {
                url: '/',
                templateUrl: '../static/partials/home.html',
                controller: 'IndexController',
            })
            .state('main.team', {
                url: '/team',
                templateUrl: '../static/partials/team.html',
                controller: 'TeamController',
            })
            .state('main.contact', {
                url: '/contact',
                templateUrl: '../static/partials/contact.html',
                controller: 'ContactController',
            })
            .state('main.resources', {
                url: '/resources',
                templateUrl: '../static/partials/resources.html',
                controller: 'ResourcesController',
            })
            .state('main.listen-to', {
                url: '/listen-to',
                templateUrl: '../static/partials/listen-to.html',
                controller: 'ListenController',
            })
            .state('main.listen-to.season', {
                url: '/listen-to/:season',
                templateUrl: '../static/partials/listen-to.season.html',
                controller: 'ListenController',
            })
            .state('main.listen-to.season.episode', {
                url: '/listen-to/:season/:episode',
                templateUrl: '../static/partials/listen-to.season.episode.html',
                controller: 'ListenController',
            })
            .state('main.read', {
                url: '/read',
                templateUrl: '../static/partials/read.html',
                controller: 'ReadController',
            })
            .state('main.read.post', {
                url: '/read/:post',
                templateUrl: '../static/partials/read.post.html',
                controller: 'ReadController',
            })
            }
]);

controller.js

myControllers.controller('MainController', ['$scope', '$log', 'PageTitleService',
    function($scope, $log, PageTitleService, player) {
        $log.log(player); /* This is always undefined */
    }
]);

[UPDATE]

As pointed out by Hadi in the answer below, I placed player in the array, and the controller now looks like this:

skodenControllers.controller('MainController', ['$scope', '$log', '$sce', 'PageTitleService', 'player',
    function($scope, $log, $sce, PageTitleService, player) {
        $log.log(player);
    }
]);

The console DOES show the data, but only after an error as such:

Error: [$injector:unpr] http://errors.angularjs.org/1.3.2/$injector/unpr?p0=playerProvider%20%3C-%20player at angular.js:38 at angular.js:3930 at Object.d [as get] (angular.js:4077) at angular.js:3935 at d (angular.js:4077) at Object.e [as invoke] (angular.js:4109) at F.instance (angular.js:8356) at angular.js:7608 at r (angular.js:347) at I (angular.js:7607)

Hopefully someone can lead me in the right direction.

Upvotes: 0

Views: 68

Answers (2)

Stephane Janicaud
Stephane Janicaud

Reputation: 3627

As myServices and myControllers are both modules, ensure you add them as dependencies of myApp module.

// init myApp module
angular.module('myApp', ['myServices', 'myControllers']);

Edit

Some leads :

  • According to the documentation, when using ui-router nested views, child views (state name = main.xxx) must declare the parent state, so you must add parent: "main" or child views won't inherit resolved properties of main state controller

  • As siteDate is loaded asynchronously in SoundCloudService (services.js:23), you cannot be sure it will be available in your controllers which are loaded at the same time. Instead, add a getSiteDate() method to SoundCloudService which returns a promise. siteData is then cached and immediately return by the promise.

For example :

/**
 * @name getSiteData
 * @description Scrap site data
 * @returns {promise} a promise
 */
function getSiteData() {
    var deferred = $q.defer();

    if(siteData) {
        deferred.resolve(siteData);
    }
    else {
        $http.get('/get-site-data').then(function(response) {
            siteData = response.data;
            deferred.resolve(siteData);
        }, function(err) {
            deferred.reject(err.message);
        });
    }

    return deferred.promise;
}
  • Why trying to map SoundCloudService to siteData ? You should simply inject SoundCloudService in controllers that use it :

For example :

skodenControllers.controller('MainController', ['$scope', '$log', '$sce', 'PageTitleService', 'SoundCloudService',
  function($scope, $log, $sce, PageTitleService, SoundCloudService) {

    // Note: getSiteData() could use a cache inside the service
    SoundCloudService.getSiteData().then(function(siteData) {
      ...
    });
  }

Upvotes: 1

Hadi
Hadi

Reputation: 17299

You forgot pass player into array. change to this

  myControllers.controller('MainController', ['$scope', '$log', 
 'PageTitleService','player',
    function($scope, $log, PageTitleService, player) {
    $log.log(player); /* This is always undefined */
   }
]);

Upvotes: 2

Related Questions