Angular 1.5 components with ui-router resolve : Unknown provider

Al-Mothafar picture Al-Mothafar · Jul 13, 2016 · Viewed 11.1k times · Source

I'm facing an issue with converting controllers to components preparing my application for Angular 2, but the problem the migration is not going well, I have the ui-router to route between states and using resolve in a few controllers, the version with controller is working but the version of components now working at all, I followed a lot of guides and seems I'm doing good for code but its not working for me.

I have the following module with controller:

(function () {
  'use strict';

  angular
    .module('app.sample', [])
    .config(config);

  /** @ngInject */
  $stateProvider
    .state('app.sample', {
      url    : '/sample',
      views  : {
        'content@app': {
          templateUrl: 'app/main/sample/sample.html',
            controller : 'SampleController as vm'
          }
        },
        resolve: {
          SampleData: function (myService) {
            return myService.getSample(); // I return a promise here
          }
       }
     });
  }
})();

Controller:

(function ()
{
    'use strict';
    angular
        .module('app.sample')
        .controller('SampleController', SampleController);

    /** @ngInject */
    function SampleController(SampleData)
    {
        var vm = this;
        vm.helloText = SampleData.data.helloText;
    }
})();

The above code working well, BUT After making it as a component its become like this:

(function () {
  'use strict';

  angular
    .module('app.sample', [])
    .config(config);

  /** @ngInject */
  function config($stateProvider) {
    // State
    $stateProvider
      .state('app.sample', {
        url: '/sample',
        views: {
          'content@app': {
            template: '<sample></sample>'
          }
        },
        resolve: {
          SampleData: function (myService) {
            return myService.getSample(); // I return a promise here
          }
        }
      });
  }
})();

Component:

(function () {
  'use strict';

  angular
    .module('app.sample')
    .component('sample', {
      templateUrl: 'app/main/sample/sample.html',
      bindings: {
      },
      controller: Sample
    });

  /** @ngInject */
  function Sample(SampleData) {
    var $ctrl = this;
    $ctrl.helloText = SampleData.data.helloText;
  }
})();

But now its not working and gives me the following error:

Error: [$injector:unpr] Unknown provider: SampleDataProvider <- SampleData
http://errors.angularjs.org/1.5.7/$injector/unpr?p0=SampleDataProvider%20%3C-%20SampleData
    at angular.js:68
    at angular.js:4502
    at Object.getService [as get] (angular.js:4655)
    at angular.js:4507
    at getService (angular.js:4655)
    at injectionArgs (angular.js:4679)
    at Object.invoke (angular.js:4701)
    at $controllerInit (angular.js:10234)
    at nodeLinkFn (angular.js:9147)
    at angular.js:9553

My dependencies inside bower.json:

"dependencies": {
    "angular": "1.5.7",
    "angular-animate": "1.5.7",
    "angular-aria": "1.5.7",
    "angular-cookies": "1.5.7",
    "angular-material": "1.1.0-rc.5",
    "angular-messages": "1.5.7",
    "angular-resource": "1.5.7",
    "angular-sanitize": "1.5.7",
    "angular-ui-router": "1.0.0-beta.1",
    "jquery": "2.2.4",
    "mobile-detect": "1.3.2",
    "moment": "2.13.0"
  }

Any idea what the problem, what I'm missing?

Answer

Al-Mothafar picture Al-Mothafar · Jul 13, 2016

Finally solved it, I misunderstood that how the components are working.

First I change SampleData to sampleData, Pascal Case but with first letter small.

Then inside the module i changed the template to template: '<sample sample-data="$resolve.sampleData"></sample>'

and resolve to :

resolve: {
  sampleData: function (msApi) {
    return msApi.resolve('sample@get');
  }
}

And for component I changed the binding as well:

bindings: {
  sampleData: '='
},

And inside the controller of component I removed SampleData from signature and called it like this $ctrl.helloText = $ctrl.sampleData.data.helloText;.

So the final code now is like : For Module:

 (function () {
  'use strict';

  angular
    .module('app.sample', [])
    .config(config);

  /** @ngInject */
  function config($stateProvider) {
    // State
    $stateProvider
      .state('app.sample', {
        url: '/sample',
        views: {
          'content@app': {
            template: '<sample sample-data="$resolve.sampleData"></sample>'
          }
        },
        resolve: {
          sampleData: function (myService) {
            return myService.getSample(); // I return a promise here
          }
        }
      });
  }
})();

And component like this:

(function () {
  'use strict';

  angular
    .module('app.sample')
    .component('sample', {
      templateUrl: 'app/main/sample/sample.html',
      bindings: {
        sampleData: '='
      },
      controller: Sample
    });

  /** @ngInject */
  function Sample() {
    var $ctrl = this;
    $ctrl.helloText = $ctrl.sampleData.data.helloText;
  }
})();

And finally worked.

Edit: P.S.: Outside the question and answer scope, If you use component without state too, you need to get the data inside controller instead of resolve, so you can call components wherever you want.