Angular routing - resolve or onEnter - angularjs

My use case is very simple and i'm sure many apps share the same one. I need to verify user and need a simple url to retrieve user token from URL, make api call to my backend service and route the user according to the result from the API.
I don't need to render any page but just make API call and parse the response. I see two options to accomplish: Resolve or OnEnter. I also think there might be another simple way.
Here are the steps:
user getting email with link to /verify?token={token}
in app.js I have a state 'verify' and URL '/verify=token'
call API and get "true" or "false"
if false, redirect user to homepage, if true redirect the user the user profile page.
What is the best and simple way to accomplish what I like to do?
Thanks.
btw - I'm using ui-router.

In your case, I think you should use Resolve of ui-router to make sure state won't load until all data were resolved.
To make user feel good, you should show a loading indicator and register event $stateChangeSuccess to hide it once done

Related

Angular js routing and event flow best practices

I am trying to determine what is the best approach to adopt when a user is already logged in and type /login in the browser URL.
Should I prevent the event to be fired by using $routeChangeStart or $locationChangeStart (which one to chose)
Should I instead redirect to /home ?
Where should I implement the event capture ? In the controller or the app.js
I think you have somewhere a service that tells you if the user is logged in or not. My approach is to use a "resolve" clause/guard in the route/state you want to protect. In this case (login page) you could say something like: are you already logged in? Redirect to /home. Are you not logged in? I leave you load the page and log in. The choice to redirect to /home or elsewhere it depends on your application. You could even redirect to the /my-profile page if you have it.

routing in angular js application with ui-router

When developing a web application with angular js, a part of time that developers spend is the time for implementing routing.
When using ui-router in a application, there are two "phases" to consider with regards to routing:
user navigates inside application: when click is made on some button, user is transfered to another state by using $state.go("somestate"). Parameters can be send etc. And url is changed accordingly.
user navigates directly via url.
Lets say application has such route:
/mythings/{thingid}/mysubthings/{mysubthingid}
If user navigates to that url directly by pasting it into browser window, application needs to handle it. My question is what's the best practice to do it?
What I'm thinging is: if looking at url example above what needs to be done when user enters that url in browser:
get {thingid} from url (from $stateParams), then get {mysubthingid} also from $stateParams (probably by using resolve (ui-router feature) when defining state), then inject what was resolved to controller and then make a query to api and get data about "subthing" and present view in ui with that data. So that should work with both "types of navigations": when user clicks and is transfered to state, or when user enter url directly into browser. Is this the right path to go?
And I suppose that any url you go to when you click something in application, you should be able to take that url and just paste it into browser and see the same results without being redirected to anywhere else. If application cannot handle every url in such way, maybe application' architecture needs to be reconsidered?
Thanks
In UI-Router, the main component of the routing is the state. The URL is essentially just an address that points to a specific state of the app. I don't think it's necessarily productive to think of the two ways of navigating as separate; they're just two sides of the same coin. There should be no URL that isn't handled by a state. Any URL that doesn't match a state should be caught by the otherwise definition on the $stateProvider and probably redirect to your home page or a 404 page.
In your example, the thing/:thingId/subthing/:subthingId url should map to a predefined state just like any other state. Let's say that state is main.subthing. The process for loading the data, initiating the controller and rendering the UI should be exactly the same whether you get there by calling $state.go('main.subthing', {thing: 123, subthing: 456}) or ui-sref='main.subthing({thing: 123, subthing: 456})' or you paste myapp.com/thing/123/subthing/456 into the browser. They'll all end up at exactly the same place with exactly the same data by calling the exact same logic (most likely loading thing 123 and subthing 456 in resolves and injecting those into a controller).
You're right that if a url can't be handled by the application, that's a sign that something is wrong. Like I said, bad urls should be handled by defining otherwise when setting up states. But pasting a URL into a browser shouldn't require any extra work if your states are defined correctly. URL handling is baked into UI-Router by default.
I partially agree with you. The point where I disagree is when the URL is obtained by a user who is not supposed to access it. Quite often some websites implement authorization code to check if the user who is currently accessing the page is authorized to do so.
Also I think the route could be a bit different. Something like:
{thingid}/{mysubthingid}
This, I think is a cleaner URL and the parameters could be handled in the same way as the one in your example.
I suggest this in order to make it a bit difficult to unauthorized users.
Anyway, it definitely depends on the kind of application you are implementing. If the app's requirement is to be able to access the page by pasting the URL in the browser then I guess your approach is much better.

AngularJS hash causes redirect to fail

