GithubHelp home page GithubHelp logo

elm-router's Introduction

elm-router

This library contains a couple functions to assist in doing client-side routing in Elm. The way this library achieves this is by introducing the concepts of routes and routers and a match function to match url paths to different routes.

Note: This library offers very simplistic mechanisms for routing and is mainly intended for small applications and to serve as an example API for what can be achieved in Elm in terms of routing. Please do not consider this API as a definitive solution to routing or that it somehow represents how routing should be done. I'd like to think that it merely represents one way routing could be done.

Motivating Example

elm-router allows you do define routes as follows:

mainRoute : Route Html
mainRoute = match
  [ "/"               :-> displayHomePage
  , "/index.html"     :-> displayHomePage
  , "/blog"           :-> blogRoute
  , "/contacts.html"  :-> displayContactsPage
  ] display404Page

blogRoute : Route Html
blogRoute = match
  [ "/"             :-> displayBlogListing
  , "/entry1.html"  :-> displayEntry1
  , "/entry2.html"  :-> displayEntry2
  ] display404Page

Routes are created with the match function. Match takes a list of strings and functions (or Routers) and a default route and creates a route from them. In this example, if the user were to go to "/contacts.html", the displayContactsPage function would be called. You may also notice that these routes nest, as shown with blogRoute. In this example, if the user were to go to "/blog/entry2.html", the displayEntry2 function would be called.

Hopefully, you can see from this example that the DSL provided by elm-router makes it easy to work with routes. The only thing you might notice is that these routes require other routes. So, how do you make those? To this, we will explore what are routes.

Routes and Routers

Route:

A Route is defined as a function from a String to some value or computation.

type alias Route a = String -> a

The input String of a Route, in the case of the example, would be a url path. So, in our example, mainRoute is simply a function that, given a url path, produces Html. This is exactly what we intend with routers, to produce different views based on an input url path.

An example function that would fit this description could be:

displayHelloWorld : Route Html
displayHelloWorld _ = text "Hello World"

This is a function which ignores the input path and displays "Hello World" as text.

Router:

A Router is simply defined as a tuple of String and Route.

type alias Router a = (String, Route a)

As such, a Router contains sufficient information for performing a simple pattern match on strings. We can trivially take a string, match on the Router's string, and if the match succeeds, call the Router's route.

So, now that we understand the fundamental types, let's understand how match works.

Match

As stated in the example, match takes a list of routers and a default route and returns a route.

match : List (Router a) -> Route a -> Route a

Basically what happens is that match will take an input string and go through each router one by one to see if there is a match. If there is one, it will call on the matched router's route. If no strings match, then it will call on the default route.

So, in our example above, the default route is display404Page. This is the common catch-all for websites where they refer you to a 404 page to tell the user that they have entered an unknown url.

A minimal example match would be:

route : Route String
route = match
  ["/index.html" :-> (\_ -> "Hello world")]
  (\_ -> "Nothing Here")

-- route "/index.html" == "Hello world"
-- route "/someotherthing" == "Nothing Here"
-- route "/" == "Nothing Here"
-- route "/index.htmlejnuz" == "Hello world"
-- route "/index.htm" == "Nothing Here"

From this example we can see that, if the given string starts with one of the reference strings in the list of routers, the appropriate function will be called, even if the given string is non-sensical. If the given string is not matched completely, then match will default to the given default route.

So, ok, match sees if the given string starts with one of the reference strings and then calls the appropriate route. But what does it call that route with?

To answer this, let's tweak our minimal example a bit.

route : Route String
route = match
  ["/index.html" :-> (\string -> string)]
  (\string -> string)

-- route "/index.html" == ""
-- route "/someotherthing" == "/someotherthing"
-- route "/" == "/"
-- route "/index.htmlejnuz" == "ejnuz"
-- route "/index.htm" == "/index.htm"

So, now we have modified our route to simply output what it was given. We can already see the behavior of match from this example.

