Simple, lightweight routing for web browsers

Related tags

Routing pathjs
Overview

PathJS

PathJS is a lightweight, client-side routing library that allows you to create "single page" applications using Hashbangs and/or HTML5 pushState.

Features

  • Lightweight
  • Supports the HTML5 History API, the 'onhashchange' method, and graceful degredation
  • Supports root routes, rescue methods, paramaterized routes, optional route components (dynamic routes), and Aspect Oriented Programming
  • Well Tested (tests available in the ./tests directory)
  • Compatible with all major browsers (Tested on Firefox 3.6, Firefox 4.0, Firefox 5.0, Chrome 9, Opera 11, IE7, IE8, IE9)
  • Independant of all third party libraries, but plays nice with all of them

Using PathJS - A Brief Example

function clearPanel(){
    // You can put some code in here to do fancy DOM transitions, such as fade-out or slide-in.
}

Path.map("#/users").to(function(){
    alert("Users!");
});

Path.map("#/comments").to(function(){
    alert("Comments!");
}).enter(clearPanel);

Path.map("#/posts").to(function(){
    alert("Posts!");
}).enter(clearPanel);

Path.root("#/posts");

Path.listen();

Documentation and Tips

Any of the examples above confuse you? Read up on the details in the wiki.

Examples

You can find examples on the official Github Page.

Running Tests

To run the tests, simply navigate to the ./tests folder and open the HTML file in your browser. Please note that the HTML5 History API is not compatible with the file:// protocol, and to run the tests in the tests/pushstate folder, you will need to run them through a webserver such as nginx or Apache.

Next Steps

  • Adding support for "after" callbacks
  • Deprecating the "enter" callback in favour of "before"

Pull Requests

To make a pull request, please do the following:

  • Mention what specific version of PathJS you were using when you encountered the issue/added the feature. This can be accessed by doing Path.version in a debugger console
  • Provide a pastie or gist that demonstrates the bug/feature
  • Make sure you update the test suite with your changes. All tests must pass
  • Make sure to update the minified version of the source
  • Do not modify the Path.version attribute. I will modify that manually when merging the request

Disclaimer

This code is provided with no warranty. While I strive to maintain backwards compatibility, the code is still under active development. As this is the case, some revisions may break break compatibility with earlier versions of the library. Please keep this in mind when using PathJS.

Copyright and Licensing

Copyright (c) 2011 Mike Trpcic, released under the MIT license.

