$http and $stateParams in resolve of $stateProvider, Unknown provider error - angularjs

The goal here is to send an http request with the same parameter of the state parameter. This will then display the food types associated with the cuisine type that has been clicked. Is this even theoretically possible?
"Error: [$injector:unpr] Unknown provider: getFoodsProvider <- getFoods <- AppCtrl"
js
var myApp = angular.module('myApp', ['ui.router']);
myApp.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url:'/',
templateUrl: 'partials/home.html',
controller: 'AppCtrl'
})
.state('food', {
url: '/food/:cuisine',
templateUrl: 'partials/food.html',
controller: 'AppCtrl',
resolve: {
getFoods: ['$http', '$stateParams', function($http, $stateParams) {
var url = '/getfoods/' + $stateParams.cuisine;
return $http.get(url).success(function(response) {
return response.data;
})
}]
}
});
$urlRouterProvider.otherwise('/');
});
myApp.controller('AppCtrl', ['$scope', 'getFoods', function ($scope, getFoods) {
$scope.foods= getFoods;
}]);
home
<md-list>
<md-list-item ng-repeat="cuisine in cuisines">
<a ui-sref="food({cuisine:cuisine})">{{cuisine}}</a>
</md-list-item>
</md-list>
food
<md-list>
<md-list-item ng-repeat="food in foods">
<div>{{food}}</div>
</md-list-item>
</md-list>

Your logic seems perfect and it should work. But I think as you're sending ajax request in the resolve and it works asynchronously you need a resolve there. And no need to use the resolve value in controller. Just set the data of the http response in a factory and use the same factory to get the data in the controller.
So try this:
resolve: {
getFoods: ['$http', '$stateParams','$q','foodData' function($http, $stateParams, $q,foodData) {
var url = '/getfoods/' + $stateParams.cuisine,
deferred = $q.defer(),
$http.get(url).success(function(response) {
foodData.setData(response.data);
deferred.resolve();
}).error(function(error){
deferred.reject();
$state.go(some other state);
})
return deferred.promise;
}]
}

On the off-chance that someone needs a solution to the same problem, you should know it was resolved by creating a separate controller for the state with the service (see comment below). The main controller was trying to load the 'getFoods' service when its associated state hadn't been activated yet. No promises necessary. Also, I added .data after the service in the controller.
new controller
var myApp= angular.module('myApp');
myApp.controller('foodCtrl', ['$scope', 'getFoods', function ($scope, getFoods) {
$scope.foods = getFoods.data; //added .data after service
}]);
main js
var myApp = angular.module('myApp', ['ui.router']);
myApp.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url:'/',
templateUrl: 'partials/home.html',
controller: 'AppCtrl'
})
.state('food', {
url: '/food/:cuisine',
templateUrl: 'partials/food.html',
controller: 'foodCtrl', //specify different controller
resolve: {
getFoods: ['$http', '$stateParams', function($http, $stateParams) {
var url = '/getfoods/' + $stateParams.cuisine;
return $http.get(url).success(function(response) {
return response.data;
})
}]
}
});
$urlRouterProvider.otherwise('/');
});

Related

Angularjs Ionic controller error

