Related
Right now i am making an AngularJS+UI router install application. But i have a problem, the problem is, that i want to disable access to the views, associated with the install application. I want to do it in resolve in the state config.
But the problem is i need to get the data from a RESTful API, whether the application is installed or not. I tried making the function, but it loaded the state before the $http.get request was finished.
Here was my code for the resolve function:
(function() {
var app = angular.module('states', []);
app.run(['$rootScope', '$http', function($rootScope, $http) {
$rootScope.$on('$stateChangeStart', function() {
$http.get('/api/v1/getSetupStatus').success(function(res) {
$rootScope.setupdb = res.db_setup;
$rootScope.setupuser = res.user_setup;
});
});
}]);
app.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/404");
$stateProvider.state('db-install', {
url: "/install/db",
templateUrl: 'admin/js/partials/db-install.html',
controller: 'DBController',
resolve: {
data: function($q, $state, $timeout, $rootScope) {
var setupStatus = $rootScope.setupdb;
var deferred = $q.defer();
$timeout(function() {
if (setupStatus === true) {
$state.go('setup-done');
deferred.reject();
} else {
deferred.resolve();
}
});
return deferred.promise;
}
}
})
.state('user-registration', {
url: "/install/user-registration",
templateUrl: "admin/js/partials/user-registration.html",
controller: "RegisterController"
})
.state('setup-done', {
url: "/install/setup-done",
templateUrl: "admin/js/partials/setup-done.html"
})
.state('404', {
url: "/404",
templateUrl: "admin/js/partials/404.html"
});
}]);
})();
EDIT:
Here is what my ajax call returns:
Try this way:
$stateProvider.state('db-install', {
url: "/install/db",
templateUrl: 'admin/js/partials/db-install.html',
controller: 'DBController',
resolve: {
setupStatus: function($q, $state, $http) {
return $http.get('/api/v1/getSetupStatus').then(function(res) {
if (res.db_setup === true) {
$state.go('setup-done');
return $q.reject();
}
return res;
});
}
}
})
Then inject setupStatus in controller:
.state('setup-done', {
url: "/install/setup-done",
templateUrl: "admin/js/partials/setup-done.html",
controller: ['$scope', 'setupStatus', function ($scope, setupStatus) {
$scope.setupdb = setupStatus.db_setup;
$scope.setupuser = setupStatus.user_setup;
}]
})
I want to make my views show only after the initial data is fetched and i am trying to accomplish this with a route resolve, but i can't get it to work. What am i doing wrong? Also my angular skills are a bit shabby so i aplogize in advance if my question is dumb.
Application.js :
var Application = angular.module('ReporterApplication', ['ngRoute']);
Application.config(['$routeProvider', '$interpolateProvider',
function($routeProvider, $interpolateProvider) {
$interpolateProvider.startSymbol('<%');
$interpolateProvider.endSymbol('%>');
$routeProvider
.when('/packing/scan.html', {
templateUrl: 'packing/scan.html',
controller: 'PackingScanController',
resolve: {
initData : Application.PackingScanInit()
}
})
.when('/packing/stats.html', {
templateUrl: 'packing/stats.html',
controller: 'PackingStatisticsController'
})
etc
and here is my Scan.js file :
Application.PackingScanInit = function ($q,$timeout,$http) {
var serverData = "";
$http.get('/packing/scan.action')
.success(function(data){
serverData = data;
})
.error(function(data){
serverData = data;
});
return serverData;
}
Application.controller('PackingScanController', ['initData', '$scope', '$http', function(initData, $scope, $http) {
var packer = this;
// Message log model
packer.messageLog = [{
status : "",
message : null
}];
the files are included in this order.
service are singletons means there are initialized only one but time but if you simply return from service it will be called one time but if you return a function from service it will be called again and again .See Below Sample for working.
var app = angular.module('ajay.singhApp', [])
.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/view1', {
templateUrl: 'views/main.html',
controller: 'MainCtrl',
resolve: {
myVar: function (repoService) {
return repoService.getItems().then(function (response) {
return response.data;
});
}
}
})
.when('/view2', {
templateUrl: 'views/main.html',
controller: 'MainCtrl'
})
.otherwise({
redirectTo: '/view1'
});
}]);
app.factory('repoService', function ($http) {
return {
getItems: function () {
return $http.get('TextFile.txt');
}
};
});
Try this:
Application.PackingScanInit = function ($q,$timeout,$http) {
return $http.get('/packing/scan.action')
.success(function(data){
return data;
})
.error(function(data){
return data;
});
}
Also you have to adjust your resolve to this:
resolve: {
initData : Application.PackingScanInit
}
Here is a specific working example:
(function() {
angular.module('app',['ngRoute']);
function TestCtrl($scope, initData) {
$scope.value = initData;
}
angular.module('app').config(function($routeProvider) {
$routeProvider.otherwise({
template: '`<p>Dude {{value}}</p>`',
controller: TestCtrl,
resolve: {
initData: function($http) {
return $http.get('test.json') //change to test-e.json to test error case
.then(function(resp) {
return resp.data.value; //success response
}, function() {
return 'Not Found'; // error response
});
}
}
});
});
})();
http://plnkr.co/edit/SPR3jLshcpafrALr4qZN?p=preview
I am trying to populate my model from backend(with label and messages) before my contoller get loads. My method is working fine it connects with backend and gets the data but when I am viewing that variable in controller it is coming as undefined. My variable is "Model"
This is my route file
mainApp
.config(["$routeProvider", function ($routeProvider) {
.when(AngularRoutesFactory.AIMSAdmin.SearchBookings, {
templateUrl: aimsAdminViewBase + "Bookings/SearchBookings.html",
controller: "SearchPerioperativeBookingController",
resolve: {
"Model": function (BookingFactory) {
return BookingFactory.GetSearchModel();
}
},
requireAIMSAuthorizeUser: true
})
.otherwise({
redirectTo: AngularRoutesFactory.MainApp.BaseUrl
});
}]);
My Factory is
mainApp.factory("BookingFactory", ["$location", "MainFactory",
function ($location, MainFactory) {
bookingsFactory.GetSearchModel = function () {
bookingsFactory.MainFactory.QueryAPI(apiEndpoint + "GetSearchModel", "GET", function (response) {
bookingsFactory.SearchBookingCriteria = response;
return bookingsFactory.SearchBookingCriteria;
}, null, null, bookingsFactory.LangInfo.Message_GettingBookingModel);
}
return bookingsFactory;
}]);
And this is my controller
mainApp.controller("SearchBookingController", ["$scope", "BookingFactory", "$rootScope", "$location"
, function ($scope, BookingFactory, $rootScope, $location, Model) {
$scope.bbb = Model;
}]);
Edit:
Try handling it this way:
mainApp.config(["$routeProvider", "$q", function ($routeProvider, $q) {
.when(AngularRoutesFactory.AIMSAdmin.SearchBookings, {
templateUrl: aimsAdminViewBase + "Bookings/SearchBookings.html",
controller: "SearchPerioperativeBookingController",
resolve: {
Model: function (BookingFactory, $q) {
var deferred = $q.defer();
BookingFactory.GetSearchModel().then(
function (data) {
deferred.resolve(data);
}, function () {
deferred.reject();
}
);
return deferred.promise;
}
},
requireAIMSAuthorizeUser: true
})
.otherwise({
redirectTo: AngularRoutesFactory.MainApp.BaseUrl
});
}]);
Took guidance from #Fedaykin and came up with following working solution. Please let me know if it is wrong
I just changed my factory method and resolve function by applying $q.defer method and got it working
Changed my factory GetSearchModel method with following code
bookingsFactory.GetSearchModel = function () {
bookingsFactory.MainFactory.QueryAPI(apiEndpoint + "GetSearchModel", "GET", function (response) {
deferred.resolve(response);
}, null, null, bookingsFactory.LangInfo.Message_GettingBookingModel);
return deferred.promise;
}
What I did in route file
var bookingModel= function ($q, BookingFactory) {
var deferred = $q.defer();
BookingFactory.GetSearchModel().then(
function (data) {
deferred.resolve(data);
}, function () {
deferred.reject();
}
);
return deferred.promise;
};
bookingModel.$inject = ["$q", "BookingFactory"];
Then in resolve all I did
.when(AngularRoutesFactory.AIMSAdmin.SearchBookings, {
templateUrl: aimsAdminViewBase + "Bookings/SearchBookings.html",
controller: "SearchBookingController",
resolve: {
"Model": bookingModel
},
requireAIMSAuthorizeUser: true
})
And in controller voila I got the value
mainApp.controller("SearchBookingController", ["$scope", "InitializeMainFactory", "$rootScope", "$location", "Model"
, function ($scope, InitializeMainFactory, $rootScope, $location, Model) {
$scope.Model = Model;
}]);
seems like $stateParams is not working.
passing date like this:
$state.go('state2', { someParam : 'broken magic' });
params being ignored on the target state
console.log('state2 params:', $stateParams); // return empty object {}
code:
var app = angular.module('app', [
'ui.router'
]);
app.config(function($stateProvider) {
$stateProvider
.state('state1', {
url: '',
templateUrl: 'state-1.html',
controller : function ($scope, $state, $stateParams) {
$scope.go = function () {
$state.go('state2', { someParam : 'broken magic' });
};
console.log('state1 params:', $stateParams);
}
})
.state('state2', {
url: 'state2',
templateUrl: 'state-2.html',
controller : function ($scope, $state, $stateParams) {
$scope.go = function () {
$state.go('state1', { someOtherParam : 'lazy lizard' });
};
console.log('state2 params:', $stateParams);
}
});
});
Live example can be found here
thank you.
You can't pass arbitrary parameters between states, you need to have them defined as part of your $stateProvider definition. E.g.
$stateProvider
.state('contacts.detail', {
url: "/contacts/:contactId",
templateUrl: 'contacts.detail.html',
controller: function ($stateParams) {
console.log($stateParams);
}
}) ...
The above will output an object with the contactId property defined. If you go to /contacts/42, your $stateParams will be {contactId: 42}.
See the documentation for UI-Router URL Routing for more information.
if you don't want to define your parameter in the url, you must include a params property on the state you are transitioning to. Otherwise the data will be removed from the $stateParams object. The format of the params object is an array of strings in older versions of angular-ui-router; in newer versions it is an object of empty objects:
params: { id: {}, blue: {}}
See this example:
$stateProvider.state('state1', {
url: '',
params: {
id: 0,
blue: ''
},
templateUrl: 'state-1.html',
controller: function($scope, $state, $stateParams) {
$scope.go = function() {
$state.go('state2', {
id: 5,
blue: '#0000FF'
});
};
console.log('state params:', $stateParams);
}
});
Related question:
Parameters for states without URLs in ui-router for AngularJS
Just passing parameters to a state is not enough. You have to define the parameter explicitly by name in the url property of your state.
If you don't do this, ui-router won't know this state is expecting a parameter and the $stateParams object will not be populated like you want.
Here is an example of how you might modify your state to expect a parameter, inject $stateParams, and do something with said parameter:
$stateProvider.state('state1', {
url: '',
templateUrl: 'state-1.html',
controller : function ($scope, $state, $stateParams) {
$scope.params = $stateParams;
$scope.go = function () {
$state.go('state2', { id : 'broken magic' });
};
console.log('state1 params:', $stateParams);
}
})
.state('state2', {
url: 'state2/:id',
templateUrl: 'state-2.html',
controller : function ($scope, $state, $stateParams) {
$scope.params = $stateParams;
$scope.go = function () {
$state.go('state1', { someOtherParam : 'lazy lizard' });
};
console.log('state2 params:', $stateParams);
}
})
Here is a working example of passing state params on jsfiddle.
the solutions above works but for my case I needed to pass query parameter so I dit it like this:
$stateProvider
.state('state1', {
url: '/state1?other',
templateUrl: 'state-1.html',
controller : function ($scope, $state, $stateParams) {
$scope.params = $stateParams;
$scope.go = function () {
$state.go('state2', { someParam : 'broken magic' });
};
console.log('state1 params:', $stateParams);
}
})
.state('state2', {
url: '/state2?someParam',
templateUrl: 'state-2.html',
controller : function ($scope, $state, $stateParams) {
$scope.params = $stateParams;
$scope.go = function () {
$state.go('state1', { other : 'lazy lizard' });
};
console.log('state2 params:', $stateParams);
}
});
Make a transport and use it!
angular_app.factory('$$transport', function($q) {
var transport;
return transport = {
dfr: $q.defer(),
push: function(v) {
return transport.dfr.resolve(v);
},
then: function(s, f) {
if (f == null) {
f = function() {};
}
return transport.dfr.promise.then(function(_s) {
s(_s);
transport.dfr = $q.defer();
return transport.then(s, f);
}, function(_f) {
f(_f);
transport.dfr = $q.defer();
return transport.then(s, f);
});
}
};
});
$stateProvider.state('state1', {
url: '/state1?other',
templateUrl: 'state-1.html',
controller : function ($scope, $state, $$transport) {
$$transport.then(function(s) {
$scope.param = s
console.log('state1 params:', s);
});
$scope.go = function () {
$state.go('state2', { someParam : 'broken magic' });
}
}
})
.state('state2', {
url: '/state2?someParam',
templateUrl: 'state-2.html',
controller : function ($scope, $state, $$transport) {
$scope.go = function () {
$$transport.push({other:'lazy lizard'});
$state.go('state1');
};
}
});
I've a problem with 2 resolves, one for each controller.
http://jsfiddle.net/pvivera/RhAHy/
var app = angular.module('testApp', [], function($routeProvider){
$routeProvider.when('/', {
template: 'Home {{model}}',
controller: 'HomeCtrl',
resolve: HomeCtrl.resolve
})
.when('/About', {
template: 'About {{model}}',
controller: 'AboutCtrl',
resolve: AboutCtrl.resolve
});
});
var HomeCtrl = app.controller('HomeCtrl', function($scope, HomeCtrlData){
$scope.model = HomeCtrlData;
});
HomeCtrl.resolve = {
HomeCtrlData: function($q, $timeout){
var deferred = $q.defer();
$timeout(function(){
return deferred.resolve('AboutCtrlResolver');
}, 2000);
return deferred.promise;
}
};
var AboutCtrl = app.controller('AboutCtrl', function($scope, AboutCtrlData){
$scope.model = AboutCtrlData;
});
AboutCtrl.resolve = {
AboutCtrlData: function($q, $timeout){
var deferred = $q.defer();
$timeout(function(){
return deferred.resolve('AboutCtrlResolver');
}, 2000);
return deferred.promise;
}
};
In the jsfiddler script, when the HomeCtrl want to resolve HomeCtrlData I receive this error Unknown provider: HomeCtrlDataProvider <- HomeCtrlData
If I change HomeCtrlData to AboutCtrlData in the HomeCtrl everything works, it seems that the only resolve that is assigned is AboutCtrl.resolve
Any idea?
The problem here is that app.controller() doesn't return the controller, it returns your application module. So you're assigning app.resolve twice, which is why it doesn't work for one of them.
I would suggest that you inline the resolve function like this instead:
var app = angular.module('testApp', [], function($routeProvider){
$routeProvider.when('/', {
template: 'Home {{model}}',
controller: 'HomeCtrl',
resolve: {
HomeCtrlData: function($q, $timeout) {
var deferred = $q.defer();
$timeout(function(){
return deferred.resolve('HomeCtrlData');
}, 2000);
return deferred.promise;
}
}
})
.when('/About', {
template: 'About {{model}}',
controller: 'AboutCtrl',
resolve: {
AboutCtrlData: function($q, $timeout) {
var deferred = $q.defer();
$timeout(function(){
return deferred.resolve('AboutCtrlData');
}, 2000);
return deferred.promise;
}
}
});
});