Coder Social home page Coder Social logo

ampersandjs / ampersand-router Goto Github PK

View Code? Open in Web Editor NEW
71.0 12.0 16.0 89 KB

Clientside router with fallbacks for browsers that don't support pushState. Mostly lifted from Backbone.js.

License: MIT License

JavaScript 100.00%
ampersand router pushstate

ampersand-router's People

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

Watchers

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

ampersand-router's Issues

Trigger current route callback again

Say I am on the page /contact. Is there anyway to force the router to trigger the path to load again if I run router.navigate('/contact')? Currently, the router doesn't fire the route callback if it's already on that route (which is useful 95% of the time)

Underscore dependency

This issue is not really specific to ampersand-router, but I it seems there is no general place to discuss things that cover multiple ampersand modules.

The thing is, underscore is awesome, I use and love it, but it is also a pretty big dependency that doesn't seem appropriate for a collection-of-tiny-modules type framework. Also, unlike Backbone, you can't easily replace underscore with alternatives like lodash.

There was already a mention in #1 that it is planned to remove the underscore dependency in the router, but it makes sense only if it is removed in other modules as well in my opinion.

As a replacement, I would suggest taking underscore and splitting its functions in separate files, probably removing a few that are provided by the most browsers already (like bind, map etc). So instead of doing this:

var _ = require('underscore');
_.extend(...);

you would have to do this:

var extend = require('ampersand-something/extend');
extend(...);

Thoughts?

add event after navigate

Hello,

I have a bug with Firefox only... if I go to : /some-page, and scroll to its bottom, and then change page to /some-other-page , I land on the new page but not scrolled to the top.

The way I see to solve this would be to add an event after router.navigate and scroll manually to the top, but it does not seem to have an event existing for this.

Any thought ?
Vincent

Incorrect routing of anchors when root is set

When a non-empty root is set during router start, routing of clicked anchors fails.

This happens because the anchor pathname is used, which includes the root, which is passed to navigate, which passes that to getFragment, which fails to remove the root from the fragment.

is a "catchAll" route impossible by design?

The catchAll route "(*path)": "catchAll" used in the ampersand demo webapp must be the last route in the hash. Otherwise every route defined after is impossible to reach.

{
  "index.html": "home",
  "collections": "collectionDemo",
  "info": "info",
  "person/add": "personAdd",
  "person/:id": "personView",
  "person/:id/edit": "personEdit",
  "(*path)": "catchAll"
}

The Problem is that the object key sorting is not static. I have handled the routes as JSON before using it to extend the router and they got sorted alphabetically. In result the catchAll-Route enters the first place.

{
  "(*path)": "catchAll",
  "collections": "collectionDemo",
  "index.html": "home",
  "info": "info",
  "person/:id": "personView",
  "person/:id/edit": "personEdit",
  "person/add": "personAdd"
}

Should we switch to an array of routes or oversee i something that solves the problem an other way?

Think about and document how to handle multiple routers. Specifically starting them.

AmpersandRouter automatically requires and instantiates a single ampersand-history object. AmpersandHistory serves as a global router (per frame) to handle hashchange events or pushState, match the appropriate route, and trigger callbacks. You shouldn't ever have to create one of these yourself since ampersand-router already contains one.

When all of your Routers have been created, and all of the routes are set up properly, call router.history.start() on one of your routers to begin monitoring hashchange events, and dispatching routes. Subsequent calls to history.start() will throw an error, and router.history.started is a boolean value indicating whether it has already been called.

Document history API

Some currently undocumented methods of the history API (like getFragment) are very useful for users of this package - any change you'd consider documenting them publicly? ๐Ÿ˜„

search part of location is misinterpreted as fragment when root is not "/"

When root isn't set to "/", I've noticed some unexpected behaviour with regard to the root url when it has a query string.

An example:

const Router = AmpersandRouter.extend({
    routes: {
        "": "index",
        "(*path)": "catchAll"
    },
    index() {
        //never fires
    },
    catchAll(path, query) {
        console.log(pathname);//path results in the query string instead
    }
});

const router = new Router();

router.history.start({
    pushState: true,
    root: "/app"
});

When starting the page at, say /app?foo=bar, path incorrectly results in "foo=bar", which isn't right. router.history.fragment also reports "foo=bar".

However, staring the page at /app/second?foo=bar, path correctly results in "/second"

ampersand-router pulls in underscore

ampersand-router depends on underscore, but looking through the source the only non-trivial method used is extend, which can be more minimally done using a module such as object-assign. Alternatively, the individual lodash sub-modules available on npm are an option. For example isRegExp.

Some background: I'm working on something that I want to use ampersand-router with, but not the rest of ampersand (for now at least). It would be a shame to add underscore as an indirect dependency.

If this proposal seems good, I'd be happy to make a pull request.

Non-root routes pass requests to server

So I'm pretty sure this has to be something I'm doing wrong, but I haven't quite found it. I'm currently using just ampersand-router in an app - no other ampersand dependencies. I have something like this happening (vastly simplified):

import ampRouter from 'ampersand-router'

let Router = ampRouter.extend({
  routes: {
    '': 'home',
    'reset': 'reset'
  },
  home: function () {
    console.log('Home!')
  },
  reset: function () {
    console.log('Reset!')
  }
})