Comments
  • HTML5 pushState triggers path dispatch for initial page load

    HTML5 pushState triggers path dispatch for initial page load

    When using the HTML5 history mode, like in the "HTML5 Basics" example at http://mtrpcic.github.com/pathjs/html5_basic.html, the initial page load also triggers a Path dispatch. I realise that in a lot of cases this is desirable, but I feel there should be a way to disable this.

    A common use case for Path is using it to catch links out and replace them with ajax requests that replace partial content: The initial page is rendered fully and every subsequent click on a link fetches just the content that is new.

    However, if you use Path in HTML5-mode, it also triggers an AJAX request for the first request, essentially causing duplicate work. Of course there are ways to hack around this, but it seems to me there should be a more elegant way to solve this.

    I have given a simple example below. On the first visit of /pages/test, it says "loading..." and fires off an XHR to /partials/test. This is unnecessary, as the content of /pages/test already contains what it needs prerendered by the server.

    Path.map("/pages/:page").to(function(){
    
        $("#content").html("loading...");
    
        $.ajax({
          url: "/partials/"+this.params["page"], 
          timeout: 2000,
          success: function(data) {
            $("#content").html(data)
          }
        });
      })
    
      $(document).ready(function(){
        Path.history.listen();
    
        $("a").click(function(event){
          event.preventDefault();
          Path.history.pushState({}, "", $(this).attr("href"));
        });
      })
    
    opened by micheljansen 24
  • Syntax error, unrecognized expression

    Syntax error, unrecognized expression

    var routes = [
        "#/home",
        "#/obstacles",
        "#/obstacles/:id"
    ];
    
    Path.map(routes[2]).to(function(){
        app.route(this.path, this.params["id"]);
    });
    

    When looping through an array of routes, firefox - firebug throws a

    • uncaught exception: Syntax error, unrecognized expression: id

    Any reason why this is happening?

    opened by Zettersten 8
  • Support multiple actions per route

    Support multiple actions per route

    Hi Mike,

    I'd like to get your thoughts on this. In my application it's necessary for independent modules to map all of their own routes so they can each act independently. This patch enables this so that each call to Path.map pushes the handler onto an action stack, rather than overwriting it.

    
    Path.map('/awesome').to(function() {
      console.log('this is awesome');
    });
    
    Path.map('/awesome').to(function() {
      console.log('this is ALSO awesome');
    });
    
    Path.history.navigate({}, '', '/awesome');
    // this is awesome
    // this is ALSO awesome
    

    Before this patch, only the last callback would have been executed.

    opened by dandean 6
  • Assumes that parameters do not contain '/'

    Assumes that parameters do not contain '/'

    I Agree that its a fair assumption, but I had to write a workaround for this for my scenario. The simple scenario is that my tabs are hierarchical in naming.

    I'm attaching the workaround i currently use in the match function. I know it is not the best code, but it works. It'd be great if you could support this by default.

    
    'match': function (path, parameterize) {
            var params = {}, route = null, possible_routes, slice, i, j, compare;
            for (route in Path.routes.defined) {
                if (route !== null && route !== undefined) {
                    route = Path.routes.defined[route];
                    possible_routes = route.partition();
                    for (j = 0; j < possible_routes.length; j++) {
                        slice = possible_routes[j];
                        compare = path;
                        if (slice.search(/:/) > 0) {
                            for (i = 0; i < slice.split("/").length; i++) {
                                if ((i < compare.split("/").length) && (slice.split("/")[i].charAt(0) === ":")) {
                                    params[slice.split('/')[i].replace(/:/, '')] = compare.split("/")[i];
                                    compare = compare.replace(compare.split("/")[i], slice.split("/")[i]);
                                }
                            }
                        }
                        if (slice === compare) {
                            if (parameterize) {
                                route.params = params;
                            }
                            return route;
                        }
                    }
                }
            }
            if (parameterize) {
                var maxMatchedRoute = null, maxMatches = 0, 
                    arr2 = path.split('/');
                for (route in Path.routes.defined) {
                    if (route !== null && route !== undefined) {
                        var arr1 = route.split('/');
                        if (arr2.length < arr1.length) {
                            continue;
                        }
                        var len = arr2.length;
                        var matches = 0;
                        for ( var i = 0; i < len; i++) {
                            var ele1 = arr1[i], ele2 = arr2[i]
                            if (typeof ele1 !== "undefined"
                             && typeof ele2 !== "undefined" 
                             && ele1 === ele2) {
                                matches++;
                            }
                        }
                        if (matches > maxMatches) {
                            maxMatches = matches;
                            maxMatchedRoute = route;
                        }
                    }
                }
                if (maxMatches) {
                    var pathArray = maxMatchedRoute.split('/');
                    var i = 0, last = null;
                    for (i = maxMatches; i < pathArray.length; i++) {
                        var slice = pathArray[i];
                        if (slice.charAt(0) !== ':') {
                            return null;
                        }
                        last = slice.substr(1);
                        params[last] = arr2[i];
    
                    }
                    while (i < arr2.length) {
                        params[last] += '/' + arr2[i];
                        i++;
                    }
                    Path.routes.defined[maxMatchedRoute].params = params;
                }
                return Path.routes.defined[maxMatchedRoute];
            }
            return null;
        }
    

    Thanks, Sujay

    opened by SujayKrishna 4
  • default path

    default path

    In some previous documentation it seemed like there a default function you could set if no paths matched. I want to use this but it seems to be missing in the current version. I tried using rescue for this but it doesn't work in the same way (doesn't set the window location)

    Is there any way to apply a default function to all paths?

    Maybe one way to do this is to include the same wildcard functionality as in rails routes using *

    Path.map("/*path")

    opened by aaronchi 4
  • Bugfix, and test changes

    Bugfix, and test changes

    The code was crashing when I entered a page where the #hashvalue was unspecified, and I had a rescue function defined.

    The code to fix it was used elsewhere, so I moved it to a helper function, and called it from both.

    Tests are updated, but currently there is no test for the Path.root function, because testing the error I had could not be done at the same time. Sometime I will add another test.

    opened by alexhughson 4
  • Optional parameters

    Optional parameters

    This would help DRY out some code so that someone doesn't have to duplicate route maps.

    For example ( this is how ExpressJS does it on the server side ):

    Path.map("#/venues/:sortorder?").to(function{
        // Then we can do stuff like fn(this.params['sortorder'] || 'default');
    });
    

    I would happily fork it and submit the changes to make this work, however my javascript-fu is weak. Looking at the code, I couldn't tell how easily this could be accomplished. So this is just a feature request.

    opened by jchaney 4
  • Example page view source doesn't work in Chrome

    Example page view source doesn't work in Chrome

    On http://mtrpcic.github.com/pathjs/html5_basic.html there is an instruction to view the source of the page to see what's going on. That won't work in Chrome after clicking on any of push state links, eg Users.

    View source in Chrome opens a new tab to a view source url, for example:

    view-source:http://mtrpcic.github.com/users
    

    This does a request for http://mtrpcic.github.com/users, then shows the source of the GitHub 404 page.

    opened by DouglasLivingstone 3
  • Open link in new tab

    Open link in new tab

    Hi,

    I'm trying to fix an issue, but I'm a little bit lost and maybe you thought about this already.

    When you want to open a Path.js link in a new tab you can do it rightclicking in the link and selecting "Open In New Tab" in the Browser, but it's not working clicking on the link with the mousewheel at windows or doing Click + command on Mac OS X.

    Do you know why is it happening?

    Best regards!

    opened by dolarsrg 3
  • Execution on page load only in Chrome

    Execution on page load only in Chrome

    I'm using PathJS's HTML5 pushState capability in an application. I want to be able to trigger actions not only when the user explicitly clicks on a link/form element, but also when the user goes to that page. For example: If the user goes to example.com/do/something, that should be the same as if they went to example.com and clicked a link that triggered "do/something." This is working for me in Chrome, but not Safari, Firefox, or Opera. Even if this is not the intended behavior, it is an inconsistency.

    Is this a problem with PathJS or the implementation of the History API? I feel like it must be the former, since Backbone.js can do what I'm trying to do, right?

    Thanks, Gerard

    opened by GRardB 2
  • Form posts

    Form posts

    Hi,

    sorry for using an "issue" like this but can't find any contact info. How are you supposed to handle form posts? Can't find any route setup that will listen on POSTs.

    //Daniel

    opened by danielwertheim 2
  • A problem with the function match

    A problem with the function match

    https://github.com/mtrpcic/pathjs/blob/2fe037d6b2d54ab70e0490b90cce16bd5fce9cca/path.js#L56

    Paths:#test1/id , #test2/name/desc

    Go to #test2/1/2 the params is {id:1,name:1,desc:2} not {name:1,desc:2}.

    opened by liujian10 0
  • Incomplete documentation

    Incomplete documentation

    I love this framework and its handy that a typescript definition file exists for Path.JS . My problem is the getting started page in the wiki does not cover some of the other functions such as Path.Match() so if anyone could find me a way to learn the API completely, that would be perfect.

    opened by DoubleCouponDay 0
  • Grunt build and proper bower.json

    Grunt build and proper bower.json

    Even though PathJS available on bower, it does not have proper bower.json with main:{} section. Also the bower.json files are missing on git repository. This is the restructured version of Path JS with proper bower configurations and with a grunt build.

    opened by fahimfarookme 0
  • Relative urls using pathjs

    Relative urls using pathjs

    I'm having trouble with relative image urls and links when using pathjs and routing. I am developing in http://localhost/app and on that page, I have relative urls for images (i.e. src="images/some.jpg"). When I navigate to some route (i.e. "test/route/1"), the url changes to http://localhost/app/test/route/1, which is expected. But if I refresh that page on that route, the image no longer works. It is looking for the image at http://localhost/app/test/route/1/images/some.jpg (incorrect location) instead of http://localhost/app/images/some.jpg (correct location). Is there a way to use relative urls for links and image sources when routing with pagejs?

    opened by docmattman 0
  • Path with #anythyng/1/1/1

    Path with #anythyng/1/1/1

    Has anyone had trouble with path: #anythyng/1/1/1

    It is used:

    Path.map("#anything(/:parameter1)(/:parameter2)(/:parameter3)").to(function(){
      //anything
    });
    

    But he doesn't know this path is a valid path.

    opened by vinimarques 0
