Coder Social home page Coder Social logo

navigo's Introduction

Navigo

A simple dependency-free minimalistic JavaScript router

npm downloads size

Selling points

  • Dependency free
  • ~10KB minified, ~4KB gzipped
  • Based on History API so it does update the URL of the page
  • Supports hash based routing too
  • Simple mapping of route to a function call
  • Parameterized routes
  • Navigating between routes
  • Hooks (before, after, leave, already)
  • Not-found and default handler
  • Easy integration with HTML links via data-navigo HTML attribute

Installation

Drop the following into your page:

<script src="//unpkg.com/navigo"></script>

or via npm/yarn:

> npm install navigo --save
> yarn add navigo -S

Quick start

import Navigo from 'navigo'; // When using ES modules.

const router = new Navigo('/');

The constructor of the library accepts a single argument - the root path of your app. If you host your project at https://site.com/my/awesome/app, your root path is /my/awesome/app. Then you have to define your routes.

router.on('/my/awesome/app', function () {
  // do something
});

At the end you have to trigger the resolving logic:

router.resolve();

After that when you need a page change call the navigate method. This one changes the URL and (by default) triggers resolve.

router.navigate('/about');

Add data-navigo attribute to your page links and they'll be transformed into navigate callers.

<a href="/about/contacts" data-navigo>Contacts</a>

Checkout the online playground to see it in action.

Development

> yarn dev

Building

> yarn build

Tests

> yarn test
> yarn test-watch

MISC

navigo's People

Contributors

abradley2 avatar andrewheekin avatar builtbylane avatar ceg-ecoles avatar duncank avatar eazari avatar egorshulga avatar ejez avatar emflores avatar finppp avatar fjorgemota avatar fr6 avatar havunen avatar huevoncito avatar krasimir avatar kzelda avatar mathiasrw avatar milesje avatar nyholm avatar oxbambooxo avatar sergiopvilar avatar smallhadroncollider avatar teawithfruit avatar tombyrer avatar xtephan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

navigo's Issues

Current state / statechange

  • Is there a way to retrieve the current route state? History.state appears null...
  • Similarly, is there an event handler for route changes? Something triggers when the state changes, like routestatechange or something?

Preserve trailing slash for routes

Hi there, great work! How can I achieve that, when I navigate to an url using router.navigate('/products/list/');, the trailing slash stays in the route? I would need this to have consistent urls, both from the server as well as from the js app.

Include pause in navigate

Instead of having to .pause the router before .navigate in order to skip resolving, can the resolve/ paused state be passed in as a boolean to .navigate()?

For eg., instead of having to do

router.navigate('/path');
router.pause(false);

It will just be
router.navigate('/path', false);

I find the .pause(false) API to be extremely awkward.

Hash in URL becomes part of param

If I have the URL https://mysite.com/page#, and a route defined as /:id, then params.id is page#. Should it just be page? I.e. the # should not be considered part of the param?

I'm running into this issue because Chrome automatically appends # to my URL after redirecting from another page that has # in its URL

Double event handler after updatePageLinks()

Hey, first of all thank you for this simplistic but very helpful router :)

I've got a problem where updatePageLinks doesn't work as intended in the minified version. It somehow adds multiple (in my case even different) click handlers to an element with data-navigo attribute. I think it is because in the minified file link.hasListenerAttached isn't set to true correctly. The different click handlers could be because I'm exchanging the href attribute though...

In the non-minified version everything works fine though

Hooks?

Hey guys,

Not a bug but rather an idea. I was thinking about adding hooks to this router and was wondering what you think. With hooks you could have page transitions or initialize page specific libraries and things like that.

I imagine they could be called like this:

//global hooks that run before and after all routes`
 Router.beforeRun(function () {
     //do stuff
 });
Router.afterRun(function () {
    //do stuff
});
Router.beforeLeave(function () {
    //do stuff
});
Router.afterLeave(function () {
    //do stuff
});

//route specific hooks
Router.beforeRun('myAwesomeRoute', function () {
    //do stuff
});

///etc...

Thoughts @krasimir? If you're open to the idea, we can talk design and then I can submit a draft. Let me know.

Thanks,
Daniel.

Have title option for routes config

Browser history is helpful but would be better if there were optional custom titles for each route. This would be a lightweight feature add-on but something very useful built-in to the router. Currently I change it in the route handler. Since navigo is already handling history state, this might be something useful for others. Is this something anyone else is interested in? I'd be willing to make the changes if we could agree on a reasonable syntax.

Push version tags?

There's a version number in package.json, but Bower looks for git version tags in the repository, so specifying a version to install with Bower isn't working. Could you push version tags to the repo?

onpopstate event

Hello,

