Angular route resolve not passing to controller - angularjs

For some reason whatever i do i cannot get my data to the controller no matter what i do, i keep getting this error
Error: [$injector:unpr] Unknown provider: initDataProvider <- initData <- PackingScanController
first file
var Application = angular.module('ReporterApplication', ['ngRoute']);
Application.config(['$routeProvider', '$interpolateProvider',
function($routeProvider, $interpolateProvider) {
$interpolateProvider.startSymbol('<%');
$interpolateProvider.endSymbol('%>');
$routeProvider
.when('/packing/scan.html', {
controller: 'PackingScanController',
templateUrl: 'packing/scan.html',
resolve: {
initData : function () {
return "shite";
}
}
}) etc more code
second file
Application.controller('PackingScanController', ['$scope', '$http', 'initData', function($scope, $http, initData) {
var packer = this;
$scope.packedToday = initData;

The posted code is all right, you are injecting initData properly with resolve route block. However you are probably using explicit ngController in you route template. You don't want it, and of course in this case there is no initData service available which results in error you are getting.
Solution is simple: just remove
ng-controller="PackingScanController"
from your packing/scan.html template and it will work fine.
Explicit controller binding is not needed in this case since template is already bound properly to controller instance created behind the scene by $route service, with all necessary dependencies properly injected.

Related

angular ui bootstrap: Error: [$injector:unpr] Unknown provider: appMainProvider <- appMain

I m currently trying to open an AngularUI Bootstrap Modal. Somehow, I keep getting the following error:
Error: [$injector:unpr] Unknown provider: appMainProvider <- appMain
I search online and found several "solution" but none of them seem to work (or perhaps i m doing something wrong). One of the solution i found is this one.
This is my main js controller:
module.exports = function(appMain, name) {
appMain.controller(name, mainCtrl);
mainCtrl.$inject = ['$state', 'mainDataService', 'dnnVariables', '$uibModal'];
function mainCtrl($state, mainDataService, dnnVariables, $uibModal) {
var vm = this;
function fullAnswer() {
var source = require("../ViewAnswer/viewAnswer.html");
$uibModal.open({
templateUrl: source,
controller: require("../ViewAnswer/viewAnswer.controller.js"),
controllerAs: 'viewAnswerCtrl',
backdrop: 'static'
});
}
}
}
This opens the modal. The modal html is as following (barely anything for testing purpose)
something
The modal js controller is as following:
module.exports = function (appMain, name) {
appMain.controller(name, viewAnswerCtrl);
viewAnswerCtrl.$inject = ['$state', 'mainDataService', 'dnnVariables', "$uibModalInstance"];
function viewAnswerCtrl($state, mainDataService, dnnVariables, $uibModalInstance) {
var vm = this;
}
}
Note: I'm using angular-ui-bootstrap 2.5.
In this example mainCtrl is not controller function but some wrapper function that defines a controller. It is likely supposed to be used as:
mainCtrl(appMain, name);
instead of
appMain.controller(name, mainCtrl);
There's no benefit in wrapping controllers in module.exports = function (appMain, name) {...}. It should be preferably omitted, and angular.module(...) should be used instead of appMain variable.

Angular-JS strict-DI doesn't like injecting resolved results from $routeProvider

I hit some problems minifying my Angular code so I turned on ng-strict-di
One problem seems to reside in the way I resolve a promise on a route in my app.js config
.when('/:userId', {
templateUrl: 'views/main.html',
controller: 'MyCtrl',
resolve : {
myDependency : function(Cache, Model, $route){
return Cache.getCached( $route.current.params.userId);
}
}
})
Then I inject this resolved promise into the MyCtrl controller
angular.module('myApp')
.controller('MyCtrl',[ 'myDependency', '$scope', '$rootScope', '$timeout', function (myDependency, $scope, $rootScope, $timeout) {
etc...
However I get an error from Angular
[Error] Error: [$injector:strictdi] myDependency is not using explicit annotation and cannot be invoked in strict mode
The problem appears to be traceable to the resolve definition in app.js because I can change the name of 'myDependency' there in the resolve and the error message uses the name from there rather than the name of the dependency in myCtrl. And I am explicitly listing the name of the dependency in the myCtrl controller. The app works, but I cannot minify this code because of the problem with this error.
Follow strict-di for resolve as well. Hope this works!
resolve : {
myDependency : ['Cache', 'Model', '$route', function(Cache, Model, $route){
return Cache.getCached( $route.current.params.userId);
}
]}
I catched the same problem and #Mahesh Sapkal solution was right.
But if look at this in details then my problem was that ng-annotate does not detect correctly that function must be annotated. So I added /#ngInject/ comment and it works now!
app.config(/*#ngInject*/function ($routeProvider) {
$routeProvider
.when('/tables', {
template: templateList,
controller: 'TableListController',
resolve: {
initial: /*#ngInject*/function (tableListControllerInitial) {
return tableListControllerInitial();
}
}
})

Angular initializing data in $routeProvider using resolve

I have a AngularJS application and have a requirement to initialize data from a REST API before the controller initializes. I use the "resolve" in the routeProvider and also injected the relevant value in the controller in order to make this data available. The code snippets are as follows:
RouteProvider code snippet:
myApp.config(function($routeProvider) {
$routeProvider
....
.when('/account', {
templateUrl : path + 'admin/js/pages/inputs/account.html',
controller : 'mainController',
resolve: {
data: function() {
return $http.get(api_path + 'dashboard/get_accounts');
}
}
})
myApp.controller('mainController', function($scope,$http, data, $routeParams, DataService) {
...
console.log(data);
}
The console is supposed display the data by I get the following error " Error: [$injector:unpr] Unknown provider: dataProvider <- data "
Your help much appreciated.
It's because the data provider has not instantiated yet and it is instantiating the controller before the provider is ready, coming through as an undefined and unknown provider.
Try something like this that returns a promise:
myApp.config(function($routeProvider, $q) {
$routeProvider, $q
....
.when('/account', {
templateUrl : path + 'admin/js/pages/inputs/account.html',
controller : 'mainController',
resolve: {
data: function() {
return $q.all($http.get(api_path + 'dashboard/get_accounts'));
}
}
})
Now, the controller won't instantiate until the promise has resolved completely. As per the documentation for $routeProvider and how it handles promises in the resolve.
$routeProvider on Angular's website
resolve - {Object.=} - An optional map of dependencies which should be injected into the controller. If any of these dependencies are promises, the router will wait for them all to be resolved or one to be rejected before the controller is instantiated. If all the promises are resolved successfully, the values of the resolved promises are injected and $routeChangeSuccess event is fired. If any of the promises are rejected the $routeChangeError event is fired.

AngularJS Dynamic loading a controller

I read a lot about lazzy loading, but I am facing a problem when using $routeProvider.
My goal is to load a javascript file which contains a controller and add a route to this controller which has been loaded previously.
Content of my javascript file to load
angular.module('demoApp.modules').controller('MouseTestCtrlA', ['$scope', function ($scope) {
console.log("MouseTestCtrlA");
$scope.name = "MouseTestCtrlA";
}]);
This file is not included when angular bootstap is called. It means, I have to load the file and create a route to this controller.
First, I started writing a resolve function which has to load the Javascript file. But declaring my controller parameter in route declaration gave me an error :
'MouseTestCtrlA' is not a function, got undefined
Here is the call I am trying to set :
demoApp.routeProvider.when(module.action, {templateUrl: module.template, controller: module.controller, resolve : {deps: function() /*load JS file*/} });
From what I read, the controller parameter should be a registered controller
controller – {(string|function()=} – Controller fn that should be associated with newly created scope or the name of a registered controller if passed as a string.
So I write a factory which should be able to load my file and then (promise style!) I whould try to declare a new route.
It gave me something like below where dependencies is an array of javascript files' paths to load :
Usage
ScriptLoader.load(module.dependencies).then(function () {
demoApp.routeProvider.when(module.action, {templateUrl: 'my-template', controller: module.controller});
});
Script loader
angular.module('demoApp.services').factory('ScriptLoader', ['$q', '$rootScope', function ($q, $rootScope) {
return {
load: function (dependencies)
{
var deferred = $q.defer();
require(dependencies, function () {
$rootScope.$apply(function () {
deferred.resolve();
});
});
return deferred.promise;
}
}
}]);
Problem
I still have this javascript error "'MouseTestCtrlA' is not a function, got undefined" which means Angular could not resolved 'MouseTestCtrlA' as a registered controller.
Can anyone help me on this point please ?
Re-reading this article http://ify.io/lazy-loading-in-angularjs/ suggested to keep a $contentProvider instance inside Angular App.
I came up with this code in my app.js
demoApp.config(function ($controllerProvider) {
demoApp.controller = $controllerProvider.register;
});
It enables me to write my controller as expected in a external javascript file :
angular.module("demoApp").controller('MouseTestCtrlA', fn);
Hope this can help !

Injection of angularFireCollection into angular.js config for usage in resolve

I've been experimenting a little with Angular.js lately. As part of this I created a very simple set of controllers with an ng-view and templates to trigger depending on the route requested. I'm using angularFireCollection just to grab an array from Firebase. This works fine in the thumbnailController which does not form part of the ng-view.
My problem is that in addition to the data flowing into the thumbnailController, I also need the two other controllers to be able to access the data. I initially simply set the data to either be part of $rootScope or to have the ng-view as a child of the div in which the thumbnailController is set.
However, the issue from that perspective is that each sub-controller presumably attempts to set the data in the template before it is actually available from Firebase.
The solution appears to be using resolve as per the answer to this question angularFire route resolution. However, using the below code (and also referencing angularFireCollection) I get an error message of angularFire being an unknown provider. My understanding is the code below should be sufficient, and I would also add that the usage of angularFireCollection in thumbnailController works fine as I say.
I also experimented with injecting angularFire/aFCollection directly into the controllers using .$inject however a similar issue arose in terms of it being considered an unknown provider.
If possible could someone advise on what the issue may be here?
var galleryModule = angular.module('galleryModule', ['firebase']);
galleryModule.config(['$routeProvider', 'angularFire', function($routeProvider, angularFire){
$routeProvider.
when('/', {
controller: initialController,
templateUrl: 'largeimagetemplate.html',
resolve: {images: angularFire('https://mbg.firebaseio.com/images')}
}).
when('/view/:id', {
controller: mainimageController,
templateUrl: 'largeimagetemplate.html',
resolve: {images: angularFire('https://mbg.firebaseio.com/images')}
}).
otherwise({
redirectTo: '/'
});
}]);
galleryModule.controller('thumbnailController', ['$scope', 'angularFireCollection', function($scope, angularFireCollection){
var url = 'https://mbg.firebaseio.com/images';
$scope.images = angularFireCollection(url);
}]);
function initialController($scope,images){
$scope.largeurl = images[0].largeurl;
}
function mainimageController($scope, images, $routeParams){
$scope.largeurl = images[$routeParams.id].largeurl;
}
I got the chance to dig into this a little bit - it seems like regular services cannot be used in .config sections. I'd instantiate angularFire in the controller instead of using resolve, for example:
galleryModule
.value("url", "https://mbg.firebaseio.com/images")
.controller('thumbnailController', ['$scope', 'angularFireCollection', 'url',
function($scope, angularFireCollection, url) {
$scope.images = angularFireCollection(url);
}])
.controller('initialController', ['$scope', 'angularFire', 'url',
function($scope, angularFire, url) {
angularFire(url, $scope, 'images').then(function() {
$scope.largeurl = $scope.images[0].largeurl;
});
}])
.controller('mainimageController', ['$scope', 'angularFire', '$routeParams', 'url',
function($scope, angularFire, $routeParams, url){
angularFire(url, $scope, 'images').then(function() {
$scope.largeurl = $scope.images[$routeParams.id].largeurl;
});
}]);
This is not ineffecient, since the data is only loaded once from the URL by Firebase, and all subsequent promises will be resolved almost immediately with data already at hand.
I would like to see angularFire work with resolve in the $routeProvider, however. You can use this method as a workaround until we figure out a more elegant solution.

Resources