I am working with IONIC Framework (Angularjs)
I am receiving below error,
463788 error Error: [ng:areq] http://errors.angularjs.org/1.4.3/ng/areq?p0=PaymentCtrl&p1=not%20a%20function%2C%20got%20undefined
at Error (native)
at http://localhost:8100/lib/ionic/js/angular/angular.min.js:6:416
at Sb (http://localhost:8100/lib/ionic/js/angular/angular.min.js:22:18)
at Qa (http://localhost:8100/lib/ionic/js/angular/angular.min.js:22:105)
at http://localhost:8100/lib/ionic/js/angular/angular.min.js:79:497
at I.appendViewElement (http://localhost:8100/lib/ionic/js/ionic-angular.min.js:17:4463)
at Object.O.render (http://localhost:8100/lib/ionic/js/ionic-angular.min.js:16:17590)
at Object.O.init (http://localhost:8100/lib/ionic/js/ionic-angular.min.js:16:16825)
at I.render (http://localhost:8100/lib/ionic/js/ionic-angular.min.js:17:3419)
at I.register (http://localhost:8100/lib/ionic/js/ionic-angular.min.js:17:3150)
Here is my code for controller.
define(['ionic', 'ionicAngular', 'angular',
'ngRoute', 'angularAnimate', 'angularSanitize', 'uiRouter'],
function (ionic, ionicAngular, angular) {
'use strict';
console.log('Payment controller ');
var PaymentCtrl = function ($scope, PaymentSvc,$state, $ionicLoading) {
/*$scope.phoneNumberVerification = function() { $state,$ionicPopup,
console.log('PhoneNumber controller added1 ');
$ionicLoading.hide();
$state.go('tab.eateries');
};*/
// When button is clicked, the popup will be shown...
};
return PaymentCtrl;
});
Serveics.js
define(['ionic', 'ionicAngular', 'angular',
'ngRoute', 'angularAnimate', 'angularSanitize', 'uiRouter'],
function (ionic, ionicAngular, angular) {
'use strict';
//console.log('service modules');
var PaymentSvc = function(){
console.log('serverices call');//var svc = this;
}
return PaymentSvc;
});
// });*/
payment.js
define(['ionic', 'ionicAngular', 'angular',
'./modules/payment/controllers/paymentctrl',
'./modules/payment/services/services',
'ngRoute', 'angularAnimate', 'angularSanitize', 'uiRouter'],
function (ionic, ionicAngular, angular,
paymentCtrl,
paymentSvc) {
'use strict';
console.log('payment.js modules');
var payment = angular.module('payment', ['ionic'])
.controller('PaymentCtrl', paymentCtrl)
.service('PaymentSvc',paymentSvc);
return payment;
});
No need to inject ['angular','ngRoute', 'angularAnimate', 'angularSanitize', 'uiRouter']. Ionic automatically inject angular decencies when you inject ['ionic']
Just write your controller directly
angular.module('starter', ['ionic']).controller('PayCtrl',function ($scope,$state,$ionicLoading,PaymentSvc){
//starter is the app name come from ng-app="starter"
$ionicLoading.show();
$scope.phoneNumberVerification = function(){
console.log('PhoneNumber controller added1');
$ionicLoading.hide();
$state.go('tab.eateries');
};
});
I advise you to organize your javascript project files to in 3 files:
app.js which contains
angular.module('starter', ['ionic', 'starter.controllers','starter.services'])..config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('app', {
url: '/app',
abstract: true,
templateUrl: 'templates/menu.html',
controller: 'AppCtrl'
}).state('app.home', {
url: '/home',
views: {
'tab-home': {
templateUrl: 'templates/home.html',
controller : 'HomeCtrl'
}
}
});
$urlRouterProvider.otherwise('/app/home');
});
controller.js which contains your controllers
angular.module('starter.controllers', []).controller('AppCtrl', function('PayCtrl',function ($scope,$state,$ionicLoading,PaymentSvc){
$ionicLoading.show();
$scope.phoneNumberVerification = function(){
console.log('PhoneNumber controller added1');
$ionicLoading.hide();
$state.go('tab.eateries');
};
});
service.js which contains you connections to server
angular.module('starter.services', []).factory('PaymentSvc',function($http,$q){
});
it is an injection error. for example, if you inject ['a','b','c'] you must have it in your function in the same order and amount: function(a,b,c). in your case, you have more parameters in the injection than the parameters in your controller function.

Pass parameter from Angularjs controller to $stateProvider

This is my Angularjs .config file that opens lead.html page whenever 'tasks' is activated from another html using ui-router.
App
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider){
$stateProvider
.state('tasks', {
templateUrl: {{name}}.html,
controller:"TasksController"
});
}]);
This is my Taskscontroller.js
App
.controller(
"TasksController", [function($scope, $http,$window) {
var self = this;
self.name = 'lead'; // I wanna use this parameter in templateUrl
console.log("In tasks Controller");
}]);
I want to make the templateUrl take parameter from TasksController so that it redirects to relevant page based on the parameter set in TasksController.
Please guide me how to do this.
Thanks
You could try using $stateParams:
App.config(['$stateProvider', '$urlRouterProvider', '$stateParams', function($stateProvider, $urlRouterProvider, $stateParams) {
$stateProvider
.state('tasks', {
params: {
page: null
},
templateUrl: {{$stateParams.page}}.html,
controller: "TasksController"
});
}]);
Then in your controller:
App.controller("TasksController", [function($scope, $http, $window, $stateParams, $state) {
var self = this;
self.$stateParams.page = 'some_url.html';
self.$state.go('tasks');
}]);
Don't forget the injection in the controller too. Haven't tested this but you may need the $state go like this:
self.$state.go('tasks', { page: 'some_url.html' }, { });

$stateParams is empty object

i saw a lot of similar questions at SO, but those solutions not worked for me :(
About my site and app:
backend is wordpress with json api, angular app is on the mysite.lc/catalog/ page.
my controller:
var catalogControllers = angular.module('catalogControllers', []);
catalogControllers.controller('catalogCtrl', ['$scope', '$state', '$stateParams',
function ($scope, $state, $stateParams) {
$log.debug(angular.toJson($stateParams, true));
$http.get(url).success(function(data) {
console.log('data is loaded');
});
}
]);
my routing setup:
var catalogApp = angular.module('catalogApp', ['ui.router', 'ngResource', 'ngSanitize', 'catalogControllers']);
catalogApp.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '?producttype&colors&models',
controller: 'catalogCtrl',
onEnter: function() {
console.log('route entered');
}
});
$urlRouterProvider.otherwise("/");
}]);
So when i go to url like http://mysite.lc/catalog/#/?producttype=4&colors=5,7,9&models=17 console shows
{} from catalogCtrl, then
data is loaded from catalogCtrl $http.get, and only after that
route entered
If i do log it that way (at router config) controller: function($stateParams) { console.log($stateParams); } it doesn't output anything.
I would suggest resolving the $stateParams on its corresponding state on the .config section. Also,if it is your intention, you need to make your url name part of the url property and not just the stateParameters because ui-router doesn't automatically assign 'home' just because you declared it to be the home state. You can also make the parameters optional by declaring the 'params' property and setting everything to null.
var catalogApp = angular.module('catalogApp', ['ui.router','ngResource', 'ngSanitize', 'catalogControllers']);
catalogApp.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
params: {
productType: null,
colors: null,
models: null
}
url: '/home?productType&colors&models',
controller: 'catalogCtrl',
resolve: {
parameters: function($stateParams){
return $stateParams;
}
}
});
$urlRouterProvider.otherwise("/");
}]);
and to view it in the console, I would suggest using $log to preserve the sequence of it (I had this problem before using console.log) and angular.toJson to display the data;
var catalogControllers = angular.module('catalogControllers', []);
catalogControllers.controller('catalogCtrl', ['$scope', 'parameters', '$log'
function ($scope, parameters, $log) {
$log.debug(angular.toJson(parameters, true));
//the 'true' arguments makes the json 'prettyfied'
}
]);
let me know how it goes because it's a bit unorthodox for me to create the app which doesn't start from the root page.
I've found what was the problem, and it's small and easy (as usually :) ).
Actually everything worked fine, but i had some unmentioned $http.get calls in code above, and my logging was before any data has been loaded, so firstly i logged my $stateParams and only after that (after data has been loaded) my "home" state has been achieved.
So solution is to put work with $stateParams into $http.get(..).success() function.
So now my controller looks like
var catalogControllers = angular.module('catalogControllers', []);
catalogControllers.controller('catalogCtrl', ['$scope', '$state', '$stateParams',
function ($scope, $state, $stateParams) {
$http.get(url).success(function(data) {
console.log('data is loaded');
$log.debug(angular.toJson($stateParams, true));
});
}
]);
router:
var catalogApp = angular.module('catalogApp', ['ui.router', 'ngResource', 'ngSanitize', 'catalogControllers']);
catalogApp.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '?producttype&colors&models',
controller: 'catalogCtrl',
onEnter: function() {
console.log('route entered');
}
});
$urlRouterProvider.otherwise("/");
}]);
URL like http://mysite.lc/catalog/#/?producttype=4&colors=5,7,9&models=17 now outputs in console this:
data is loaded from $http.get in controller
route entered from router
{ "producttype": "4", "colors": "5,7,9", "models": "17" } from $stateParams in controller
Please add your comment, because i'm really newbie in angular and will appreciate any opinions on that.