I have build an AngularJS application and want to use paymill.com to offer different payment methods. I am currently struggling with PayPal.
This api-call allows me to specify a redirect url where the customer gets redirected to after the payment:
https://developers.paymill.com/API/index#create-new-payment-checksum
I get a response with this URL as 'return_url':
http%3A%2F%2Ftest.test.com%2F%23%2Fteatimes%2Fbuy%2Fp82uHoLI6z%2F1
which seems to be the correct encoding for:
http://test.test.com/#/teatimes/buy/p82uHoLI6z/1
Sadly the redirect after the payment does not work and simply redirects me to:http://test.test.com/?paypal_parameters/#/.
So it seems like that everything after the hashtag gets ommited...Is there a way to fix this on my end? I would rather not use html5 mode.
EDIT: If i use the above url without the '#' i get correctly redirect, but angularjs is unable to resolve this of course.
Why don´t you wanna use the html5 mode? you wouldn´t have any issue with the hashtag.
What angular method do you use for redirecting to the URL.

Passport.js, Express.js, and Angular.js routing: how can they coexist?

I apologize this question turned out a bit long, but I have worked on this for some time and really needed to explain all the story.
Background: App based on MEAN stack, trying to authorize Facebook logins using Passport.js.
Following Passport.js guide I implemented something similar to:
// HTML
Add a Facebook login
// send to facebook to do the authentication
app.get('/connect/facebook',isLoggedIn, passport.authorize('facebook',
{ scope : 'email' })
);
// handle the callback after facebook has authorized the user
app.get('/connect/facebook/callback',
passport.authorize('facebook', {
successRedirect : '/profile',
failureRedirect : '/profile'
}));
Notice the target=_self in the html in order to skip Angular routing.
Clearly, authorization works fine. However, redirection does not work, as the routing is handled by Angular. After authorization I never land on /profile (but on the default Angular route).
Therefore, I tried with a custom callback as suggested by Passport.js here, with the hope of passing json data to Angular, and let Angular do the routing. I ended up doing something like:
// In the controller
$http.get("/connect/facebook").success(function(data){
// here I wait for json data from the server and do the routing
});
// I call this route from Angular
app.get('/connect/facebook',isLoggedIn,passport.authorize('facebook',
{ scope : 'email' })
);
// But Facebook lands here!
app.get('/connect/facebook/callback',function(req, res, next) {
passport.authorize('facebook', function(err, user, info) {
res.json({something:smtg});
...
Clearly custom callbacks work for local-login, as Passport.js explains. But here do you see the problem? I call /connect/facebook from Angular, but I should receive some json from /connect/facebook/callback.
I am about to give up Passport, but before this, do you see any solution which would allow landing on /profile after FB authorization, perhaps with a custom message? Many thanks for reading through.
EDIT:
The same question had been reported as an issue on the Passport-Facebook GitHub account. Some additional attempts have been posted there, but not quite the fix yet.
This is a bit more in depth than can be described in one answer, but I'll try to start pointing you in the right direction.
Essentially, Angular.js routes are not really HTML routes at all, but an internal route structure that happens to use the URL for use of the end user. Remember that Angular.js is a client script, and that a full page reload is not desired, as this will reload the entire script. Therefore, /# is used to trick the browser into jumping to a specific bit of code within the already loaded script. (as opposed to the traditional anchor location in the HTML document). Unfortunately (or fortunately), HTML 5 mode allows you to hide the /# part of the url, so instead of seeing http://somesite.com/#/someroute you just see http://somesite.com/someroute. Rest assured, however, that the /# is still there. Angular.js uses the HTML5 pushState (AKA HistoryAPI) to perform the magic replacement.
Given this, if you have called a server route, you are outside the Angular.js script, and any call to load the angular script again will start from the very beginning. You can't actually call your Angular.js route from the server without a full reload. Therefore, you are really doing a double route redirect here. Your server should be calling it's default route for angular, appending /#/someroute to the call. The angular.js page will load, parse off the /#, and redirect to the correct angular route. Keep in mind, however, that if there was any dependency on already loaded objects, those are no longer in memory. Therefore, any route accessed this way should operate as if it is an entry point to your application.
Effectively, you should try using successRedirect : '#/profile', keeping in mind that the profile route in angular should be treated as an app entry point.
Hopefully this gets you started.
If #Claies's way is not working, is it possible you have not get rid of the #= fragment from the facebook callback.
Have a read of this post

Dynamic route without redirect

I have an angularjs app and would like the homepage to depend on the logged in status of the user.
Im looking for something like the following to happen:
When I goto mypage.com use 'resolve' to perform an HTTP GET with a server to check if logged in.
If the user is not logged in resolve the promise from 1) and show some generic splash screen. For example, templateUrl: splash.html
If the user is logged in then fetch additional data from the server. Once the data has been returned then resolve the promise from 1) and show a page specific for this user. For example, templateUrl: loggedin.html
In either case, the URL should not change. ie: I do no want to redirect to another route. The URL should always be mypage.com.
How can I have a dynamic page like this without using any redirects?
Have a look # https://github.com/angular-app/angular-app, its the best example app I've found so far for dealing with the user authorization rabbit hole.
For a quick start with getting your head around how user auth works in angular-app, have a look at these 3 files:
https://github.com/angular-app/angular-app/blob/master/client/src/app/app.js
https://github.com/angular-app/angular-app/blob/master/client/src/common/security/security.js
https://github.com/angular-app/angular-app/blob/master/client/src/common/security/authorization.js

Resources