johnpapa / generator-hottowel

Yo generator that creates an Angular app via HotTowel
835 stars 230 forks source link

Error with resolve in ui-router, using preconfigured router #150

Closed kunzai closed 8 years ago

kunzai commented 8 years ago

Hi

Im trying to access a function from a resolve, configured in ui-router. When "resolved", the dataservice is "undefined" in dataPrepService. Im not sure if this is due to a misconfiguration of mine or a problem of the config of router.

The code I`m using:

dashboard.route.js: `(function () { "use strict";

angular
    .module('app.dashboard')
    .run(appRun);

appRun.$inject = ['routerHelper', "dataservice"];
/* @ngInject */
function appRun(routerHelper, dataservice) {
    routerHelper.configureStates(getStates());
}

function getStates() {
    return [{
        state: 'app',
        config: {
            resolve: {
                dataPrepService: dataPrepService
            },
            url: '/',
            views: {
                "header": {
                    templateUrl: "app/layout/header.html"
                },
                "sidebar": {
                    templateUrl: "app/layout/sidebar.html",
                    controller: "CountriesController",
                    controllerAs: "vm",
                },
                //more views
            }
        }

    }];
}

dataPrepService.$inject = ["dataservice"];
function dataPrepService(dataservice) {
    return dataservice.retrieveData();
}

})(); countries.controller.js (function () { 'use strict';

angular
    .module('app.layout')
    .controller('CountriesController', CountriesController);

CountriesController.$inject = ["$scope", "$state", "logger", "$translate", "serv", "dataservice", "pageservice"];

/* @ngInject */
function CountriesController($scope, $state, logger, $translate, serv, dataservice, pageservice) {
    /* jshint validthis: true */
    var vm = this;
    activate();

    function activate() {
        $state.$current.resolve.dataPrepService().then(function () {
        // compute the data....

        });
    }

`

The error message in Console is: Error: [cofog Error] Cannot read property 'retrieveCofogData' of undefined TypeError: Cannot read property 'retrieveCofogData' of undefined at Object.dataPrepService (http://localhost:8080/app/dashboard/dashboard.route.js:56:27) at activate (http://localhost:8080/app/layout/countries.controller.js:43:37) at new CountriesController (http://localhost:8080/app/layout/countries.controller.js:38:9) at invoke (http://localhost:8080/bower_components/angular/angular.js:4523:17) at Object.instantiate (http://localhost:8080/bower_components/angular/angular.js:4531:27) at http://localhost:8080/bower_components/angular/angular.js:9197:28 at http://localhost:8080/bower_components/angular-ui-router/release/angular-ui-router.js:4018:28 at invokeLinkFn (http://localhost:8080/bower_components/angular/angular.js:8841:9) at nodeLinkFn (http://localhost:8080/bower_components/angular/angular.js:8335:11) at compositeLinkFn (http://localhost:8080/bower_components/angular/angular.js:7731:13) <div ui-view="sidebar" style="float:left;" class="ng-scope">

If more information is needed, I`m happy to provide those.

Thanks in advance.

plwade commented 8 years ago

@kunzai Hello, Try injecting 'dataPrepService' into your controller instead of dataservice. The purpose of the resolve is to complete any code and promises before the controller code is executed. The return dataservice.retrieveData() statement on you resolve will make the data results available to your controller, providing you inject 'dataPrepService' into the controller.

You should be able remove $state.$current.resolve.dataPrepService().then(function () from your controllers activate and just use dataPrepService. You don't even need to handle the promise in the controller, as this will already have been handled by your 'resolve'.

You may want to replace you resolve code with something like this:-

dataPrepService.$inject = ["dataservice"]; function dataPrepService(dataservice) { return dataservice.retrieveData().then(function (response) { return response; } }

Hope this helps.

Kind Regards, Paul

kunzai commented 8 years ago

Hi Paul,

thanks for your answer. If you look at the controller, I don't use dataservice in there. I'm trying to use the dataPrepService, dataservice is just there for testing purpose. Sorry, for that.

What I don't understand is, that dataPrepService is injected into the controller. All Examples that I've seen and also the styleguide by John suggest to do it, like I did. But, when I do so, dataPrepService is "undefined". If I use the $state Object I finally have access to the resolve, but, when all dependencies are resolved in the route resolver and the dataPrepService in the route has no longer access to the dataservice(=undefined)!

@johnpapa Could you provide me an example how to use the dataPrepService, with your hottowel spa? As I used this as a starting point and wanted to keep those "blocks"? Something like you did in your styleguide (https://github.com/johnpapa/angular-styleguide#style-y081), but this time for ui-route?

Thank you very much in advance, kunZai

plwade commented 8 years ago

@kunzai Hi, I think you need to use this code in your resolve:-

dataPrepService.$inject = ["dataservice"]; function dataPrepService(dataservice) { return dataservice.retrieveData().then(function (response) { return response; } }

This will make sure the dataservice.retrieveData() promise has completed before your controller is activated.

The 'return response;' is the key to solving the problem. This means the promise has to finish before the resolve is complete. I think this explains why you are getting undefined in your controller.

Hope this helps. Regards, Paul

kunzai commented 8 years ago

@plwade Thanks again for your effort and time. Actually I found the problem and the cause of the undefined dataservice / dataPrepService.

I had ngRoute included in the html, but somehow I haven't had it injected in my setup =(

After injecting, it worked as it should.

Best regards