Owner
Mike Trpcic
Mike Trpcic
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
Javascript client for Sanity. Works in node.js and modern browsers (older browsers needs a Promise polyfill).

@sanity/client Javascript client for Sanity. Works in node.js and modern browsers (older browsers needs a Promise polyfill). Requirements Sanity Clien

Sanity 23 Nov 29, 2022
This package generates a unique ID/String for different browsers. Like chrome, Firefox and any other browsers which supports canvas and audio Fingerprinting.

Broprint.js The world's easiest, smallest and powerful visitor identifier for browsers. This package generates a unique ID/String for different browse

Rajesh Royal 68 Dec 25, 2022
1KB lightweight, fast & powerful JavaScript templating engine with zero dependencies. Compatible with server-side environments like node.js, module loaders like RequireJS and all web browsers.

JavaScript Templates Contents Demo Description Usage Client-side Server-side Requirements API tmpl() function Templates cache Output encoding Local he

Sebastian Tschan 1.7k Jan 3, 2023
It shows how to escape cross-origin issues for web client and API server using CloudFront routing.

AWS CloudFront의 URL Routing을 이용한 Web Client 및 API Server 구현 여기서는 CliendFront의 URL Routing을 이용하여 Web Client와 API Server를 구현하고자 합니다. Web Client는 Amazon