Angular Routing Params issue

I am using a module where I add in my first controller which is taking a service as a dependency. All the service is doing is bringing in some data.
Then I have a show function which I am adding on an anchor element in my view in order to be able to click on the the first name and then get the user's details.
My second controller takes the data from the first controller and then using $routeParams I am trying to show the data on the user view.
Is there something I am doing wrong here?
(function() {
var app = angular.module('test');
app.controller('testCtrl', ['$scope', 'testFactory', '$location', function($scope, testFactory, $location) {
testFactory.getContact().then(function(data) {
$scope.contacts = data.data;
});
$scope.show = function(firstname) {
$location.path('main/' + firstname);
};
}]);
app.controller('userCtrl', ['$scope', '$routeParams', function($scope, $routeParams) {
$scope.user = $scope.contacts[$routeParams.firstname];
}]);
}());
These are the routes
(function() {
var app = angular.module('test', ["ngRoute"]);
app.config(function($routeProvider, $locationProvider) {
$routeProvider
.when("/main", {
templateUrl: "main.html",
controller: "testCtrl"
})
.when("/main/:firstname", {
templateUrl: "contact.html",
controller: "userCtrl"
})
.otherwise({redirectTo:"/main"});
$locationProvider.html5Mode(true);
});
}());
This is the error I am getting in my console:
TypeError: Cannot read property 'any1' of undefined
where any1 is the is the first name.

