How to route to two pages on certain conditions with $urlRouterProvider.otherwise(" ") in angularjs - angularjs

I have a strange requirement. Since I have a 404 page on my angularjs app, I don't want to leave it unnoticed because it has a random joke API added to it.
Now my angular js application uses UI route provider for routing. I have a
$urlRouterProvider.otherwise("/home")
code in my angularjs configuration. I want the page to redirect to home if there isn't any path specified. E.g. https://mypage.com should route to https://mypage.com/#!/home but if someone types a wrong state name manually, it should redirect it to the 404 page.
My only question is since this requires two routings in otherwise statement, is it even possible? And if it is possible, then how?

Related

Routing an user in a single page application using the adress bar

I have a backend using express to serve a static directory, to the path /, in which is contained a single page frontend. This backend also serves an API REST.
The frontend is built in React, and uses react-router to route the user from the different views of the web application.
If my react-router have two entries, let say /app and /config,
how can I redirect the client to that view of the application, if the user enters directly the URL in the web browser's address bar?
Right now, if I do that, Express gets the request and obviously returns a 404 message, as the single page is served to / path.
A simple way to resolve that is to always (even on 404s) send to user the index.html in your express route handlers.
See: https://stackoverflow.com/a/25499007/2624575
However, you need to take care of some things:
1) Your React Router code should start to handle 404s: https://stackoverflow.com/a/37491381/2624575
2) You need to handle correctly the path to your assets (icons, css, js, etc), otherwise you'll send the same index.html to those kind of resources (which will make your page render incorrectly)
3) Make sure that react-router is using browserHistory (the history that doesn't use hashes #), This way React will be able to render your routes correctly
Hope it helps!

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.

Browser history doubled in angularjs app

So I am using a web app which has an iframe pointing to my angularjs application. If I navigate around the parent web app, I notice that the browser history is doubled up. For example, if I navigate to contacts > about us > home, then the history will be:
- home
- about us
- about us
- contacts
- contacts
If I point the iframe to a simple web page with no angular, then the parent app history works fine. I came across this bug on the angularjs website with a similar issue which appears to have been resolved in an earlier version of angular: https://github.com/angular/angular.js/issues/1054 but it doesn't seem to be resolved for some people. I'm using v1.2.26. Has anyone else experienced this issue?
So it turns out my assumptions about routing as the potential cause were correct, and I can't believe I didn't realize this sooner. Essentially my iframe app routes to different locations through some sort of event. Each route, while it does not impact the parent url, will add a new entry to the browser history (which is normal browser behaviour). The iframe app is designed upon page load to run through a couple routes, thus adding to the browser history, and making it appear like each parent page navigation was doubled.
The question now becomes, is there a way to prevent each route execution from adding the browser history?
UPDATE:
$location.replace() seems to be the only solution I can find. The app makes use of $location.path() a lot to trigger a new route; so I've modified it to be $location.path().replace(); This will replace the current history entry instead of adding a new one.

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

angularjs technique for login then redirecting to dashboard page

I'am doing my first AngularJS project with ASP.NET Web API backend. What I am trying to do is, whenever a user visits www.mydomain.com, a login page (index.html) will displayed. After successfull login, he will be redirected to the dashboard.html (this is the shell page, partial views go here). My project structure is shown below-
I am confused about some issues:
Is this the best/common practices what i am trying to do in above?
As because dashboard.html is the main page, should i place app.js on dashboard.html?
If i put app.js on dashboard.html, will index.html (login page) have another app.js (i.e. loginApp.js)?
How should I manage the login state i.e. IsUserLoggedId, UserId etc in angular part?
This question may be silly. I googled, but did not find any example/article addressing such issue.
Would you please help?
Thank you in advance.
I am not sure how ASP.NET deals with it, but to my knowledge ASP.NET is just a server side framework whereas AngularJS is client side framework.
These two framework solve different problem, but has some overlapping features.
If you start using angularjs, then most of the time you will deal with the term "Single Page Application (SPA)".
There are different approaches in how you can handle the url redirection after login. I will just show you two example. There are many more how you can handle the user authentication and session.
First Approach:
In SPA, most of the time browser will change the url route and state directly in the page itself without making the entire page request from the server.
With that said, your dashboard.html will most likely be come a static template file which will be loaded from the browser directly. (i.e. the server does not dynamically parse the dashboard.html but only serve as a static file). Upon the user login, the angularjs will fire a asynchronous HTTP request into the ASP.NET authentication end point. A successful login may return a token to the browser, and the client will use it to manage the user session. At the same time, the Angular will have to change the route to /dashboard/. Notice that that the entire flow happens transparent to the user, it does not fire a full page HTTP request.
Second Approach:
Alternatively, if you choose to redirect from the server, you will have to send a HTTP Redirect 302. and since HTTP redirect will eventually call make a full HTTP request to /dashboard/, and it will then have to reload and bootstrap the angular app.js from the browser again. In this case, the user will have to wait for the dashboard page to be processed by the server upon login
Issues:
Is this the best/common practices what i am trying to do in above? there are many approaches, I think it is best to find the one that works for you. If you have a RESTful API, then you might want to have a look at the SPA approach in more detail.
As because dashboard.html is the main page, should i place app.js on dashboard.html? in SPA, you don't need to load app.js twice. but if you use the second approach, you have to reload the app.js again.
If i put app.js on dashboard.html, will index.html (login page) have another app.js (i.e. loginApp.js)? depends on your approach as stated above
How should I manage the login state i.e. IsUserLoggedId, UserId etc in angular part? Authentication Strategy, UNIX style authorization
There are more official guide that can help AngularJS Developer Guide.
Hope this helps you to integrate with the ASP.NET authentication mechanism.
you should have multiple shell pages. this link can help you...
refer to Multiple Shell Pages part.

Resources