Here is my code:
.state("dashboard.userRoles", {
url: "/user/:id/roles",
controller: "userRolesController as vm",
templateUrl: "app/auth/users/user-roles.html",
resolve: {
user: function (userResource, $stateParams) {
return userResource.get({ id: $stateParams.id }).then(function (res) { return res.data; });
},
roles: function($http, $stateParams) {
var url = appSettings.authApiBaseUrl + "api/accounts/users/" + $stateParams.id + "/roles";
return $http.get(url).then(function(res) { return res.data; });
},
loadMyFiles: function($ocLazyLoad) {
return $ocLazyLoad.load({
name: "app",
files: [
"app/auth/users/userRolesController.js"
]
});
}
}
})
If I navigate to dashboard.userRole and look in fiddler, I see the request to get the user resource, but not the roles. If I comment out the user: section, I see the request to get the roles in fiddler. Why can't I resolve both? Should I just be sending the id into the controller and get everything there?
I was trying to avoid gathering data in the controller as it should just be the stitching between the view model stuff and the ui. Maybe that doesn't matter? Thanks in advance.
Edit 1:
Ok, I can change the code to this and see both requests showing in fiddler, and they both return the properly formatted json data:
.state("dashboard.userRoles", {
url: "/user/:id/roles",
controller: "userRolesController as vm",
templateUrl: "app/auth/users/user-roles.html",
resolve: {
user: function (userResource, $stateParams) {
return userResource.get({ id: $stateParams.id }).$promise;
},
roles: function($http, $stateParams) {
var url = appSettings.authApiBaseUrl + "api/accounts/users/" + $stateParams.id + "/roles";
return $http.get(url).then(function(res) { return res.data; }).$promise;
},
loadMyFiles: function($ocLazyLoad) {
return $ocLazyLoad.load({
name: "app",
files: [
"app/auth/users/userRolesController.js"
]
});
}
}
})
However, the roles injected into the controller are always 'undefined'. The user is populated correctly. And the response in fiddler shows the roles that come back, so I'm not sure why they are undefined. Here is the controller code.
"use strict";
angular
.module("app")
.controller("userRolesController", [
"user", "roles", function (user, roles) {
console.log("app.userRolesController.function()");
var vm = this;
vm.user = user;
vm.roles = roles;
}
]);
This angular-ui-router issue/question was helpful. Anyhow, this works!
.state("dashboard.userRoles", {
url: "/user/:id/roles",
controller: "userRolesController as vm",
templateUrl: "app/auth/users/user-roles.html",
resolve: {
user: function (userResource, $stateParams) {
return userResource.get({ id: $stateParams.id });
},
roles: function($http, $stateParams) {
var url = appSettings.authApiBaseUrl + "api/accounts/users/" + $stateParams.id + "/roles";
return $http.get(url);
},
loadMyFiles: function($ocLazyLoad) {
return $ocLazyLoad.load({
name: "app",
files: [
"app/auth/users/userRolesController.js"
]
});
}
}
})
And here is the controller. The .data on roles is important!
angular
.module("app")
.controller("userRolesController", [
"user", "roles", function (user, roles) {
var vm = this;
vm.user = user;
vm.roles = roles.data;
}
]);
Set a breakpoint (or watch) in the Chrome browser (within your angular controller). And inspect $state. I found my answer to be:
$state.$current.locals.globals.employeeslist
Thats pretty weird. Perhaps you could try:
.state("dashboard.userRoles", {
url: "/user/:id/roles",
controller: "userRolesController as vm",
templateUrl: "app/auth/users/user-roles.html",
resolve: {
// put both in one object
data: function (userResource, $stateParams, $http) {
var url = appSettings.authApiBaseUrl + "api/accounts/users/" + $stateParams.id + "/roles";
return {
user: userResource.get({ id: $stateParams.id }).then(function (res) { return res.data; });
roles: $http.get(url).then(function(res) { return res.data; });
}
},
loadMyFiles: function($ocLazyLoad) {
return $ocLazyLoad.load({
name: "app",
files: [
"app/auth/users/userRolesController.js"
]
});
}
}
})
Update:
Solution above doesn't fix the problem. OP has resolved his own issue (See the comments below).
Related
I've been working on some code for a project and have run into a problem with using $stateParams. I am trying to inject a item name into my service through a resolve but it keeps coming up with undefined. I realized I need $stateParams to define it but I can't seem to inject $stateParams into the service. Here is my code and the error, thank you in advance.
Error
Uncaught Error: [$injector:modulerr]
http://errors.angularjs.org/1.6.5/$injector/modulerr?p0=MenuAppX&p1=ReferenceError%3A%20%24stateParams%20is%20not%20defined%0A%20%20%20%20at%20RoutesConfig%20(http%3A%2F%2Flocalhost%3A3000%2Fsrc%2Froutes.js%3A30%3A14)%0A%20%20%20%20at%20Object.invoke%20(http%3A%2F%2Flocalhost%3A3000%2Flib%2Fangular.min.js%3A44%3A357)%0A%20%20%20%20at%20d%20(http%3A%2F%2Flocalhost%3A3000%2Flib%2Fangular.min.js%3A42%3A237)%0A%20%20%20%20at%20http%3A%2F%2Flocalhost%3A3000%2Flib%2Fangular.min.js%3A42%3A376%0A%20%20%20%20at%20p%20(http%3A%2F%2Flocalhost%3A3000%2Flib%2Fangular.min.js%3A8%3A7)%0A%20%20%20%20at%20g%20(http%3A%2F%2Flocalhost%3A3000%2Flib%2Fangular.min.js%3A42%3A138)%0A%20%20%20%20at%20gb%20(http%3A%2F%2Flocalhost%3A3000%2Flib%2Fangular.min.js%3A46%3A251)%0A%20%20%20%20at%20c%20(http%3A%2F%2Flocalhost%3A3000%2Flib%2Fangular.min.js%3A22%3A19)%0A%20%20%20%20at%20Uc%20(http%3A%2F%2Flocalhost%3A3000%2Flib%2Fangular.min.js%3A22%3A332)%0A%20%20%20%20at%20xe%20(http%3A%2F%2Flocalhost%3A3000%2Flib%2Fangular.min.js%3A21%3A1)
at angular.min.js:7
at angular.min.js:43
at p (angular.min.js:8)
at g (angular.min.js:42)
at gb (angular.min.js:46)
at c (angular.min.js:22)
at Uc (angular.min.js:22)
at xe (angular.min.js:21)
at angular.min.js:333
at HTMLDocument.b (angular.min.js:38)
State
.state('items', {
url: '/menuItems/{itemId}',
templateUrl: 'src/MenuApp/template/items.template.html',
params: {$stateParams, itemId: null},
controller: 'itemsXController as itemsX',
resolve: {
itemsResult: ['MenuDataService, $stateParams', function
(MenuDataService, itemId, $stateParams) {
return MenuDataService.getItemsForCategory($stateParams.itemId);
}]
}
})
Service
(function () {
'use strict';
angular.module('data')
.service('MenuDataService', MenuDataService)
.constant('categoryBasePath', "https://davids-
restaurant.herokuapp.com/menu_items.json?category=");
MenuDataService.$inject = ['$http', '$q', '$timeout','categoryBasePath'];
function MenuDataService($http, $q, $timeout, categoryBasePath) {
var service = this;
service.getAllCategory = function() {
var deferred = $q.defer();
var categoriesResult = $http({
method: "GET",
url: ('https://davids-restaurant.herokuapp.com/categories.json'),
});
$timeout(function () {
deferred.resolve(categoriesResult);
}, 800);
return deferred.promise;
}
service.getItemsForCategory = function(itemId) {
var deferred = $q.defer();
console.log(itemId);
var itemsResult = $http({
method: "GET",
url: ('https://davids-restaurant.herokuapp.com/menu_items.json?category=L'),
});
$timeout(function () {
deferred.resolve(itemsResult);
}, 800);
console.log(deferred.promise);
return deferred.promise;
}
};
})();
Template(the one calling the state)
<a ui-sref="items">This Page works</a>
<ol>
<li ng-repeat="item in categoriesX.categories" ui-sref="items({itemId:
categoriesX.categories[$index].short_name})">
{{ categoriesX.categories[$index].name }}
</li>
</ol>
remove itemid from the resolve function
change this
resolve: {
itemsResult: ['MenuDataService, $stateParams', function
(MenuDataService, itemId, $stateParams) {
return MenuDataService.getItemsForCategory($stateParams.itemId);
}]
}
to this
resolve: {
itemsResult: ['MenuDataService, $stateParams', function
(MenuDataService, $stateParams) {
return MenuDataService.getItemsForCategory($stateParams.itemId);
}]
}
.state('items', {
url: '/menuItems/{itemId}',
templateUrl: 'src/MenuApp/template/items.template.html',
params: { itemId: null},
controller: 'itemsXController as itemsX',
resolve: {
itemsResult: ['MenuDataService, $stateParams', function
(MenuDataService, itemId, $stateParams) {
return MenuDataService.getItemsForCategory($stateParams.itemId);
}]
}
})
I have an app where my main state makes a resolve makes an http call and fetches an array.
Then, the child array is supposed to display one object from this array, but it seems that the variables from the controller are defined too early and don't get updated properly, so the child comes out empty.
I've tried it without http call (var array = [array]), and it works fine, but not with the http call.
Any tips on how to fix this?
Here's the controllers:
.controller('appCtrl',['$scope', 'SearchService','fair', function($scope, SearchService, fair){
$scope.data = SearchService;
$scope.datafairs = $scope.data.flatexhibitors;
console.log($scope.datafairs);
}])
.controller('ChildController',['$scope', 'exhibitor', '$filter', function($scope, exhibitor, $filter){
$scope.$watch(function() { return $scope.fair; }, function(newVal) {
$scope.fairs = newVal;
console.log($scope.fairs);
$scope.chosenexhibitor = $filter("filter")($scope.fairs, {'slug':exhibitor}, true);
}, true);
}])
The service:
.factory("SearchService", function($http) {
var service = {
flatexhibitors : [],
datafairs : [],
getAllExhibitors : function (wop) {
var searchindex = wop;
console.log(searchindex);
var url = '../register/backend/databaseconnect/getexhibitors.php';
var config = {
params: {
search: searchindex
},
cache:true
};
$http.get(url, config).then(function (data) {
service.datafairs = data.data.rows;
for (var i in service.datafairs) {
service.flatexhibitors.push(service.datafairs[i].doc);
};
return service.flatexhibitors;
});
}
}
return service;
})
And the states:
.config(function($stateProvider) {
$stateProvider.state('berliner', {
url: '/berlinerliste',
params : {search: 'Berliner 2017'},
resolve: {
fair: function(SearchService, $stateParams) {
return SearchService.getAllExhibitors($stateParams.search);
}
},
views: {
'header': {
templateUrl: 'header.htm'
},
'main':{
templateUrl: 'bl2017.htm',
controller: 'appCtrl'
}
}
})
.state('berliner.exhibitor', {
url: '/{id}',
resolve: {
exhibitor: function($stateParams) {
var slug = $stateParams.id;
return slug;
}
},
views: {
'header': {
templateUrl: 'header.htm'
},
'wop':{
templateUrl: 'exhibitor.htm',
controller: 'ChildController'
}
}
})
})
I've managed to replicate the issue in a Plunkr.
Change the getAllExhibitors to return a promise like below:
getAllExhibitors : function (wop) {
var searchindex = wop;
console.log(searchindex);
var url = '../register/backend/databaseconnect/getexhibitors.php';
var config = {
params: {
search: searchindex
},
cache:true
};
return $http.get(url, config).then(function (data) {
service.datafairs = data.data.rows;
for (var i in service.datafairs) {
service.flatexhibitors.push(service.datafairs[i].doc);
};
return service.flatexhibitors;
});
}
I've been scratching my head over this one for a couple hours now, and after a good amount of searching I haven't found a helpful solution.
As the title state, my dependencies are not being resolved by Angular's route provider. This is the error:
Unknown provider: testServiceProvider <- testService <- testService
My compiled Javascript file (app.js) looks like this:
'use-strict';
var app = angular.module('test-app', ['ngRoute']);
app.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/home.html',
controller: 'HomeController',
resolve: {
testService: function (testService) {
console.log(testService.message);
}
}
})
}]);
app.factory('apiService', ['$http', function ($http) {
function url(endpoint) {
return '/api/v1' + endpoint;
}
return {
user: {
authenticated: function () {
return $http({method: 'GET', url: url('/user/authenticated')});
},
login: function (token) {
return $http({method: 'GET', url: url('/user/login'), cache: false, headers: {
Authorization: 'Basic ' + token
}});
},
logout: function () {
return $http({method: 'GET', url: url('/user/logout')});
},
model: function () {
return $http({method: 'GET', url: url('/user/data')});
}
}
};
}]);
app.factory('testService', function () {
return {
message: 'Hello world'
};
});
app.controller('HomeController', ['$scope', '$http', function ($scope, $http, apiService, testService) {
$scope.user = {
authenticated: false,
error: '',
username: '',
password: ''
};
$scope.login_button = 'Log in';
$scope.isAuthenticated = function () {
return $scope.user.authenticated;
}
$scope.needsAuthentication = function () {
if (!$scope.user.authenticated) {
return true;
}
return false;
}
$scope.logIn = function ($event) {
$event.preventDefault();
$scope.login_button = 'Please wait...';
var token = btoa($scope.user.username + ':' + $scope.user.password);
apiService.user.login(token).then(function (success) {
$scope.user = success.data.user;
$scope.user.authenticated = true;
}, function (error) {
$scope.user.error = 'Please try logging in again.';
$scope.login_button = 'Log in';
});
};
}]);
As far as I can tell, everything should be resolving fine; am I missing or misunderstanding something?
I think the problem in an alias. You use testService as alias for your resolving. $injector could be confused. Try to rename it for example:
resolve: { testData: function (testService) { console.log(testService.message); } }
and rename it in controller as well.
You have to inject the service,
change
From:
app.controller('HomeController', ['$scope', '$http', function ($scope, $http, apiService, testService)
To:
app.controller('HomeController', ['$scope', '$http','apiService','testService' ,function ($scope, $http, apiService, testService)
I'm new in angular/ui-route and firebase.
Do you know if it's possible to resolve firebase data using ui-route ?
I tryed the following states :
.state('contacts', {
abstract: true,
url: '/contacts',
templateUrl: './assets/app/views/contacts/contacts.html',
resolve: {
contacts: ['contacts',
function( contacts){
return contacts.all();
}],
contactsFb: WHAT TO SET ???
},
controller: ['$scope', '$state', 'contacts', 'utils', 'contactsFb',
function ( $scope, $state, contacts, utils, contactsFb) {
// Working Fine but not from firebase
$scope.contacts = contacts;
// Can't make it works... :-(
$scope.contacts = contactsFb;
}]
})
Here is the factory:
.factory('contactsFb', function($firebase) {
var url='https://evet.firebaseio.com/contacts';
return $firebase(new Firebase(url));
})
.factory('contacts', ['$http', function ($http, utils) {
var path = './assets/app/models/contacts.json';
var contacts = $http.get(path).then(function (resp) {
return resp.data.contacts;
});
var factory = {};
factory.all = function () {
return contacts;
};
factory.get = function (id) {
return contacts.then(function(){
return utils.findById(contacts, id);
})
};
return factory;
}])
Can't make it works... :-(
Maybe you can help me ?
Many thanks!
Try something like this:
.state('contacts', {
abstract: true,
url: '/contacts',
templateUrl: './assets/app/views/contacts/contacts.html',
resolve: {
loadContacts: function(contactsFb) {
return contactsFb.promiseToHaveContacts();
}
},
controller: function ($scope, contactsFb) {
$scope.contacts = contactsFb.contacts;
}
})
.factory('contactsFb', function($firebase, $q) {
return {
contacts: null,
promiseToHaveContacts: function() {
var deferred = $q.defer();
if (this.contacts === null) {
this.contacts = $firebase(new Firebase('https://evet.firebaseio.com/contacts'));
this.contacts.$on('loaded', function(loadedData) {
deferred.resolve();
});
}
else {
deferred.resolve();
}
return deferred.promise;
}
};
});
I am having a heck of a time trying to figure out why I'm getting the Unknown provider error in Angular. I've checked every other question I could find on the subject and most suggest an error in dependency injection. However, it doesn't seem to me like I'm forgetting to inject anything. I've been trying to get the resolve property to work like this post by Misko. I'm able to console log out the employee data after it's resolved, but then I get the Unknown provider error, which prevents the data from being shown on the page.
Here is my router:
"use strict";
var app = angular.module('app',[
'employeeServices'
]);
app.config(appRouter);
function appRouter ($routeProvider) {
$routeProvider
.when('/employees/:account_id', {
controller: 'EmployeeCtrl',
templateUrl: 'view/employee/view.html',
resolve: employeeCtrl.resolve
})
.otherwise({ redirectTo: '/' });
}
Here is my controller
var employeeCtrl = app.controller('EmployeeCtrl', [
'$scope',
'employees',
function ($scope, employees) {
$scope.employee = employees;
console.log($scope.employee);
}
]);
employeeCtrl.resolve = {
employees: function (Employee, $q, $route) {
var deferred = $q.defer();
console.log("current params: ", $route.current.params.account_id);
Employee.getOne({ id: $route.current.params.account_id }, function (successData) {
deferred.resolve(successData);
}, function (errorData) {
deferred.reject(errorData);
});
return deferred.promise;
}
};
And my factory:
angular.module('employeeServices', ['ngResource'])
.factory('Employee', ['$resource', function ($resource) {
return $resource('/employees/:id/json',
{
id: '#account_id'
},
{
'save': {
method: 'POST',
isArray: false
},
'update': {
method: 'PUT',
params: {
id: '#account_id'
}
},
'remove': {
method: 'DELETE',
params: {
id: '#account_id'
}
},
'getOne': {
method: 'GET',
params: {
id: '#account_id'
},
isArray: false
},
'query': {
method: 'GET',
params: {
id: '#account_id'
},
isArray: true
}
}
);
}]);
Any suggestions would be so greatly appreciated!
So the problem was that I was setting up the EmployeeCtrl controller through ng-controller inside my partial's view, like so:
<div class="viewPage" ng-controller="EmployeeCtrl">
When using resolve, however, the controller set up must be done through the router in order for it to be available at runtime. I removed the ng-controller="EmployeeCtrl...
<div class="viewPage">
... and presto, like nothing ever happened.
I have to note that I received help from the kind, patient folks over on the AngularJS IRC channel...
Since you defined the factory called Employee, you should use the exact name to refer to this module when you inject it to the controller.
var employeeCtrl = app.controller('EmployeeCtrl', [
'$scope',
'employees',
Change to
var employeeCtrl = app.controller('EmployeeCtrl', [
'$scope',
'Employee',