Changing route with ui-router skipping resolve

I am using ui-router in my angular app.
I define the routing like this:
angular.module('app.product', [])
.config(['$stateProvider', function($stateProvider) {
$stateProvider
.state('product', {
url: '/product/:product_id',
templateUrl: 'partial/product',
controller: 'productCtrl',
resolve: {
product: ['$http', '$stateParams',
function($http, $stateParams) {
return $http.get('/api/product/' + $stateParams.product_id);
}]
}
})
}])
At some point, I manually change the route on the client side using $state.go('product'). Here I already have the product data on the client side so there is no need for an extra $http request.
What is the best way to pass the data in the $state.go call and let ui-router know there is no need to make this request?
Should I build a service to handle this?
Use a service (something like the code below). Just note this is off the top of my head.
.config(['$stateProvider', function($stateProvider) {
$stateProvider
.state('product', {
url: '/product/:product_id',
templateUrl: 'partial/product',
controller: 'productCtrl',
resolve: {
product: ['ProductCache', '$stateParams',
function(ProductCache, $stateParams) {
return ProductCache.getProduct($stateParams.product_id);
}]
}
});
}])
.factory('ProductCache', ['$http', '$q', function($http, $q) {
var cache = [];
return {
getProduct: function(id) {
// return the product if available, otherwise from the api
if(!cache[id]){
return $http.get('/api/product/' + id, function(result){
cache[id] = result.product; // or however your api return is structured
return cache[id];
});
}else{
// use .when() to ensure a promise is returned to the resolve function
return $q.when(cache[id]);
}
}
};
}]);

Resources