Is it possible to latch onto the window.onpopstate event Navigo uses for forward/back buttons? I can use it easily enough, but then navigo stops working :)

I have a page transition in this project, so it's not possible to re-render the menu in this case. I'm manually updating the .active class on the menu with jQuery, which works fine, except for the forward/back browser buttons.

Was thinking a custom event could be fired onpopstate with the window.location.pathname passed to it, but interested in your thoughts.

Thanks.

All routes are greedy?

Hi @krasimir - thanks for your work Navigo, really liking it so far.

I have encountered one issue that I wanted to raise , and that is that all routes seem to be greedy. Meaning that, given a route of /foo, the findMatchedRoutes function will return a positive match for the path /foo/bar, regardless of whether or not a wildcard is used. I believe this RegExp is to blame: https://github.com/krasimir/navigo/blob/master/src/index.js#L5.

Was this an intentional design decision? If not, I am happy to open a PR to fix this issue. Regardless, probably should add a spec to cover this case.

Callback don't fire if navigating between some URL and `/`, but URL is changing

The bug is reproducing here with Navigo 2.3.0:

https://jsbin.com/ximekug/edit?html,js,output — source code
https://output.jsbin.com/ximekug/ — there you can see URL changing

With each click text under the list should change according to link.

Steps to reproduce:

  1. Click “Task 1” → correct
  2. Click “Home” → correct
  3. Click “Task 1” → fail

URL changed, but text under the list didn't.

Also can be reproduced this way:

  1. Click “Task 1” → correct
  2. Click back button in a browser → correct
  3. Click forward button in a browser → fail

If we click “Task 1” → “Home” → “Task 2” → “Home” → “Task 1” → ... It works as expected.

Click handler...

Like the simplicity of your router, but it would be nice to have a simple click handler to intercept <a href='/route'> clicks. Is that on the roadmap?

Navigo triggers resolve for hash with hash navigation disabled

Hey, I'm having a problem with Navigo.

I have this url:
http://localhost:3000/users/foo#section1

In this page I have some tabs (section1, section0) when I click any of the tabs and the url changes to, for instance, http://localhost:3000/users/foo#section1 Navigo triggers the resolve even with the hash navigation disabled.

Add changelog

Can you add changelog, please? It doesn't clear what changed in newer versions and should I upgrade.

replaceState

Is there a way to replace the current state, instead of just push via navigate()?

For changing language I'm looking for such functionality, since changing language is not really navigating away from the current content.

Router gets resolved for empty url.

Hi,

First, Thankyou for the simple router. Made my life easy.

I am not reporting a bug but need some help here. This should have been very simple but I am not able to figure out how to differentiate between no query and an unmatched query. I have written a fallback so:
router.on({
'p1' : loadP1,
'p2' : loadP2,
'g1' : loadG1,
's1' : loadS1,
'user' : loadUserPage,
'#': loadLanding
}).resolve();
router.on(function fallback() {
alert('oops!! this page was not found');
}).resolve();
but this get fired even for my landing index.html without any queries at all. I want to fire the fallback for unmatched queries only. I am using hash.

Parameters

It took me while to figure out how to use one parameter as the url. My root url is http://localhost:43088/test-page

router.on(':slug', function (slug) {
// slug is "http:"
});

When the parameter is not the first thing, it works like it should:
http://localhost:43088/example/test-page

router.on('/example/:slug', function (slug) {
// slug is "test-page"
});

This can be fixed with a custom regex /([\w-]+)$/ (Anything [a-zA-Z_-] at least once untill the end of the string)
A better solution would be to exclude the root from the matching process.

Start the router silently

Hi there, it's me again. Is there a way to sart the router silently? Like, without fireing the first route?

pushState - state object support

Hey, thanks for the awesome library :)

Do you have plans to implement support for the state object param of History.pushState()?

My current use case is to save scroll position between pages. The site I'm working on is fully AJAXed so I can persist a variable with the scroll position between page transitions. But, if a user reloads the page, the previous scroll position is lost. So then if they hit the back button, the page scrolls back to the top regardless of where they were previously.

Seems like the cleanest way to do it would be to just push a state object along with the route to router.navigate(path = '', state = {}, absolute = false). I'm happy to open a PR if you like this idea, or defer to you if you already have this feature in the works.

Navigo is not defined

I'm probably just a noob but I dropped in navigo.min.js and Navigo just isn't being found. Both:

var router = new Navigo(root = null, useHash=false);
and
var router = new Navigo();

Is there another component like RequireJS that I'm missing here?

Request: a way to disable hash usage at all

Hi there,
I just stumbled upon this lightweight router library and I'm pretty delighted of how it works. There's only one problem I'm having:

If the browser does not support pushState, the library falls back of using hashes as links. I think it would be nice to have the option to disable that at all, because in most cases that means doubling the logic for routing (especially in backend) - with and without hashes.

I also don't like the idea of my old browser checking five times a second what's the url (I mean I really won't need that, not that it's bad as an idea).

I don't know what's the best scenario for doing it - provide another parameter, add public method, I don't know. But I think it would be pretty nice if it can work.

Поздрави :)

Any differences between Navigo and other routers?

For example, there is an older and smaller in size vanilla router page.js.

What whas the main reason you created another router?
Have you analyzed how Navigo is different/better/worse then other router libraries?

Nevertheless, nice work and your ES6 syntax and export is very appreciated in my build process.

Router is not defined on empty path

let router = new Navigo(null, false);

router
    .on('#/home', controllers.home)
    .on(() => {
        router.navigate("#/home");
    })
    .resolve();

When the path in the browser is empty I get the following error
Uncaught (in promise) Error: (SystemJS) router is not defined(…)

Do you have any ideas why, the module is loaded with systemjs

Named Routes with Before and After Hooks

Is support for hooks and named routes possible?

router.on(
	'/':
		as: 'home'
		uses: (params, query) ->
			console.log 'Router: Home Route...'
			renderHome()
		hooks:
			before: ->
				console.log 'BEFORE'
			after: ->
				console.log 'AFTER'
)

Named routes and URL generation

Hey

I love this router and have used it on a lot of small projects with no issues, thanks! I'm now scoping a larger project, and there's one thing stopping me from using it there (well two related things).

Some example routes:

const trip = new TripController();
router.on({
  '/trip/:tripId/edit': trip.edit,
  '/trip/create': trip.create,
  '/trip/:tripId': trip.show,
  '/trip': trip.index
});

An example for a named route API (using Laravel 5.2 API as inspiration):

const trip = new TripController();
router.on({
  '/trip/:tripId/edit': {as: 'trip.edit', uses: trip.edit},
  '/trip/create': {as: 'trip.create', uses: trip.create},
  '/trip/:tripId': {as: 'trip.show', uses: trip.show},
  '/trip': {as: 'trip.index', uses: trip.index}
});

Then using the custom names, we don't need to hardcode URLs in th views:

<a href="{{ router.generate('trip.show', {tripId: 6}) }}">...</a>

official page doesn't work

Hi, I wanted to let you know the official page doesn't show any content beside the tabs navigation..

I'm on Firefox 50, Windows 7

root path gives me the same behavior with *

I am having trouble with the following code : When I type the following url '/v1/a/b/c', I'd like to match the "not found" handler. Instead, I match the root path that I defined at last ('/'). It's like I would have defined it that way : '/*'.

var router = new Navigo('/v1');

router.on('modify', function () {
    setContent('modify');
})
.on('modify/:name', function (params, query) {
    setContent('name');
})
.on('/', function () {
    setContent('home');
})
router.notFound(function () {
    console.log("not found");
    // called when there is path specified but
    // there is no route matching
});
router.resolve();

Way to check referring route

Looking for a way to fire different functions on a given route, but only depending on which route was last visited. Is there already a way to do this?

Lost query parameters

My original code just extracted any query parameters from the last params property that was resolved. I honestly thought that this was how it was designed to work... but w/e.

Since b1d7a98#diff-1fdf421c05c1140f6d71444ea2b27638R95 query parameters are now completely lost (they're just stripped).

If Navigo is going to interfere with query parameters now, it should instead pass an additional parameter to the callback with the string it removed so applications that relied on it can upgrade, e.g.

router
  .on('/user/:id/:action', function (params, query) {
    // ......................................^
  })

Absolute Path vs Relative Path

Another issue I found is the use of relative paths vs. absolute paths.