In the case that an input string was matched against a reference string in a router, match will pass the remainder of the input string to the route. In essence, match will string the part of the input string that is matched and pass what is left to the route.

So, if we had "hello" as input and matched against "he", match would pass "llo" to the route.

In the case that an input string was not matched, it will pass the entire input to the default route. This is partly because, since there is nothing to match, there is nothing to string and partly because this may be useful for debugging and analytics purposes.

It is also important to note that match matches routers in the order you state them. This means that in the following example:

route = match
  [ "/user"       :-> userRoute
  , "/users.html" :-> displayUserListing
  ] display404Page

the "/users.html" router will never be matched. This is because if you pass "/users.html" to route, then the "/user" router will be matched and userRoute will be called with the string "s.html". In order to solve this issue, you must re-order the routers as follows:

route = match
  [ "/users.html" :-> displayUserListing
  , "/user"       :-> userRoute
  ] display404Page

Now, match will try "/users.html" first.

At this point, you may note that in our very first example, we used "/" as a router before all the other routers. You would assume that all the other routes are unreachable. This is not the case because match special cases the empty string and "/" due to their prevalence.

Finally, you may have noticed the weird :-> operator. This is just an alias for the (,) tuple constructor.

(:->) : String -> Route a -> Router a
(:->) = (,)

For more details on usage, please refer to the examples in the repo. Note that this library is best used in conjunction with elm-history as it allows you to capture the url path as it changes and thus match on it.

elm-router's People

Contributors

theseamau5 avatar ryanashcraft avatar

Stargazers

 avatar  avatar Joe Tarricone avatar Andrew Meier avatar MB avatar Alexsey Ramzaev avatar Adailton Nascimento avatar Ryan Taylor Long avatar Josh Girvin avatar Josh Waller avatar Xx avatar Tim Kendall avatar Tim Perry avatar Candy Zheng avatar Boons avatar Jack Valinsky avatar Fed Reggiardo avatar Alexey Poimtsev avatar Adam Witko avatar Yami Odymel avatar  avatar Qingo avatar Preethi Kasireddy avatar Zen Savona avatar Guido Schmidt avatar Théo Crevon avatar Jonah George avatar Theron Boerner avatar  avatar Jelle Versele avatar Tony Seing avatar K.K. POON avatar Peter Keogh avatar David Johnson avatar Geoffrey Dhuyvetters avatar Boris Joffe avatar Henry S avatar Dorian Karter avatar Douglas Correa avatar Shuhei Kagawa avatar Alexis Couronne avatar Salla avatar Shawn Lim avatar chinuka avatar Ben Smith avatar ninjure avatar Christian Meunier avatar Gabriel Grinberg avatar Nutchaphon Rewik avatar Leon Gaban avatar Guido avatar Maki Uehara avatar Beat avatar Flux Xu avatar Serhii Yavnyi avatar Simone Vittori avatar Volkan Unsal avatar Kota Yoshitsugu avatar Schalk avatar Zeljko Nesic avatar Lakshminp avatar Xe Iaso avatar Samuli Ulmanen avatar Viktor Lazarev avatar Po-Ying Chen avatar Ian Ramos avatar Evan Walsh avatar apscomp avatar Vinh Quốc Nguyễn avatar Allie avatar Jason Hickner avatar Max Hoffmann avatar Hussein Morsy avatar Jonathan Krause avatar Angus H. avatar Jack Franklin avatar Josh Teneycke avatar M∎∎r avatar Ronen avatar Seoh Char avatar Mitch Crowe avatar Mark Farrell avatar Pete Doherty avatar Alexis King avatar Paul Allton avatar Anton Strilchuk avatar Matt Parsons avatar Nick avatar Edward O avatar Anton Byrna avatar Esdras Mayrink avatar H avatar Federico Carrone avatar Rehno Lindeque avatar  avatar Josh Black avatar Iain Ballard avatar Bruno Melo avatar antonio nikishaev avatar macmoebius avatar

Watchers

James Cloos avatar Pablo Botelho avatar Simone Vittori avatar chinuka avatar  avatar