John Park 4 Nov 20, 2022
A tiny foundation that providing nested state-based routing for complex web application.

StateMan stateman: A tiny foundation that provides nested state-based routing for complex web applications. stateman is highly inspired by ui-router;

ZhengHaibo 390 Dec 20, 2022
Declarative routing for React

React Router Declarative routing for React Docs View the docs here Migrating from 2.x/3.x? 3.x docs 2.x docs Packages This repository is a monorepo th

React Training 49.3k Jan 9, 2023
RESTful degradable JavaScript routing using pushState

Davis.js Description Davis.js is a small JavaScript library using HTML5 history.pushState that allows simple Sinatra style routing for your JavaScript

Oliver Nightingale 532 Sep 24, 2022
Example project implementing authentication, authorization, and routing with Next.js and Supabase

Magic Link Authentication and Route Controls with Supabase and Next.js To run this project, To get started with this project, first create a new proje

Nader Dabit 134 Dec 11, 2022
Distance Matrix Routing App with Tom Tom API

Distance Matrix Routing App Have you ever wanted to build a delivery app that will calculate the shortest distance from each drop off spot? Get extra

Ania Kubow 31 Dec 13, 2022
Hooks lifecycle (II), routing with RRD v6, Context API

day-2 Hooks lifecycle (II), routing with RRD v6, Context API Hooks lifecycle Es posible asociar un efecto a cada una de las fases del ciclo de vida de

null 2 Dec 17, 2021
A boilerplate for Vite, React, Tailwindcss with filesystem based routing

Template This is a React, Vite, Tailwind template. It features filesystem based routing, similar(ish) to Next.js. It also formats and serves markdown

Chris Dzoba 8 Dec 28, 2022
"Nuxt-like" routing in Quasar projects

Quasar App Extension auto-routing "Nuxt-like" routing in Quasar projects Install quasar ext add auto-routing Quasar CLI will retrieve it from the NPM

Luke Diebold 19 Dec 2, 2022
Demo showing how to lazy load a component in Angular without routing!

WidgetDashboard This project was generated with Angular CLI version 13.2.6. Development server Run ng serve for a dev server. Navigate to http://local

Andy Bond 3 Mar 25, 2022
Read Blog. This is also a practical project. Working with APIs more and Routing and many new things.

React blog This is a React blog that created with a custom API. We serve the API in our system and run blog with it. Goals of this project In this pro

AmirHossein Mohammadi 7 Jul 25, 2022
This package allows you to show a placeholder-component while inertia fetches the content of ne new page while routing

inertia vue placeholder middleware This package adds a component placeholder middleware for inertia vue. instead of the InertiaProgressBar you can sho

null 6 Jul 24, 2022
Example code for MFE routing, shared state, build-time & runtime deploy video

Turborepo starter with pnpm This is an official starter turborepo. What's inside? This turborepo uses pnpm as a packages manager. It includes the foll

Jack Herrington 42 Nov 2, 2022