I'm studying in backbone.js and I like the routing system. But all users of my site can see there requests, like: http://example.com/#/projects and so on.
How can I hide the routing from a browser's url bar but use that cool backbone feature?
I'm not 100% sure what you want, but if you are asking to remove everything after your domain
and keep http://mysite.com in the address bar, without the hashes (#projects/10) i think you will be dissapointed.
as far as i know, you cannot remove that, since the history and the routing depend on those hashes, thanks to that part of the url, it knows which route you are trying to fetch.
however, it is possible to remove the /#/ part... and make it http://mysite.com/projects
for that you need to use pushstate in the router like this:
Backbone.history.start({pushState: true});
You can put your whole website in an iframe 100% width/height of the page and have your address bar always show root URL...
It will work though it will kill the whole idea behind routes which are supposed to give users fast access to all the states of the app directly with the URL and make any route in your app be bookmarkable and shareable.
Though in the end it's your call :) if you think it's the bet for your app - you know best!
Related
I'm working on a React web app with an Asp.Net Core + Typescript back-end. The routing is on the front-end, managed by the React-Router v4. Everything is working fine so far.
By the way, there are cases where I need (I want) to redirect the routing by the server instead to let it to the browser logic. For instance, I want to force the redirection to a certain page when a cookie is not present or expired.
As just for instance, if I use something like <Redirect to="/reserved" /> the React.Router does its best: routes toward the "reserved" page, but that's not what I want. I need this path supplied to the server, i.e. kind of bypassing the front-end routing.
In such cases, the solution I found is to set the desired path as follows:
window.location.href = '/reserved';
That seems sending the new path request straight to the server with no (apparent) involvement with the React.Router. Apparently, everything works fine, as I expect.
The question is: is it a reliable way to achieve the desired behavior, or it looks much likely a hack (and I should avoid it)?
Within the context of a single-page application (SPA), regardless of the framework or technology you are using, setting window.location explicitly is a perfectly fine way to leave the routing control of the SPA and force the browser to make an actual HTTP request for that new route.
Doing so of course means that the whole page will unload, so when doing that, you are leaving your SPA. If that target URL then loads the same SPA again, this will usually be distracting to the user. That is why common SPA router implementations will intercept route changes and handle them through their own routing instead of having the browser make an actual request.
You should check your router’s documentation to see if you can add some router guards that allow you to verify things on load or on route changes, so you can navigate the user away to some forced location.
If that target URL is not part of the SPA, then of course setting window.location is perfectly fine. It’s certainly not a hack but rather just the proper way to change the location without going through the SPA’s 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.
I was setting up a simple router in Backbone.js while I noted an issue, I googled for a long time and found some solutions.
The problem is that whenever I navigate to a url, this url will work while I'm inside the app itself, but once you bookmark it and return it will obviously return a 404 since that page doesn't exist.
Backbone.history.navigate('test', true);
This will navigate to http://www.domain.com/test, which is great, but once you refresh the same URL it returns a 404.
There are ways to get this to work with using a specific .htaccess file, but I'm building this inside an existing website, so I can't use this.
Is there a way in Backbone.js to revert to just using hashbangs? My url would then look like this `http://www.domain.com/#!/test
This might not be the cleanest URL, but at least it will work.
Or am I just missing something obvious here? It can't be that I'm the only person with this problem.
You're using pushState according to your url, so you've got 2 main options:
stop using pushState when starting Backbone history (which would be the equivalent of using a hashbang, except for SEO)
have your server return a page for every URL your app generates (it can be the same exact page)
In the second case, if you don't care about SEO, you can have a catch all rule always returning (e.g.) index.html containing your Backbone app. When you start Backbone's history, it will lokk at the URL and navigate to the proper page (although you might have a "double render" effect).
If you're worried about SEO, you need to return page content for SEO along with your Backbone app.
I am currently using the Backbone router for my SPA. It sort of works OK, but I am having a number of small issues:
The problem is - I want to either have pushState navigation or none, meaning - app state gets executed (when I pass the "initial" URL to the router or I trigger a route via JS), but the address bar doesn't change. I don't want the hashChange fallbacks for IE9. It will work just fine if IE9 does not get the back button and the changing address bar, but still retains navigation state within the application. I can then show the users a URL which they can bookmark and the server will route that page and the app state will bootstrap based on the initial URL. The address bar not changing in IE during in-app navigation is a compromise I am willing to accept.
Another problem that I have is that I am using navigate(url, {trigger: true}) for my intercepted HREFs, and the back button doesn't work (does nothing). But I really need to change app state on forward/back navigation, even if it gets rebuilt for that particular URL - I'd rather rebuild the state.
What are my options in terms of routers that I could use? Like I said, I don't want to have hashbang fallbacks (meaning - I only want to have ONE way of representing URLs in the application, period).
What should I use? Director.js? History.js? There seems to be quite a number of router/history libraries out there but which one is the closest to what I'm looking for?..
Supposing you have Modernizr around scanning the HTML5 history support, if I understand well wouldn't a fast solution be, in your main layout js file, to add as event
'click a' : "navigate"
and add the function navigate to this layout as follow
navigate : function(e){
if(!Modernizr.history) document.location.href = $(e.currentTarget).attr("href");
},
to optimize, you could of course bind that only if history is not supported,don't forget to include "modernizr" in your layout. Hope this is an interesting answer for you..
Not sure what i am missing, but I have pushState working on my Backbone based app, where I could click around and have my URL look like www.example.com/route_specified, however if i try to go directly to that page it shows up as not found. If I do www.example.com/#route_specified it works, and quickly changes back to www.example.com/route_specified on the address bar
I am guessing i need to do something in Apache to handle this and make sure that all calls resolve to the index or something like that, but can't find explanation.
Correct. Think about it this way without pushstate enabled. Your server is still trying to serve the page at that route. Since it cannot find the specified document at that location, it throws a 404.
Technically speaking, your server should still produce some sort of result at the url location, then have Backbone take over. In it's simplest form, this is called progressive enhancement. The server should still serve some sort of static page with critical info, which will eliminate issues you will have with SEO. Work your site/app with javascript disabled, serving only the relevant data. Then have Backbone takeover. I have just come across Mashable's redesign, and they integrate progressive enhancement extremely well with Backbone.
If SEO is not a concern, you could always redirect the user to the index page. Just remember that search engines will only index your app page then. If your content is being served dynamically, there wont be any data to index.
Hope this helps.
Thanks
Tyrone