elm-router's Issues

parameters in routes / alternate API design

Maybe using different types like this:

type alias Router a =
  List (String, (List String -> Maybe a))

type Page
  = IndexPage
  | BlogPost String
  | MonthIndex Int Int

myRouter : Router Page
myRouter =
  [ "/" :-> (\_ -> Just IndexPage)
  , "/post/:slug" :-> (\[slug] -> Just (BlogPost slug))
  -- would need to use String.toInt and handle Results here,
  -- returning Nothing if they fail
  , "/posts/:year/:month" :-> (\[year, month] -> Just (MonthIndex year month))
  ]

type alias URL = String

match : Router a -> URL -> Maybe a
match = ...

I've seen the /:param_name syntax in Rails, react-router, Ember, etc; seems to work well. It could also allow you to do something like this:

urlFor : Router a -> a -> URL
urlFor = ...

-- urlFor (BlogPost "elm-is-cool") => "/post/elm-is-cool"

If you put this in as a link's href, when the browser goes to it it'll trigger that route.

start-app integration?

Hi @TheSeamau5, is it possible to use elm-router with start-app? If so, could you possible provide an example or at least give me a general idea of how?

If not, I don't understand how you can loading data over HTTP without effects, and the only examples I can find of Effects use start up. Could you point me in the right direction? What am I missing?

Exemple2.elm broken

Hi,

I am trying to use your Example2.elm has a started point for learning elm-router and Task in elm but it's seems broken.

I got the following errors using 0.15 :


Error in src/sample2.elm:

Type mismatch between the following types on line 15, column 18 to 25:

       Signal.Message

       Signal.Address a

   It is related to the following expression:

       message

Type mismatch between the following types on line 15, column 9 to 16:

       a -> Html.Attribute

       Html.Attribute

   It is related to the following expression:

       onClick

Type mismatch between the following types on line 12, column 18 to 25:

       Signal.Message

       Signal.Address a

   It is related to the following expression:

       message

Type mismatch between the following types on line 12, column 9 to 16:

       a -> Html.Attribute

       Html.Attribute

   It is related to the following expression:

       onClick

Type mismatch between the following types on line 28, column 18 to 25:

       Signal.Message

       Signal.Address a

   It is related to the following expression:

       message

Type mismatch between the following types on line 28, column 9 to 16:

       a -> Html.Attribute

       Html.Attribute

   It is related to the following expression:

       onClick

Type mismatch between the following types on line 25, column 18 to 25:

       Signal.Message

       Signal.Address a

   It is related to the following expression:

       message

Type mismatch between the following types on line 25, column 9 to 16:

       a -> Html.Attribute

       Html.Attribute

   It is related to the following expression:

       onClick

Type mismatch between the following types on line 61, column 18 to 25:

       Signal.Message

       Signal.Address a

   It is related to the following expression:

       message

Type mismatch between the following types on line 61, column 9 to 16:

       a -> Html.Attribute

       Html.Attribute

   It is related to the following expression:

       onClick

Type mismatch between the following types on line 58, column 18 to 25:

       Signal.Message

       Signal.Address a

   It is related to the following expression:

       message

Type mismatch between the following types on line 58, column 9 to 16:

       a -> Html.Attribute

       Html.Attribute

   It is related to the following expression:

       onClick

Type mismatch between the following types on line 55, column 18 to 25:

       Signal.Message

       Signal.Address a

   It is related to the following expression:

       message

Type mismatch between the following types on line 55, column 9 to 16:

       a -> Html.Attribute

       Html.Attribute

   It is related to the following expression:

       onClick

Type mismatch between the following types on line 52, column 18 to 25:

       Signal.Message

       Signal.Address a

   It is related to the following expression:

       message

Type mismatch between the following types on line 52, column 9 to 16:

       a -> Html.Attribute

       Html.Attribute

   It is related to the following expression:

       onClick

I think it have something to do with the route : Route (String -> Int -> Html) but i can't find a way to correct it. Can you help ?

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.