class Application {
  constructor() {
    // A bunch of other stuff is instantiated
    this.router = new Router()
    this.router.history.start({
      pushState: true
    })
  }
}

// Global for example purposes
window.app = new Application()

Navigating to the root route ('') calls the home handler as expected, but navigating to /reset sends the request to the server (which in this case returns a 404). Navigating to /#reset calls the reset handler as expected (and ampersand-router rewrites the URL as /reset, as expected). Why are non-hash, non-root routes routing to the server instead of routing to the ampersand-router?

(Also of note is that in both of the above cases, each handler is called twice - not sure what's going on there either)

event binding fails while initialize new Router(options)

When creating a new router, you may pass its routes hash directly as an option, if you choose.

The route init want to read particular callbacks from the surrogate object.
if (!callback) callback = this[name];

Problem is that the surrogate object is created in the Router.extend() function only. When passing the routes hash directly this[name] is always undefined and the event binding is broken.

Can the extend step be included in the constructor?

Question: no route change detection by default?

Dumbest code:

var AmpersandRouter = require('ampersand-router');

var Router = AmpersandRouter.extend({
  routes: {
    "": "main", // #help
    "search/:query": "search", // #search/kiwis
    "search/:query/p:page": "search", // #search/kiwis/p7
    "*notFound": "notFound"
  },
  main: function() {
    console.log('main', arguments);
  },
  search: function(query, page) {
    console.log('search', arguments);
  },
  notFound: function notFound() {
    console.log('notFound', arguments);
  }
});

var router = new Router();

router.history.start();
console.log('blastoff');

If I enter '/#search/foo' in the url nothing happens. Do I have to manually do router.navigate()? I couldn't find a working example for the router, sorry for posting here.

encoded "%" gets stripped fragment in navigate call

I noticed a bug when dealing with encoded percent signs in urls. Take the following simple example:

store/search/<query>

with a query value of % and proper encoding this gets

store/search/%25

When i pass this as a route to the navigate function the fragment gets changed to store/search/%by the decodeURI call in the following line. Changing the URL fragment on navigation appears like a bug to me. Based on navigating around the code a bit and the comment for that function saying that the caller is responsible for proper encoding I wonder if the decodeURI call is actually necessary.

Any thoughts on that? Thanks.

Last index in execute args is always null

I'm overriding the execute method to filter the query, just like in the documentation, but the last argument in args is always null. The documentation says that we can do args.pop() to get the query argument (assuming a route like help/:query), which makes sense, but since the last argument is always null, the pop just returns null.

I traced the issue to the route.exec call in _extractParameters so it seems that the regex used to extract the params always returns a null at the end. I can write a workaround for this in my overriding execute method but it seems incorrect for a null to be there.

On a side note, if you add an extra parameter to your route argument list, you get the null but any other extra parameters are undefined. So that null is passed on.

routes: {
    'help/:query': 'help'
},
help: function (query, nully, undef) {
    console.log(nully === null); // true
    console.log(undef === null); // false
    console.log(undef === undefined); // true
}

Document browser support

Hey - great to finally see a standalone JS router with a hash fallback! Thank you.

Documentation regarding what browsers are supported would be great . . . specifically what versions of IE are supported?

Even better, consider automating test runs using Sauce Labs to verify that tests are passing in all supported browsers.

Cheers
-Alden

Extract History and Router into independent modules.

Is there a reason that I cannot use History without Router and visa versa? I'm curious is this was a design decision or just the result of the Backbone port. The current implementation prevents the router from being used outside of the browser.

Honestly, I'd love to see 3 modules:

  1. History/pushState - A client-side module that manages browser history for me and provides events for state change.
  2. Route matching and URL interpolation - Basically I want to map from a URL to a route and params, and from a route and params back to a URL. Could be used client-side or in node.
  3. The whole enchilada - A fancy facade that wraps these two together for me on the client. Basically what this module is today (plus url interpolation FTW).

Basic readme example not cleaning up stuff?

    home: function () {
        this.trigger('newPage', new HomePage());
    },

This means that whenever you go to the homepage it will create a new instance of HomePage and probably bind some events. That code suggests that the events don't get cleaned up.

I think it's better to update the example to either store the last view and then cleanup or to use the ampersand-view-switcher.

What about the order of the routes-property when JavaScript Object properties have no inherent order?

The order of the routes-property-object seems to be of importance in the Ampersand Router.

We stumbled upon this, because we needed to dynamically define our routes. When we used lodash.assign(routes1, routes2) to merge a bunch of routes, the "catch-all-wildcart" of the first "routes1"-object overruled all routes in our second "routes2"-object. If we reverse the assign-order, things behave differently.

Anyone having same issues here? No-one having crossbrowser issues here?
From ECMAScript Third Edition (pdf):

4.3.3 Object
An object is a member of the type Object. It is an unordered collection of properties each of which contains a primitive value, object, or function. A function stored in a property of an object is called a method.

We noticed in other parts of our app that we can not rely on the order of the properties in a Javascript Object. Yes, we were testing on an old Android 4.x.x's Stock Browser, but this post does confirm our observations: http://stackoverflow.com/questions/280713/elements-order-in-a-for-in-loop

Hash changes are impossible to follow

If I have hashes that I want to track changes in, in addition to normal routing, this is impossible because getFragment() strips out the hash. I know the url changed, but I don't know why without hacking in something tracking hash state on its own.

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.