When i bundle the js files then resolve statement is not working in angular project. Below is the code
app.js
app.config(["$stateProvider",
"$urlRouterProvider",
function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/");
$stateProvider
.state("home", {
// welcome
url: "/",
templateUrl: "app/views/welcomeView.html"
})
.state("productList", {
// Product List
url: "/products",
templateUrl: "app/views/productListView.html",
controller: "ProductListCtrl as vm"
})
.state("productDetail", {
// Product Details
url: "/products/:productId",
templateUrl: "app/views/productDetailView.html",
controller: "ProductDetailCtrl as vm",
resolve: {
productResource: "productResource",
product: function (productResource, $stateParams) {
var productId = $stateParams.productId;
return productResource.get({ id: productId }, function (data) {
return data;
});
}
}
});
}]
);
productDetailCtrl.js
(function () {
"use strict";
angular
.module("productManagement")
.controller("ProductDetailCtrl",["product",ProductDetailCtrl]
);
function ProductDetailCtrl(product) {
var vm = this;
vm.product = product;
vm.title = "Product Detail: " + vm.product.productName;
}
}());
After login i can see product list perfectly but when I try to see details of product nothing happens not error in console as well. If I comment resolve property and remove product parameter in controller then it works fine. This problem occur only after bundling and minification. If I refer bare files its working fine. Please suggest me where I made mistake.
You can use the same pattern of passing an array with the argument names as strings before the function anywhere angular uses dependency injection.
resolve: {
productResource: "productResource",
product: ["productResource", "$stateParams", function (productResource, $stateParams) {
...
}]
}
Use in-line array annotation for the resolver function:
resolve: {
productResource: "productResource",
//product: function (productResource, $stateParams) {
product: ["productResource", "$stateParams", function (productResource, $stateParams) {
var productId = $stateParams.productId;
return productResource.get({ id: productId }, function (data) {
return data;
}).$promise;
//}
}]
}
For more information, see AngularJS Developer Guide - Dependency Injection -- Inline Array Annotation
Related
First, thanks for your help in advance. I'm a noob to angular though I did search quite a bit trying to resolve this issue. I'm guessing I missed something obvious. I'm using ui-router and using the resolve property to call a resource and can't get it for the life of me to pass the params to the web service.
First, my routes and states:
(function () {
"use strict";
var app = angular.module("MyModule",
["ui.router",
"ngResource",
"common.services"]);
app.config(["$stateProvider", '$urlRouterProvider',
function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/");
$stateProvider.state("home", {
url: "/",
templateUrl: "welcomeView.html"
})
$stateProvider.state("vehicleList", {
url: "/vehicles",
templateUrl: "App/Vehicles/vehicleListView.html",
controller: "VehicleListController as vm"
})
$stateProvider.state("vehicleEdit", {
url: "/vehicles/edit/:vin",
templateUrl: "App/Vehicles/vehicleEditView.html",
controller: "VehicleEditController as vm",
resolve: {
vehicleResource: "vehicleResource",
vehicle: function (vehicleResource, $stateParams) {
var vehicleVIN = $stateParams.vin;
return vehicleResource.get(
{ vin: $stateParams.vin }).$promise;
}
}
})
$stateProvider.state("vehicleDetails", {
url: "/vehicles/:vin",
templateUrl: "App/Vehicles/vehicleDetailsView.html",
controller: "VehicleDetailsController as vm",
resolve: {
vehicleResource: "vehicleResource",
vehicle: function (vehicleResource, $stateParams) {
var vehicleVIN = $stateParams.vin;
return vehicleResource.get(
{ vin: 'T123432342' }).$promise;
}
}
})
}
]);
}());
Note that you see a couple of varieties of passing the vin is as I've tried numerous ways with passing in the variable vehicleVIN, a string, etc. The vehicleVIN variable does assign properly there so injecting $stateParams or passing the vin to it doesn't seem to be the problem.
Here is the resource:
(function () {
"use strict";
angular
.module("common.services")
.factory("vehicleResource",
["$resource",
"appSettings",
vehicleResource]);
function vehicleResource($resource, appSettings) {
return $resource(appSettings.serverPath + "/api/Vehicle/:vin", { vin: '#vin' },
{
'update': { method: 'PUT' },
'details': { method: 'GET' },
'query': { method: 'GET', isArray = true }
});
}
}());
Here is common.services:
(function () {
"use strict";
angular
.module("common.services", ["ngResource"])
.constant("appSettings",
{
serverPath: "http://localhost:8098"
});
}());
And here is the service end of it (Asp.Net WebAPI):
// GET api/Vehicle
[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All, AllowedOrderByProperties = "Name")]
[ResponseType(typeof(IQueryable<IEnumerable<IVehicle>>))]
public IHttpActionResult Get()
{
return ListOfVehicles...blah..blah
}
// GET api/Vehicle/5
[ResponseType(typeof(IQueryable<IVehicle>))]
public IHttpActionResult Get(string vin)
{
return SingleVehicle...blah...blah
}
Every time I execute it, the breakpoint hits Get (without the vin parameter) and when I run fiddler, it looks like it's sending an empty body.
Any ideas on what is going on? Much appreciated!
I am working on an application and I'd like to use the controllerAs syntax to not rely only on $scope. I am using $resource to get data from the API and the problem I encounter is that in the success/error callbacks I can use only $scope, since this is not defined.
Here is some code to better explain the problem.
This is my main module where among other things I configure the router:
angular
.module('app', ['ngRoute', 'ngResource', 'LocalStorageModule', 'app.users', 'app.auth'])
.config(configure)
.controller('MainController', ['$scope', '$location', MainController]);
function configure($routeProvider, localStorageServiceProvider, $resourceProvider) {
// configure the router
$routeProvider
.when('/', {
templateUrl: 'app/homepage.html',
controller: 'MainController',
controllerAs: 'vm',
data: { authRequired: true }
})
.when('/users', {
templateUrl: 'app/users/main.html',
controller: 'UserController',
controllerAs: 'vmu',
data: { authRequired: true }
})
.otherwise({redirectTo: '/'});
}
// the MainController is not relevant here
In the user module I get some info about the users from the API. Here is a simplified example:
angular
.module('app.users', ['ngResource'])
.controller('UserController', ['UserService', UserController])
.factory('UserService', ['$resource', UserService]);
function UserController(UserService) {
this.users = UserService.users.list();
this.getUserInfo = function(userId) {
this.user = UserService.users.single({ id: userId },
function(success) {
// here I'd like to use 'this' but the following line will trigger an error
this.groupRules = UserService.users.rules({ id: success.userGroupId });
// I have to use $scope instead but it is not what I want
// $scope.groupRules = UserService.users.rules({ id: success.userGroupId });
} );
}
}
function UserService($resource) {
var userResource = {};
userResource.users = $resource('https://my.api.com/users/:action',
{},
{
list: { method: 'GET', isArray: true, params: { action: 'list' } }
single: { method: 'GET', params: { action: 'single', id: '#id' } }
rules: { method: 'GET', params: { action: 'getRules', id: '#id' } }
});
return userResource;
}
I'd like to be able to use 'this' in the callback of the $resource, but of course I'll get an error since 'this' is 'undefined' inside the callback.
Using $scope solves the problem, but I need to refactor some code and I'd like to avoid using $scope all the time.
Any workaround? Maybe I should use a different approach?
Thanks in advance for your help and explanations!
You should look into how to use this in javascript and into javascript scopes and closures.
This should work better:
function UserController(UserService) {
var _this = this;
this.users = UserService.users.list();
this.getUserInfo = function(userId) {
_this.user = UserService.users.single({ id: userId },
function(success) {
// here I'd like to use 'this' but the following line will trigger an error
_this.groupRules = UserService.users.rules({ id: success.userGroupId });
} );
}
}
I am confused. For a long time now I have been using stateParams as a means of find out the stateParams inside a templateUrl.
Now I tried to do the same in a resolve and it does not work. In fact nothing happens when I use stateParams.
However by chance I found that I can use $stateParams in the resolve and it works.
Can someone tell me what is the difference and why do I need to use stateParams in the templateUrl and $stateParams in the resolve?
var auth = {
name: 'auth',
url: '/Auth/:content',
templateUrl: function (stateParams) {
var page = 'app/auth/partials/' + stateParams.content + '.html';
return page;
},
controller: function ($scope, authService) {
$scope.aus = authService;
},
resolve:
{
init: function ($stateParams) {
var x = 99;
return true;
}
}
};
I've created working example here, showing that $statePrams are accessible in the resolve
// States
$stateProvider
.state('auth', {
url: "/auth/:content",
templateUrl: 'tpl.html',
controller: 'AuthCtrl',
resolve : {
init : ['$stateParams' , function($stateParams){
return { resolved: true, content: $stateParams.content };
}]
}
})
Controller
.controller('AuthCtrl', ['$scope', 'init', function ($scope, init) {
$scope.init = init;
}])
and this could be the calls
auth/8
auth/xyz
Check it here
I have a state with resolve:
function config($stateProvider, $urlRouterProvider) {
$stateProvider
.state('emails.list', {
url: "/list/:folder/:page",
parent: 'emails',
templateUrl: "views/emails.list.html",
data: { pageTitle: 'Mail Inbox' },
resolve: {
searchResult: ['Emails', function (Emails) {
return 1;
}]
}
});
}
And I have a controller for this state:
function EmailListCtrl($scope, searchResult, $stateParams, $state) {
...
}
angular.module('peachy').controller('EmailListCtrl', EmailListCtrl);
When I try to pass searchResult to controller I get an error [$injector:unpr]. How it can be fixed? (Or may be something wrong in configuration)
Angular version is 1.3.6
My mistake:
I called EmailListCtrl using ng-controller. Right way is setting controller name in state:
function config($stateProvider, $urlRouterProvider) {
$stateProvider
.state('emails.list', {
...
controller: 'EmailListCtrl'
});
}
There is a working plunker. Try to be sure that even EmailListCtrl recives all the needed dependencies properly:
function EmailListCtrl($scope, result, $stateParams, $state) {
$scope.data = { searchResult : result };
};
EmailListCtrl.$inject = ['$scope','searchResult','$stateParams','$state'];
the $inject contains clear definition for angluar IoC ... so I could even use result as param name instead of searchResult
Check it here
This works, but Json is not how I want to retrieve the data:
var states = [
{ name: 'main', url: '/', templateUrl: '/views/main.html', controller: 'MainCtrl' },
{ name: 'login', url: '', templateUrl: '/views/login-form.html', controller: 'LoginCtrl' },
{ name: 'logout', url: '', templateUrl: '', controller: 'LogoutCtrl' },
{
name: 'sales',
url: '',
templateUrl: '/views/sales-data.html',
controller: 'SalesDataCtrl',
resolve: {
user: 'User',
authenticationRequired:
['user', function(user) { user.isAuthenticated(); }]
}
}
];
angular.forEach(states, function (state) {
$stateProvider.state(state.name, state);
});
This does not work in retrieving the data:
app.config(['$locationProvider', '$resourceProvider', '$stateProvider', function ($locationProvider, $resourceProvider, $stateProvider) {
$locationProvider.html5Mode(true);
not working ---> var states = $resource('http://localhost:9669/api/breeze/states').query();
angular.forEach(states, function(state) {
$stateProvider.state(state.name, state);
});
}]);
My question is two-fold:
How does one retrieve remote data inside app.config so as to populate $StateProvider.
I know even when that is acheived, I will have a problem with the return value of
"['user', function(user) { user.isAuthenticated(); }]"
as it will come back as a string and angular will not recognize it as a function.
How can I overcome that issue?
[Side note: the api call does work, the issue is not the api controller.]
Thank you.
[Solution]
Documentation is piece-meal on this matter, but after sewing various posts together I found the answer.
First one must understand that data cannot be populated in the $stateProvider as it is part of app.config because app.config only initializes providers, the actual http service has to be performed in app.run.
Step 1: Declare 2 Globals, ie. $stateProviderRef and $urlRouterProviderRef references before the app.module and pass the actual $stateProvider & $urlRouterProvider references to them in app.config:
(function() {
var id = 'app';
var $stateProviderRef = null;
var $urlRouterProviderRef = null;
......
// Create the module and define its dependencies.
app.config(function($stateProvider, $urlRouterProvider) {
$stateProviderRef = $stateProvider;
$urlRouterProviderRef = $urlRouterProvider;
});
.......
Step 2: Create a Custom Factory Provider:
app.factory('menuItems', function($http) {
return {
all: function() {
return $http({
url: 'http://localhost:XXXX/api/menuitems',
method: 'GET'
});
}
};
});
Step 3: Call the custom provider in app.run:
app.run(['$q', '$rootScope', '$state','$urlRouter', 'menuItems',
function($q, $rootScope, $state, $urlRouter, menuItems) {
breeze.core.extendQ($rootScope, $q);
menuItems.all().success(function (data) {
angular.forEach(data, function (value, key) {
var stateName = 'state_' + value.OrderNum; //<-- custom to me as I have over 300 menu items and did not want to create a stateName field
$stateProviderRef.state(stateName, {url:value.url, templateUrl:value.templateUrl, controller:value.controller });
});
// because $stateProvider does not have a default otherwise
$urlRouterProviderRef.otherwise('/');
});
.....
}
]);