This is a followup to my earlier question, Backbone routing/history issue with Jekyll static pages.
I'm building a simple, static site with Jekyll and using Backbone to do some routing. All of my pages are separate HTML files. I handle navigation by watching my <a> elements for clicks, and using jQuery.get to load up the new page and replace the content. A bit unusual, I know, but I want a single page in order to provide smooth transitions and preserve my webfonts.
The issue is that when I start from any page other than my root url — let's say /page1 — navigate around, and then use the browser's back button to return to my first page, I get a 404: /page1/page1 not found. Here's some example navigation:
localhost/page1/ <- entered into address bar
localhost/page2 <- linked from an <a>
localhost/page1 <- linked from an <a>
localhost/page3 <- linked from an <a>
localhost/page1 <- clicked back button; works fine
localhost/page2 <- clicked back button; works fine
localhost/page1/ <- clicked back button; 404 at /page1/page1
Note that returning to page1 from deeper within the history works fine; it's only my starting route that gives me grief. I think it might have to do with the trailing slash appended by the browser when I manually enter that first URL, but I'm not sure how to resolve this.
I posted my relevant backbone code in this JSFiddle. As you can see, my router is initialized with silent: true and root: '/'.
Not sure what to do here — been banging my head against the wall for weeks!
Related
I am working on a site that is transitioning to Angular - it uses Angular for single page application navigation and a new feature I'm currently working on is written entirely in Angular.
The rest of the site takes navigation results and returns them through the SPA model, the feature I'm working on runs entirely in a single page, but in order to make links shareable and bookmarkable it changes the URL in relation to the current state of the page.
So when someone selects a new subsection of the new feature, we have some code like this in the subsection service:
function setLocationForSubsection(subsection) {
var path = subsection.id ? "subsections/" + subsection.id + "/" + subsection.urlSlug : "";
$location.path("/section/" + path).search({}).skipReload();
};
If they follow a link to elsewhere in the site ( which goes through a $stateProvider.state('all', { url: '*urlPath?id', controller... pattern ) it works correctly.
If they then hit the back button, they come back to the correct page and setLocationForSubsection is called. If they click on the same link outside of the subsection again, nothing happens.
So this course of action occurs:
/section/2/subsection-name <- works.
/news <- works
back button ( /section/2/subsection-name ) <- works
/news fails
As far as I can tell, the problem arises because the location path setting fails to push the location into the angular state in this situation, so as far as angular is concerned it is still on /news and so when I try to navigate back there, it doesn't pick it up as a navigation event. I have tried using $window.history.pushState(null, 'any', $location.absUrl()); manually, but it doesn't seem to make any difference. If I drop the skipReload call it works but reloads the contents of the page, which is superfluous in this case. I'm using that approach for now, but I would like to know if there is a better option.
Is there a way to tell angular that a state change has happened in this case?
I'm using Angular UI router in my app. This is what I'm doing.
A main view contains a child view and a div container for "pagination"
By default, initially, a first set of contents is loaded
When a user clicks on "next page", next set of contents is loaded (with the URL also being changed to /content/2 (where 2 indicates the next page number)
All is working well, but each time the contents are loaded, it goes "blank" before it loads. So it seems like it's reloading the view (which is obvious).
What I would like to do is reload the content without having that "blank" page. How can I achieve this?
At first thought, I think you could you the same approach as infinite-scroll, which is what I'm using. So you make a GET request to the server to get new content and push it to the list on clicking 'next'. However, since the URL changes also. This will cause the controller to be reloaded. You can actually bypass this by setting reloadOnSearch to false.
I have an unusual question.
I have this old page that I want to convert to angular.js.
http://transience.me/TD/
I have 5 pages worth of html loaded on one page and the only visible portion is the part that has been navigated to. i.e. home is at x position 0, about is at x position, 1024, projects is at x position 2048, etc...
Right now though there's no way to link to the individual sections. You have to land at the home and then navigate to the section you want to visit.
However I want to add a deep linked url: url/#/home, url/#/project, etc.. to correspond with the navigation which triggers a change in page position.
Is there a way to link the router in angularjs to a directive so that instead of loading an html template it triggers a new dom behavior?
Thanks for any help!
I think ui-router would help you greatly.
It uses a $stateProvider which allows you to change the url without reloading the entire template. You can add transition effects and to move between pages and it will keep all back buttons, page refreshes, etc.
Check out the ui-router demo
let's say that I have two "pages" (endpoints) on a chaplin.js site
the routes:
match('', 'first_controller#show');
match('second_view', 'second_controller#show');
and two links:
Go to home
Go to Second
the generated urls are "correct":
mysite.com/something/ (home)
mysite.com/something/second_view (second view)
(notice that I'm not on the root of the site). When I start the application at "home" and then click the "Go to second" link i get correctly redirected to the second view, everything gets tendered correctly and the url on the browser changes to mysite.com/something/second_view
But then I cannot refresh the navigator since my webserver will try to reach a second_view folder instead, and I'll get a 404.
What i need is to always generate the urls using a # like in backbone, something like mysite.com/something/#/second_view.
BTW: that last link works but chaplin deletes the # (like a redirect)
Maybe I need to configure something? or change something on the ùrl`helper, I couldn't find anything in the docs. Any Ideas??
Thxs
Backbone itself allows this functionality out of the box, through
Backbone.history.start({pushState: false})
(the default)
You can see the startHistory call here.
You just have to pass this options object as a second parameter to initRouter in your Application :
this.initRouter(routes, {pushState: false});
I am writing something like a registration process containing several steps, and I want to make it a single-page like system so after some studying Backbone.js is my choice.
Every time the user completes the current step they will click on a NEXT button I create and I use the router.navigate method to update the url, as well as loading the content of the next page and doing some fancy transition with javascript.
Result is, URL is updated which the page is not refreshed, giving a smooth user experience. However, when the user clicks on the back button of the browser, the URL gets updated to that of a previous step, but the content stays the same. My question is through what way I can capture such an event and currently load the content of the previous step and present that to the user? Or even better, can I rely on browser cache to load that previously loaded page?
EDIT: in particular, I'm trying something like mentioned in this article.
You should not use route.navigate but let the router decide which form to display based on the current route.
exemple :
a link in your current form of the registration process :
<a href="#form/2" ...
in the router definition :
routes:{
"form/:formNumber" : "gotoForm"
},
gotoForm:function(formNumber){
// the code to display the correct form for the current url based on formNumber
}
and then use Backbone.history.start() to bootstrap routing