When I am using $ionicHistory.backView() it is returning the view that was before the view previous to the current view, so it is going one step back than it should be. But when I refresh the page on the view previous to the current one, where I am testing $ionicHistory.backView() it is returning null. For some reason I am not getting anything for that specific view.
This is my code:
.controller('RegisterController', function($scope, $state, UserService, $auth, MessageService, $ionicHistory) {
$scope.user = UserService.get();
$scope.validate = {};
$scope.registerPromise = {};
console.log($ionicHistory.backView());
And these are the routes:
.state('main.login', {
url: '/login',
views: {
'content': {
templateUrl: 'templates/login.html',
controller: 'AuthController',
}
},
authenticate: false
})
.state('main.login2', {
url: '/login2',
views: {
'content': {
templateUrl: 'templates/login2.html',
controller: 'AuthController',
}
},
authenticate: false
})
.state('register.contact', {
url: '/contact',
views: {
form: {
templateUrl: 'templates/user/register-contact.html',
}
}
})
So, the flow is when the user is on the main.login page, he can either go to the register.contact page where he leaves the contact details, or go to the main.login2 page where he can login or reset the password by going again to register.contact page where he can again send his contact details for reseting the password. That is why I need to know for my form where is the user coming from, since I am using the same form for two things, leaving the contact details for registering and reseting the password. But I am not getting the correct data from $ionicHistory.backView()
Related
I'm having bad time with nested state, resolve and browser back button.
Below my states configuration, it consists of one abstract state and 2 children state, one to view a profile,
one to reserve it. The usual flow is opening the profile page, then click on some link and open the request page; this works fine. However if I click the browser back button on profile-request page, ProfileViewController is executed but profileData is not resolved.
Is there a way either to reload the previous view as it was (without having to rendering-it again) or force the promise resolution before executing the controller?
$stateProvider
.state('public', {
abstract: true,
templateUrl: 'app/public.html'
})
.state('public.profile-view', {
url: '/profile/:slug',
templateUrl: 'app/profile/profile.view.html',
controller: 'ProfileViewController',
controllerAs : 'vm',
resolve: {
profileData: function($stateParams, Profiles) {
return Profiles.query({ slug: $stateParams.slug });
}
}
})
.state('public.profile-request', {
url: '/profile/request/:slug',
templateUrl: 'app/profile/profile.request.html',
controllerAs: 'vm',
controller: 'ProfileRequestController',
resolve: {
profileData: function($stateParams, Profiles) {
return Profiles.query({ slug: $stateParams.slug });
}
}
})
Have you tried caching the profileData in Profiles and then in ProfileViewController try to get cached data if it is existing.
Another option is storing profileData in the $rootScope.
I am having tab structure in my application like below :
and for each tab I have a form and a submit button. If all the form data is not filled then I am showing the Error popup(using angular UI bootstap Modal popup) which displays "Fill the Account Creation Data" on click of the Submit button.
But What I want to do is when user clicks on Personal Details Tab (or any other tab) shown in above image, then also I want to show the error message that "Fill the Account Creation Data"
In general if user click on any tab, and if one of the form is not completely filled then Error popup should be displayed.
I have written the code to show error Popup on click of the Submit button,
But not sure how to achieve this on the click of the tab Routes.
My code for the route is as follow :
onboardingApp.config(['$routeProvider', '$httpProvider', function ($routeProvider, $httpProvider) {
$routeProvider.when('/empDetails', {
templateUrl: 'templates/employeeDetails.html',
controller: 'empDetailsController',
activeLink: 'empDetails',
data: {
login: false
}
});
$routeProvider.when('/login', {
templateUrl: 'templates/login.html',
controller: 'loginController',
activeLink: 'login',
data: {
login: true
}
});
$routeProvider.when('/accType', {
templateUrl: 'templates/accountType.html',
controller: 'accountTypeController',
activeLink: 'accType',
data: {
login: false
}
});
$routeProvider.when('/verifyID', {
templateUrl: 'templates/identityVerification.html',
controller: 'verifyIdentityController',
activeLink: 'verifyID',
data: {
login: false
}
});
$routeProvider.when('/personalDetails', {
templateUrl: 'templates/personalDetails.html',
controller: 'personalDetailsController',
activeLink: 'personalDetails',
data: {
login: false
}
});
$routeProvider.otherwise({
redirectTo: '/login'
});
}]);
Kindly help me in this case. Is there any way to check the form validity in Resolve property in route configuration?
Thanks in Advance !
What I am trying to do is within the Search controller, once I get the search results back from the server ($http) change view to a different view - the search results view. I am not sure if the approach I am going about it is right, but either-way it doesn't seem to be working. I will need to pass the response as well, so the new view can display the results/response.
My app.js:
.....state('tab.search', {
url: '/search',
views: {
'tab-search': {
templateUrl: 'templates/tab-search.html',
controller: 'SearchCtrl as search'
}
}
})
.state('tab.search-results', {
url: '/results',
views: {
'tab-search-results': {
templateUrl: 'templates/tab-search-results.html',
controller: 'SearchResultsCtrl as searchResults'
}
}
})
Then my search controller has:
.controller('SearchCtrl', function($scope, $state, $location, $ionicPopup, service) {
....
$scope.doSearch = function(state) {
.....
var result = service.doSearch(dataObj);
result.then(function(response) {
console.log("I'm here");
$state.go('tab.search-results');
......
My search results view (tab-search-results.html) has the following basic code at the moment:
<ion-view view-title="Search Results">
<ion-content padding="true">
hello world
</ion-content>
</ion-view>
This basic structure is how all my other pages/views are setup too.
What happens when I perform the search is that the console message gets outputted, and then the URL changes to /results as per the tab.search-results state, but the template/view doesn't change/show.
Interestingly if I change $state.go('tab.search-results'); to point to another app state/view that I know works, it works perfectly - but for whatever reason this state/view isn't working.
Also, if there is a better way of achieving this same thing, then please let me know. I will be needing to eventually pass the "response" from SearchCtrl to SearchResultsCtrl - or rather access it on the search results page in one form or another.
Many thanks.
I think you are looking for $stateParams.
var result = service.doSearch(dataObj);
result.then(function(response) {
$state.go('tab.search-results', {'searchData':response});
}
In your routes file:
.state('tab.search-results', {
url: '/results/:searchData',
views: {
'tab-search-results': {
templateUrl: 'templates/tab-search-results.html',
controller: 'SearchResultsCtrl as searchResults'
}
}
})
And in your SearchResultsCtrl:
.controller($stateParams) {
console.log($stateParams.searchData) // will give you search results
}
NOTE:If you don't want to pass data through the URL you can use params key in the .state() method.
.state('tab.search-results', {
url: '/results',
params: {
'searchData':null
},
views: {
'tab-search-results': {
templateUrl: 'templates/tab-search-results.html',
controller: 'SearchResultsCtrl as searchResults'
}
}
})
I realised why my view wasn't changing properly. The fix was changing the views in the sub-view to reference the parent view.
Fail (sub-view has unique name from parent):
.....state('tab.search', {
url: '/search',
views: {
'tab-search': {
templateUrl: 'templates/tab-search.html',
controller: 'SearchCtrl as search'
}
}
})
.state('tab.search-results', {
url: '/results',
views: {
'tab-search-results': {
templateUrl: 'templates/tab-search-results.html',
controller: 'SearchResultsCtrl as searchResults'
}
}
})
Success (sub-view references parent, 'tab-search'):
.....state('tab.search', {
url: '/search',
views: {
'tab-search': {
templateUrl: 'templates/tab-search.html',
controller: 'SearchCtrl as search'
}
}
})
.state('tab.search-results', {
url: '/results',
views: {
'tab-search': {
templateUrl: 'templates/tab-search-results.html',
controller: 'SearchResultsCtrl as searchResults'
}
}
})
Thanks all, I think I worked out the problem. It was putting the search results page under the tab abstract state. eg: tab.search-results rather than search-results - I am guessing this was the problem as there is no search results tab. When I re-named the state to just search-results (and modified the $state.go to use 'search-results' instead of 'tab.search-results') it worked. Does this seem right?
I'm following this sample on adding custom data to state objects but can't figure out what I'm doing wrong.
The idea is to have a Users state with a template that have 3 views: header, content and footer. The header-view gets updated with the child state's title and breadcrumb. The unnamed content-view will show the child's template (like a users list) and the footer will show summary data.
I have 2 issues:
My custom data object on my header's current state is undefined. ['Cannot read property 'title' of undefined]
If I exclude the custom data and just set the $scope values directly in the controller, it works fine but now get a 404 error. [GET http://localhost:3000/users 404 (Not Found)]. This makes no sense to me.
Am I on the right track with what I want to do? I'm unsure if I need the custom data or can I just set it in the controller?
angular.module('users').config(['$stateProvider',
function($stateProvider) {
// Users state routing
$stateProvider
.state('users', {
onEnter: function(){
console.log('state change to users');
},
abstract: true,
url: '/users',
views: {
'': {
templateUrl: 'modules/users/views/users.html'
},
'header#users': {
templateUrl: 'modules/core/views/page-header.html',
// data: { //<- this is undefined in the controller
// title: 'Users',
// breadcrumb: 'Home / Users'
// },
controller: function($scope, $state) {
$scope.title = 'Users'; //$state.current.data.title;
$scope.breadcrumb = 'Home / Users'; //$state.current.data.breadcrumb;
}
},
'footer#users': {
templateUrl: 'modules/core/views/page-footer.html'
}
}
})
.state('users.list', {
onEnter: function(){
console.log('state change to users.list');
},
url: '',
templateUrl: 'modules/users/views/users-list.html'
})
.state('signin', {
url: '/signin',
templateUrl: 'modules/users/views/authentication/signin.client.view.html'
});
}
]);
<section>
<div ui-view="header"></div>
<div ui-view=""></div>
<div ui-view="footer"></div>
</section>
You're receiving undefined because you're trying to access a data object belonging to the state itself, rather than the view you've defined it on. Typically, data would be defined against the state, but if you wish to do so against the view, you will need to use:
views: {
'header#users': {
data: {
title: 'Users',
},
controller: function($scope, $state) {
$scope.title = $state.current.views['header#users'].data.title;
}
}
}
As for your 404 error, there is nothing presented in the code that would cause this, so the problem must lay elsewhere.
I have a state that has multiple views declared in it as follows:
$stateProvider
.state('home.details.item', {
url: '^/details',
views: {
'chartsView': {
templateUrl: 'charts.html',
controller: 'chartsCtrl'
},
'gridView': {
templateUrl: 'grid.html',
controller: 'gridCtrl'
},
'detailsView': {
templateUrl: 'details.html',
controller: 'detailsCtrl'
}
}
});
I need to reload one of the views without reloading the whole state, without using $state.go($state.current,null , {reload: true}) , and if possible, from the chartCtrl reload detailsCtrl. Is that possible?
I'd say, that the UI-Router solution should be built arround *states*, not views.
(I created working example here). Other words, if there are
some views which should not be reloaded and
some other views, which should be reloaded
... it calls for state nesting. Let's move that view into child state:
.state('home.details.item', {
url: '^/details',
views: {
'chartsView': {
templateUrl: 'tpl.charts.html',
controller: 'chartsCtrl'
},
'gridView': {
templateUrl: 'tpl.grid.html',
controller: 'gridCtrl'
},
// 'detailsView': {
// templateUrl: 'details.html',
// controller: 'detailsCtrl'
// }
}
})
.state('home.details.item.more', {
views: {
'detailsView#home.details': {
templateUrl: 'tpl.details.html',
controller: 'detailsCtrl'
}
}
})
We also need a state, which will do the reload. We could use other way, e.g. with some changing parameter in state more, but that would mean to change the param value on each call. With this specil state, we can easily reload our state 'more':
.state('reload', {
parent: "home.details.item",
views: {
'detailsView#home.details': {
// this controller will just redirect to 'more' and make it fresh...
controller: ['$state', function($state) { $state.go('^.more')}],
}
}
})
And with these simple controllers we can do all that required stuff:
.controller('chartsCtrl', function ($scope, $state) {
var childName = ".more";
$state.go(childName); // default is a sub state 'more'
})
.controller('detailsCtrl', function ($scope) {
$scope.when = Date.now();
})
Having this: we can call this to reload just details:
<a ui-sref="reload">force reload detail view</a>
Now, when navigating to reload, we will be redirected to state "more" and our view will be rerendered.
SUMMARY:
In general, UI-Router represents state machine. I would strongly suggest:
Do not worry to think in states. Views are just their representation in the DOM.
If there are some features related, they most likely represent state. If others do not relate (should be changed often or rarely) they belong to other state. It could be parent, child or sibling...
Check it here