In my project the $http call is getting called more than once every time. Check the code below.
router.js
angular.module('adminsuite',['ngFileUpload','ui.router','ngCookies','angular-clipboard','ngAnimate', 'ngSanitize', 'ui.bootstrap','ngMessages']).constant("__env",env).config(function($stateProvider, $urlRouterProvider, $locationProvider) {
$urlRouterProvider.otherwise('/');
//$locationProvider.html5Mode(true);
$stateProvider
.state('login', {
url: '/',
views:{
header:{
templateUrl: '',
controller: ''
},
pageContent:{
templateUrl: 'Login/login3.html',
controller: 'loginController'
},
footer:{
templateUrl: 'common/footer3.html',
controller: 'footerController'
}
}
})
// HOME STATES AND NESTED VIEWS ========================================
.state('dashboard', {
url: '/dashboard',
views:{
header:{
templateUrl: 'common/header.html',
controller: 'headerController'
},
pageContent:{
templateUrl: 'dashboard/dashboard.html',
controller: 'dashboardController'
},
footer:{
templateUrl: 'common/innerFooter.html',
controller: 'footerController'
}
}
})
//SURVEY STATES
.state('survey', {
url: '/survey',
views:{
header:{
templateUrl: 'common/headerTool.html',
controller: 'headerController'
},
pageContent:{
templateUrl: 'survey/survey.html',
controller: 'surveyController'
},
footer:{
templateUrl: 'common/innerFooter.html',
controller: ''
}
}
}).state('survey.surveyList', {
url: '/:id',
templateUrl: 'survey/surveyList.html',
controller: ''
}).state('survey.surveyList.details', {
url: '',
templateUrl: 'survey/survey-details/summary.html',
controller: ''
}).state('survey.surveyList.questionare', {
url: '',
templateUrl: 'survey/questionare/questionare.html',
controller: 'questionareController'
}).state('survey.surveyList.sampleManagement', {
url: '',
templateUrl: 'survey/sample-management/sample-management.html',
controller: ''
}).state('survey.surveyList.quotaManagement', {
url: '',
templateUrl: 'survey/quota-management/quota-management.html',
controller: 'quotaController'
}).state('survey.surveyList.scheduling', {
url: '',
templateUrl: 'survey/scheduling/scheduling.html',
controller: ''
}).state('survey.surveyList.notification', {
url: '',
templateUrl: 'survey/notification/notification.html',
controller: ''
}).state('survey.surveyList.reports', {
url: '',
templateUrl: 'survey/reports/reports.html',
controller: ''
}).state('survey.surveyList.location', {
url: '',
templateUrl: 'survey/location/location.html',
controller: ''
});
// ABOUT PAGE AND MULTIPLE NAMED VIEWS =================================
})
loginAuthentication.js
UserService.GetByUsername(requestData)
.then(function (user) {
console.log(user);
if (user.SessionID) {
sessionID = user.SessionID;
userDetails = user.UserProfile;
response = { success: true};
} else {
response = { success: false, message: 'Username or password is incorrect' };
}
callback(response);
});
UserService.js
function GetByUsername(user) {
//console.log(__env.apiUrl);
return $http.post(__env.apiUrl+'/UserAuthentication/login', user, {headers: { 'Content-Type': 'application/json'}}).then(handleSuccess, handleError('Error getting user by username'));
}
When I call this function in the backend it is called more than once. And the same thing is happening for the other APIs.
I removed all the duplicate controllers, but the issue persists.
One particular issue what am getting is sending the token id in the header section of $http call, but this call in back end happening two times and some times more than that. In first time this header token shows empty and second times or more than that time it is giving the result. please check the below code.
api call
$http.get(__env.apiUrl+'/UserSurvey/GetAllSurveys', {
headers: { 'Content-Type': 'application/json','SessionID':$rootScope.token}
})
.then(function(response){
console.log(response);
return response.data;
}, function(error){
console.log("error");
console.log(error);
return error;
});
You might be having a digest cycle issue.
When my AJAX module is located in plain Javascript my data renders on the first server query. However, when I place my AJAX module in an AngularJS module I must query the server twice before my data renders. Note the query is invoked from the UI.
After poking around I realized the data had indeed arrived on the first query and was assigned to all designated objects and variables but only within the scope of the AngularJS code. Of course, the data had arrived asynchronously and the UI had already gone through a digest cycle and had no reason to go again because nothing in the UI had changed. When there’s a change in the UI Angular updates everything but does nothing when the change (arriving data) comes from the server.
Subsequently, the second identical query would force a digest cycle and update all the bindings with the data that was already sitting there from the first query.
Thus the objective is to force a digest cycle from Javascript to update your UI bindings. I now force a digest cycle at the end of my callback function.
To force a digest cycle place the Angular method $scope.$apply([exp]) after your data variable assignments are complete. I found helpful details in the Angular docs at: https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$apply and also a great explanation with working examples at: http://jimhoskins.com/2012/12/17/angularjs-and-apply.html and an important detail about using the “controller as” syntax when forcing a digest cycle at: How to call $scope.$apply() using "controller as" syntax and hopefully this fixes the problem of the double HTTP call.
Related
I'm trying to create a nested state config. When I go with the simple non-nested it works, but when I attempt to do it in a nested fashion it fails.
Below is the working code: (Notice the last state 'new')
app.config(
function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/home',
templateUrl: '/views/home.html',
controller: 'MainCtrl',
resolve: {
qstnrPromise: ['qstnrs', function(qstnrs) {
return qstnrs.getAll();
}]
}
})
.state('questionnaires', {
url: '/questionnaires/{id}',
templateUrl: '/views/questionnaire.html',
controller: 'QuestionsCtrl',
resolve: {
questionnaire: ['$stateParams', 'qstnrs', function($stateParams, qstnrs){
return qstnrs.get($stateParams.id);
}]
}
})
.state('new', {
url: '/questionnaires/{id}/new',
template: '<h3> testy </h3>'
});
//$urlRouterProvider.otherwise('home');
$urlRouterProvider.otherwise(function($injector, $location){
$injector.invoke(['$state', function($state) {
$state.go('home');
}]);
});
});
If I attempt to change it with the following, it fails. The URL on browser changes but I don't receive the template.
.state('questionnaires.new', {
url: '/new',
template: '<h3>New question</h3>'
});
Have I understood states incorrectly? Or where have I gone wrong?
Try changing your new state to:
.state('new', {
url: '/new',
parent: 'questionnaires',
template: '<h3>New question</h3>'
})
See if that works for you.
You can make the questionnaires state abstract.
$stateProvider
.state('questionnaires', {
abstract: true,
url: '/questionnaires',
})
.state('questionnaires.new', {
// url will become '/questionnaires/new'
url: '/new'
//...more
})
But in this case you will need to add one additional nested state in order to implement the functionality you need for the $stateParams.id.
I use angular's ui-router and nested routes in a project and I'm faced by the problem that everything works like a charm when I use links (ui-sref) to navigate to the user's detail page with the userId as part of the url. When I refresh the page, state params are missing.
So I've taken a look at the angular demo: http://angular-ui.github.io/ui-router/sample/#/contacts/1/item/b and couldn't reproduce this behaviour, however nested states are not part of this demo in contrast to my application.
$stateProvider
.state('base', {
abstract: true
})
.state('home', {
parent: 'base',
url: '/',
views: {
'content#': {
templateUrl: 'app/index/index.view.html',
controller: 'IndexController',
controllerAs: 'home'
}
}
})
.state('users', {
url: '/users',
parent: 'base',
abstract: true
})
.state('users.list', {
url: '/list',
views: {
'content#': {
templateUrl: 'app/users/users.list.html',
controller: 'UsersController',
controllerAs: 'users'
}
},
permissions: {
authorizedRoles: UserRoles.ALL_ROLES
}
})
.state('users.details', {
url: '/:userId/details',
views: {
'content#': {
templateUrl: 'app/users/user.details.html',
controller: 'UserDetailsController',
controllerAs: 'userDetails'
}
},
resolve: {
logSomeParams: ['$stateParams', '$state', function ($stateParams, $state) {
console.log($stateParams);
console.log(this);
console.log($state);
}]
}
})
When refreshing the page the url immediately changes to http://localhost:3000/#/users//details and console output (resolve function) shows that params are missing.
html5Mode (LocationProvider) is not enabled. I already found "solutions" like redirecting back to the list if the the userId is missing on page refresh, but I just can't believe that there isn't a better way to solve this.
This is how I linked the details page in the overview (and it is working):
<div class="panel-body" ui-sref="users.details({userId: user.siloUserId})">
As expected, my problem had nothing to do with the ui-router. The URLMatcher works as expected, even if you refresh the page (everything else would have been a huge dissapointment).
However, I have a $stateChangeStart listener which checks if the SAML authentication session (cookie) is still valid and waits for the result.
function(event, toState, toParams, fromState, fromParams){
if(!authenticationService.isInitialized()) {
event.preventDefault();
authenticationService.getDeferred().then(() => {
$state.go(toState);
});
} else {
//check authorization
if ( authenticationService.protectedState(toState) && !authenticationService.isAuthorized(toState.permissions.authorizedRoles)) {
authenticationService.denyAccess();
event.preventDefault();
}
}
}
No idea how this could happen, but I forgot to pass the parameters to the go method of the stateProvider. So all I had to change was to add the params:
$state.go(toState, toParams);
I have these router.js inside my ionic app ,
myapp.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('app', {
url: "/app",
abstract: true,
templateUrl: "templates/menu.html",
controller: 'AppCtrl'
})
.state('app.myprofile', {
url: "/myprofile",
abstract: true,
views: {
'menuContent': {
controller : "myprofileCtrl",
templateUrl: "templates/myprofile.html"
}
}
})
.state('app.myprofile.info', {
url: "/info",
controller: "profileinfoCtrl",
templateUrl: "templates/profile/info.html"
})
.state('app.myprofile.location', {
url: "/location",
controller: "profilelocationCtrl",
templateUrl: "templates/profile/location.html"
})
$urlRouterProvider.otherwise('/');
});
I need a way to share controller scopes between myprofile state and myprofile.location state and myprofile.info state too .
I am using ionic framework
in myprofileCtrl
myapp.controller("myprofileCtrl",function($scope,Authy ,Auth,$http ,$rootScope){
$scope.view_loading = true;
Authy.can_go().then(function(data){
$scope.profile =data.profile;
});
});
in profilelocationCtrl
myapp.controller("profilelocationCtrl",function($scope,Authy ,Auth,$http ,$rootScope){
console.log($scope.profile);
});
I got undefined in the console
I think the problem is that since $scope.profile is set after an ajax call, when the myprofile.location state is reached initially, then profile variable is still undefined on the parent $scope, what you could do is $watch the profile variable, or better just broadcast an event downwards when you receive it fro the server call using $broadcast.
$broadcast dispatches the event downwards to all child scopes, so you could do:
myapp.controller("myprofileCtrl",function($scope,Authy ,Auth,$http ,$rootScope){
$scope.view_loading = true;
Authy.can_go().then(function(data){
$scope.profile =data.profile;
$scope.$broadcast('profileSet', data.profile);
});
});
and in the myprofile.location` state:
myapp.controller("profilelocationCtrl",function($scope,Authy,Auth,$http,$rootScope){
$scope.$on('profileSet', function(event, data) {
console.log(data);
});
}
});
Have a look at this demo plunk I just made.
after I did the update to angular 1.3 I'm not able to reach the controllers and views, they simply doesn't load.
the states in my root works perfectly, this is my app.js
$stateProvider.state("root",
{
url: '',
abstract: true,
views: {
'footer#': {
templateUrl: "/partial/footer/footer.html",
},
'header#': {
templateUrl: "/partial/header/header.html",
}
}
}).state('root.home', {
url: '/index',
views: {
'container#': {
templateUrl: '/partial/index/index.html',
controller: 'IndexCtrl'
}
}
}
).state('root.welcome', {
url: '/index/:status',
views: {
'container#': {
templateUrl: '/partial/index/index.html',
controller: 'IndexCtrl'
}
}
});
an also my configuration:
$urlRouterProvider.otherwise('index');
$locationProvider.hashPrefix('!');
$locationProvider.html5Mode({ enabled: false });
by after doing a stage.go or just by typing the url, I'm not able to reach any route in these states:
$stateProvider.state("candidate",
{
url: '',
abstract: true,
views: {
'footer#': {
templateUrl: "/partial/footer/footer.html"
},
'header#': {
templateUrl: "/user/partial/user.header/user.header.html",
},
'sideBar#': {
templateUrl: '/user/partial/user.sidebar/user.sidebar.html',
controller: 'SidebarCtrl',
resolve: {
user: 'currentUser'
}
},
'navBar#': {
templateUrl: '/user/partial/navbar/navbar.html'
}
}
}).state('candidate.dashboard',
{
url: '/dashboard',
views: {
'container#': {
templateUrl: '/user/partial/user.dashboard/user.dashboard.html',
controller: 'DashboardCtrl',
resolve: {
dashboardinfo: function ($resource, tracker) {
var resourceGet = $resource('/user/dashboard');
var promise = resourceGet.get().$promise;
tracker.addPromise(promise);
return promise;
}
}
}
}
})
I've spent a couple of hours trying to figure this out without any luck, maybe it's just a small detail I'm missing, any advice will be more than welcome.
PS: I'm using v0.2.12-pre1
I tried to replicate the issue, mentioned above in this working plunker. All the code is almost unchanged, I just used a custom version of UI-Router. The reason is this reported and known bug:
Impossible to disable html5Mode with angular 1.3.0-rc.3 #1397 (small cite:)
Due to: angular/angular.js#dc3de7f
the html5mode-check in urlRouter.js [line 383] is no longer correct. And thus it's impossible to disable html5mode.
A quick fix could be:
var isHtml5 = $locationProvider.html5Mode();
if (angular.isObject(isHtml5)) {
isHtml5 = isHtml5.enabled;
}
And this (the code above) is the change I made. Nothing else. All the code started to work then...
Check also this answer
ui-router not producing correct href attribute in angular
for a Chris T link to fixed version...
it turns out that the resolve method was failing, I'm using angular promise tracker
var resourceGet = $resource('/user/dashboard');
var promise = resourceGet.get().$promise;
tracker.addPromise(promise); <-- fails here
return promise;
it seems like resources and promises have breaking changes and my implementation could be deprecated.
I am asking a similar question to this question: UI Router conditional ui views?, but my situation is a little more complex and I cannot seem to get the provided answer to work.
Basically, I have a url that can be rendered two very different ways, depending on the type of entity that the url points to.
Here is what I am currently trying
$stateProvider
.state('home', {
url : '/{id}',
resolve: {
entity: function($stateParams, RestService) {
return RestService.getEntity($stateParams.id);
}
},
template: 'Home Template <ui-view></ui-view>',
onEnter: function($state, entity) {
if (entity.Type == 'first') {
$state.transitionTo('home.first');
} else {
$state.transitionTo('home.second');
}
}
})
.state('home.first', {
url: '',
templateUrl: 'first.html',
controller: 'FirstController'
})
.state('home.second', {
url: '',
templateUrl: 'second.html',
controller: 'SecondController'
});
I set up a Resolve to fetch the actual entity from a restful service.
Every thing seems to be working until I actually get to the transitionTo based on the type.
The transition seems to work, except the resolve re-fires and the getEntity fails because the id is null.
I've tried to send the id to the transitionTo calls, but then it still tries to do a second resolve, meaning the entity is fetched from the rest service twice.
What seems to be happening is that in the onEnter handler, the state hasn't actually changed yet, so when the transition happens, it thinks it is transitioning to a whole new state rather than to a child state. This is further evidenced because when I remove the entity. from the state name in the transitionTo, it believes the current state is root, rather than home. This also prevents me from using 'go' instead of transitionTo.
Any ideas?
The templateUrl can be a function as well so you check the type and return a different view and define the controller in the view rather than as part of the state configuration. You cannot inject parameters to templateUrl so you might have to use templateProvider.
$stateProvider.state('home', {
templateProvider: ['$stateParams', 'restService' , function ($stateParams, restService) {
restService.getEntity($stateParams.id).then(function(entity) {
if (entity.Type == 'first') {
return '<div ng-include="first.html"></div>;
} else {
return '<div ng-include="second.html"></div>';
}
});
}]
})
You can also do the following :
$stateProvider
.state('home', {
url : '/{id}',
resolve: {
entity: function($stateParams, RestService) {
return RestService.getEntity($stateParams.id);
}
},
template: 'Home Template <ui-view></ui-view>',
onEnter: function($state, entity) {
if (entity.Type == 'first') {
$timeout(function() {
$state.go('home.first');
}, 0);
} else {
$timeout(function() {
$state.go('home.second');
}, 0);
}
}
})
.state('home.first', {
url: '',
templateUrl: 'first.html',
controller: 'FirstController'
})
.state('home.second', {
url: '',
templateUrl: 'second.html',
controller: 'SecondController'
});
I ended up making the home controller a sibling of first and second, rather than a parent, and then had the controller of home do a $state.go to first or second depending on the results of the resolve.
Use verified code for conditional view in ui-route
$stateProvider.state('dashboard.home', {
url: '/dashboard',
controller: 'MainCtrl',
// templateUrl: $rootScope.active_admin_template,
templateProvider: ['$stateParams', '$templateRequest','$rootScope', function ($stateParams, templateRequest,$rootScope) {
var templateUrl ='';
if ($rootScope.current_user.role == 'MANAGER'){
templateUrl ='views/manager_portal/dashboard.html';
}else{
templateUrl ='views/dashboard/home.html';
}
return templateRequest(templateUrl);
}]
});