You declare links in data-navigo attributed links with relative paths (eg. "about"). The router declares "/about" though. Somehow the link still trigger the particular route, but end up in doubled slashes in the address bar (eg. somedomain.com//about).

demo with hash routes

When using the demo site everything works as expected using the history api. But when you click the "hashed based routing" box in the upper right (and even after refresh) you get

http://work.krasimirtsonev.com/git/navigo/#about
http://work.krasimirtsonev.com/git/navigo/#usage
http://work.krasimirtsonev.com/git/navigo/#download
ok
but then
http://work.krasimirtsonev.com/git/navigo/testing (quickly replaces #test)
and from then on the hash is after /testing
http://work.krasimirtsonev.com/git/navigo/testing#download
http://work.krasimirtsonev.com/git/navigo/testing#usage

That doesn't seem right.

Refresh handling

I didn't really know where to go for a question, so I just opened an issue. Feel free to close.

How do you handle when a user refreshes the page... by accident? I find myself getting a 404.

Before refresh

screen shot 2016-01-06 at 10 45 25 pm

##### After refresh

screen shot 2016-01-06 at 10 54 27 pm

Route fires twice

I have this:

router.on('/pub/:pub', function (params) {
        console.log("route 2");
        gotoPageTwo(params.pub);
    });
    router.on('/', function (params) {
        gotoPageOne();
    });

When I am on "route 2" page and refresh, the route then fires twice.

Any ideas?

Bind 'click' events on links to 'document'.

When binding an event to links at start it will not catch clicks on links which are loaded later. For example if I load a new template with links, router will not change the url properly.

I think it would be better to bind event to document:

$(document).bind('click', '[data-navigo]', function() {
  // do stuff
}

Problem getting History API to work

Thanks for this library. I am able to get hash based routes working but cannot get clean URLs to work on my localhost. I added the Apache .htaccess routing as described in http://krasimirtsonev.com/blog/article/deep-dive-into-client-side-routing-navigo-pushstate-hash but does not seem to work.

Also tried setting the "root" value when creating a new Navigo() instance but not sure what that argument should actually look like, i.e. http://localhost, localhost/index.html, etc

navigate doesn't resolve if only querystring params have changed

Hello,

Thank you for Navigo. Forgive me if this is by design, but I noticed that changing just the querystring of a route and calling navigate does not resolve. I think this is a side effect from removeGETParameters that was introduced a few weeks ago. Is this a bug and if not, is there a workaround?

Thanks

Maybe don't trigger route if already there?!

More of a feature request than an issue here.

You trigger routes although you're already there. I tried to circumvent by detecting if the triggered route is already the actual page, problem though, by the time I check for it the triggered route is already added to the history, which kinda breaks the browser's back button.

Add a feature

Hi. I'd like to make a suggestion about the feature.
Following steps are for an imagination of workflow.

  1. Imagine, page now on the root '/'.
  2. Click to open MENU, then page will navigate to '#/menu'
  3. Make an action to close menu and the page will return back to '/'
  4. Click to open CART, then the page will navigate to '#/cart'.
    But if I'll click 2 times back in the browser, it will navigate to '#/menu' and open it by handling browser history!
    Are there some possible features to ignore history item but handle it?
    I tried to use pause API function, but it works like no changes.
    Thanks.

Add support for Guids as parameters

Currently the regex for the parameters is like this:

var PARAMETER_REGEXP = /([:*])(\w+)/g;

Could we possibly change it to this? (adding "-" to the possible matches allowing for the use of GUIDs as routing parameters)

var PARAMETER_REGEXP = /([:*])([a-zA-Z0-9-]+)/g;

Got error when get path more then one.

Hi,

I have a problem when I used your lib. when I need to set path more then one i got error message in console like this
bundle.js:1 Uncaught SyntaxError: Unexpected token <

this is my code

const Navigo = require('navigo');
var router = new Navigo();
router.on({
  'path/to/some/where'  : () => {
    console.log('path/to/some/where');
  },

  '/'       : () => {
    console.log('Home');
  },
});
router.resolve();

this is .htaccess

<ifModule mod_rewrite.c>
  Options +FollowSymLinks
  IndexIgnore */*
  RewriteEngine On
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule (.*) index.html
</ifModule>

localhost page ware working fine BUT localhost/path/to/some/where got error I told you above.

Link href is not updated when it's dynamic

I'm using Navigo with dynamic links - I have a simple href link with data-navigo attribute. When I click it, everything works out well, I get new data from the server.

But then I update the href attribute, using something like:

$('#link').attr('href', '/new/value');

Unfortunately this does not work properly. I first tried calling updatePageLinks, which is not documented but it's available as a function. It kind of works, but it attaches a lot of listeners to the very same link, because old ones are not cleared. I guess it just fires up a lot of redirects and I end up on the right one, I don't know (didn't investigate it too much).

I think the location property should be checked inside the click listener, instead before that:

updatePageLinks: function updatePageLinks() {
    var _this = this;

    if (typeof document === 'undefined') return;
    this._findLinks().forEach(function (link) {
        var location = link.getAttribute('href'); // do NOT use this one, as it's set only once

        link.addEventListener('click', function (e) {
            if (!_this._destroyed) {
                e.preventDefault();
                //_this.navigate(clean(location)); // don't use pre-saved location
                // get one each time the link is clicked
                // it's slower, but more robust and works for dynamic href changes
                // I found out that pathname is the actual href
                // as href gets transformed to the real address
                // ex: href="/test" -> e.currentTarget.href = "www.example.com/test"
                _this.navigate(clean(e.currentTarget.pathname));
            }
        });
    });
}

I can make PR if you find this helpful :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.