I'm working on an Ionic App where i run in some trouble.
I'm new to AngularJS and Ionic.
The user needs to be logged in to use the app. To check this an apicall to my server is called on entry of the app. If the user is not logged in, the app will show a modal where the user can login.
But in the small second that the apicall is made you see the "inside" of the app (restricted pages).
To avoid this i want to place a screen where the app checks if the user is logged in. And if the user is logged in, the screen needs to send the user further in the app.
The problem in this is that the app doesn't send the user on. I replaced all the code with a simple a href (ui-sref) but that doesn't work either.
The funny, weird part is that if i run it in my browser it works. But on my mobile(android) is doesn't do anything.
I tried it with a function with $location.path but i doesn't send me anywhere. It does set the path.
I tried $apply, $digest, $window.location.href .... etc etc. none worked.
If i don't use the wait screen everything works fine.
wait.html
<a ui-sref='app.proposals({"favorite" : 0})'>Continue</a>
RouteProvider
matcher.config(function($stateProvider, $urlRouterProvider, $ionicConfigProvider)
{
$ionicConfigProvider.tabs.position("bottom");
$ionicConfigProvider.tabs.style("standard");
$stateProvider
.state('app', {
url: '/app',
abstract: true,
templateUrl: 'templates/menu.html',
controller: 'AppCtrl'
})
.state('app.proposals', {
url: '/proposals/:favorite',
views: {
'menuContent': {
templateUrl: 'templates/proposals.html',
controller: 'ProposalsCtrl'
}
}
})
.state('app.proposal', {
url: '/proposal/:title/:id/:url',
views: {
'menuContent' : {
templateUrl: 'templates/proposal.html',
controller: 'ProposalCtrl'
}
}
})
.state('wait',{
url: '/wait',
templateUrl: 'templates/wait.html',
controller: 'WaitCtrl'
});
// if none of the above states are matched, use this as the fallback
//$urlRouterProvider.otherwise('/app/proposals/0');
$urlRouterProvider.otherwise('/wait');
});
Alright, now, the best way to solve this would be use a better practice. Your application follows the standard Authentication Flow. Now, according to me, wouldn't it be better if you just animate the current view in context. This will serve two purposes
reduce the render-load time;
get rid of you problem.
According to me, the problem here is that when you make the API call, Ionic tries to get hold of a cached page. The best way to fix it to have a default base check; point to index.html, the IndexController checks is the user is logged in, if it is, use $state.go("STATE_NAME") to go to the logged in state, otherwise, go to a state where you login.
Trust me when I say this: not only will this be easier, it'll also be more maintainable once the application code really builds up.
Should you require any further clarifications and/or code samples, just comment here. I haven't included them as it's trivial and extrapolates the logic and the syntax you're already familiar with.
Related
I am facing a url structure problem using ui-router in AngularJS. I want to have first level SEO friendly url structure like this:
https://people-profile.com/mike-david-tringe
So I can grab the SEO name "mike-david-tringe" via stateParam and use it to find data in database and populate the page.
The $stateProvider has code like this:
$stateProvider
.state('people', {
url: '/:nameUrl',
templateUrl: 'app/frontend/page.tmpl.html',
params: {
nameUrl: {squash: true},
},
controller: "PageController",
controllerAs: 'vm'
})
.state('admin', {
url:'/admin/:userId',
templateUrl:'app/frontend/admin/admin.html',
controller:'AdminController',
controllerAs: 'admin'
})
With above code, I can have https://people-profile.com/mike-david-tringe working with nameUrl = mike-david-tringe and I got SEO friendly first level url link. mike-david-tringe is SEO friendly and most important keywords beside the domain name.
But with this structure, https://people-profile.com/admin/ or https://people-profile.com/login/ will not work now. Since my controller try to grab admin as nameUrl and looking for data. And admin is not a nameUrl so my database will return null, the app will fail.
In short, stateParam nameUrl will grab anything after "/" so the url setting will think admin and login is :nameUrl but in fact, it is not.
So how do I structure my app ui-router structure to have SEO friendly url like https://people-profile.com/mike-david-tringe but when url is https://people-profile.com/admin/, it will load admin.html template and use AdminController instead as I defined in $stateProvider?
All you need to do is swap the order of them. The router will check in order of definition, so if /:nameUrl comes before /admin it will trigger first. But if you put /:nameUrl last then it will trigger on any url that hasn't already triggered something above.
A word of warning however. Moving between two urls that trigger the same state (like two urls that both hit /:nameUrl in your case) will not reload the controllers on the page. Only changing state will do that. There are options to change this behaviour, but it has always been very buggy for me.
I just wondering does anybody know how to debug situation when you have blank page for UI-Router. (Of course, without any errors in console)
By doing console.log for router events(take from here) I found you that it went to correct state but after did not stop on breakpoint inside state controller that I specified in UI-Router state:
.state('invited-user', {
parent: 'authPublic',
url: '/users/invitation/accept?back_link&invitation_token',
templateUrl: 'auth/invited-form.html',
controller: 'InvitedUserController',
data: {
hidePageNavigation: true
}
})
so I guess that controller is a problem.
Already tried to mock it:
.state('invited-user', {
parent: 'authPublic',
url: '/users/invitation/accept?back_link&invitation_token',
templateUrl: 'auth/invited-form.html',
controller: function(){
debugger
},
data: {
hidePageNavigation: true
}
})
but without any result, unfortunately.
I look for solution for current issue and general approach how to debug such kind of situations in general.
So I came to conclusion that the logic of debug should be so:
console.log router events (code is here) to check router logic
check the template of current router state (mock it if needed)
check the controller of current state (mock with empty function if needed)
check all templates and controllers of parent states from current one, starting from nearest parent and going up.
Actually it would be nice to have exception from box to see exact problem, but unfortunately we have what we have.
I have the following code redirect/transition logic in my appConfig for re-pointing of invalid routes:
$urlRouterProvider.when('/:lang/profile/:keywords/:id', ['$state', '$stateParams', function ($state, $stateParams) {
$state.transitionTo('root.public-profile.summary', $stateParams, {
reload: true,
inherit: false,
notify: true
});
with Summary route defined as:
state('root.public-profile.summary', {
url: "/summary",
templateUrl: "/templates/public.profile.summary.tpl.html"
})
So when a user attempts to access '/:lang/profile/:keywords/:id' it should redirect/re-point them to /:lang/profile/:keywords/:id/summary. This works fine when a view had been loaded before, if a user attempts to remove the 'summary' portion from the Url, it does gets re-appended automatically as expected. However, if a user copies and pastes 'wrong' link directly in a new browser window, the $stateParams object is empty and thus transition can't happen.
Is that behavior by design and is there a way to fix that?
You are right Val,
This behaviour is by design.You should see everything in the form of state-diagrams and Whether the transition will happen or not depends on what state is getting activated.What I can see from your snippet is that here you are working with ui-router where states carries more significance then the actual urls.
Not sure what you are trying to achieve but these docs can be helpful to you.
https://github.com/angular-ui/ui-router/wiki
Please Comment back for any other concerns or vote up if you are convinced with this answer.
Basically, I'm trying to find a way to efficiently fire tags using Adobe DTM in Angular without having to change the page. We have an exceptionally long elevation cycle so having to add _satelitte.track() to a page to get a new tag to fire would severly limit the benefit of using DTM. I'm primarily concerned this would be necessary in the case that I'd want to only fire tags in certain situations so I wouldn't be able to use the already existing rule in place.
I believe that _satellite.pageBottom() is what tells the satellite object that a page load has occured. I'm attempting to call _satellite.pageBottom() to mimic a page load any time the route changes.
.config(function($routeProvider, $httpProvider){
$routeProvider.when('/one', {
templateUrl: 'view1.html',
controller: 'Data1Controller'
}).when('/two', {
templateUrl: 'view2.html',
controller: 'Data2Controller'
}).when('/three', {
templateUrl: 'view1.html',
controller: 'Data3Controller'
}).when('/four', {
templateUrl: 'view2.html',
controller: 'Data4Controller'
}).when('/five', {
templateUrl: 'form.html',
controller: 'FormController'
}).otherwise({
controller: "Default",
templateUrl: 'default.html'
});
$httpProvider.interceptors.push('CacheBusterInterceptor');
}).run(function($rootScope){
$rootScope.$on('$routeChangeStart', function(){
_satellite.pageBottom();
});
});
This has worked well for me in other situations where I want to mock a page load but it's not working with the _satellite.pageBottom() call and I am at a loss how I might get DTM to work in Angular without using the direct call rules. Any advice on getting either this way to work or another work around to having to make changes to the code on the page?
Thanks,
Mike
I've used a generic _satellite.track('pageLoad') direct call rule to work around single page app challenges. You don't have to change the page code that way. As long as the variables you need are accessible by DTM, you can run all your logic in the tag manager.
Edit for dynamic direct call rule:
$rootScope.$on('$routeChangeSuccess',function(e, curr, pre){
_satellite.track(current.$$route.originalPath);
})
or if you want to add a pagename in your $routeProvider config:
$routeProvider.when('/',{pageName:'Fantastic Home Page',controller:...,templateUrl:...}
$rootScope.$on('$routeChangeSuccess',function(e, curr, pre){
_satellite.track(current.pageName || 'whoops no pageName');
})
Adobe DTM allows for firing rules based on popstate or hashtag change. The best approach is to setup your rules based on these events and if your app supports deep linking then also setup page load rules based on the deep link URL's.
how is it possible to set up url routes in the $stateProvider of the ui-router module with url params in a hierarchy like this
/home
/:username
/:title/editor
I only get it to work if there is no conflict on the same hierarchy level like:
/home
/user/:username
/editor/:title
Right now everything will router to /home if I try to set it up like in the first example.
I know it from other situations like on Google Appengine, where the first approach would work aswell and where it would be seen as a kind of hierarchy, where the /:username route would apply as long it not equals 'home'.
Thanks for help!
I would say this should be possible, e.g. this would work (see example):
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'test.html',
controller: 'TestCtrl',
})
.state('editor', {
url: '/:title/editor',
...
})
.state('user', {
url: '/:userName',
...
Observe it here. The reason why this is working, because the state editor - with a strong key /editor is evaluated before userName. The same for home - it is the first evaluated pattern.
BUT - I would suggest, do not count on order. Use these discriminators at the beginning (e.g. /user/... or /editor/..). Our users, will understand it as well, and any later confusion (why this url triggered that state) won't surprise us