Giter Club home page Giter Club logo

elm-transit-router's Introduction

Elm Transit Router

elm package install etaque/elm-transit-router

Drop-in router with animated route transitions for single page apps in Elm, extracted from (and used in) Tacks.

Features

  • Takes care of the history interaction and actions plumbing
  • Enables animated transition on route changes, thanks to elm-transit
  • Provides a simple Signal.Address String for navigation

There is a projet example with a minimal usage of the router right here.

Usage

To be able to provide animated route transitions, TransitRouter (and Transit underneath) works by action delegation: it will be able to emit (Action, Effects Action) by knowing how to wrap his own TransitRouter.Action type into your app's Action type. This is why the actionWrapper is needed in config below.

Model

Say you have an Action type wrapping TransitRouter.Action:

type Action = Foo | ... | RouterAction (TransitRouter.Action Route) | NoOp

Also a Route type to describe all routes in your apps:

type Route = Home | ... | NotFound | EmptyRoute

You must then extend your model with WithRoute on Route type:

type alias Model = TransitRouter.WithRoute Route 
  { foo: String }

Your Model is now enabled to work with TransitRouter. Initialize it with the EmptyRoute that should render nothing in your view, to avoid content flashing on app init.

initialModel : Model
initialModel =
  { transitRouter = TransitRouter.empty EmptyRoute
  , foo = ""
  }

Update

A config should be prepared:

routerConfig : TransitRouter.Config Route Action Model

-- which expands to:
routerConfig :
  { mountRoute : Route -> Route -> Model -> (Model, Effects Action)
  , getDurations : Route -> Route -> Model -> (Float, Float)
  , actionWrapper : TransitRouter.Action Route -> Action
  , routeDecoder : String -> Route
  }
  • In mountRoute, you'll provide what should be done in your update when a new route is mounted. The Route params are previous and new routes.

  • In getDurations, you'll return the transition durations, given previous/new route and current model. Write \_ _ _ -> (50, 200) if you always want an exit of 50ms then an enter of 200ms. You mountRoute will happend at the end of exit.

  • actionWrapper will be used to transform internal TransitAction.Action to your own Action.

  • routeDecoder takes the current path as input and should return the associated route. See my elm-route-parser package for help on this.

It's now time to wire init and update functions:

init : String -> (Model, Effects Action)
init path =
  TransitRouter.init routerConfig path initialModel

This will parse and mount initial route on app init. You can get initial path value by setting up a port in main and provide current path from JS side.

In update, the lib will take care of routes updates and transition control.

update : Action -> Model -> (Model, Effects Action)
update action model =
  case action of

    NoOp ->
      (model, Effects.none)

    RouterAction routeAction ->
      TransitRouter.update routerConfig routeAction model

    Foo ->
      (doFoo model, Effects.none)

View

This is where visible part of routing happens. You just have to match current route to render the current route's view, using getRoute:

contentView : Address Action -> Model -> Html
contentView address model =
  case (TransitRouter.getRoute model) of

    Home ->
      homeView address model
    
    --- and so on

Now for animations, there is getTransition, to be used with elm-transit-style (or directly with Transit.getStatus and Transit.getValue from elm-transit).

view : Address Action -> Model -> Html
view address model =
  div
    [ style (TransitStyle.fadeSlideLeft 100 (getTransition model)) ]
    [ contentView address model ]

Links: use pushPathAddress for clink handling, for instance within that kind of helper:

clickTo : String -> List Attribute
clickTo path =
  [ href path
  , onWithOptions
      "click"
      { stopPropagation = True, preventDefault = True }
      Json.value
      (\_ -> message TransitRouter.pushPathAddress path)
  ]

Routing with Effects

Suppose you are in the module of one of the screens and you want to switch routes after handling an action (for instance after handling the result from a task). You can do this by using the redirect effect:

redirect : Routes.Route -> Effects ()
redirect route =
  Routes.toPath route
    |> Signal.send TransitRouter.pushPathAddress
    |> Effects.task

In the update function of the screen module you will not have access to the RouteAction action, since it is defined in the main app module. To be able to make the effect work in your update function, map it to a null operation:

update : Action -> Model -> (Model, Effects Action)
update action model =
  case action of

    NoOp ->
      (model, Effects.none)

    TaskCompleted ->
      (model, Effects.map (\_ -> NoOp) (redirect Home))

Subrouting transitions

If you app contains submenus, you might want to adapt the scope of transition animation, ie you only want to animate the submenu content when you switch from a submenu item to another, not the whole content of your page.

A good way to do that is to create a type to indicate the current route switch happening, and to store it in your model, so you will be able to adapt the animation in your views. Let's say you have an admin submenu:

type RouteSwitch = Global | InAdmin | NoSwitch

type alias Model = TransitRouter.WithRoute Route 
  { foo: String
  , routeSwitch : RouteSwitch
  }

Types are in place, but we still need to set routeSwitch value, and Config.mountRoute is the right place for that as it provides previous and new route, so you can compare them and decide what is the current switch:

mountRoute : Route -> Route -> Model -> (Model, Effects Action)
mountRoute prevRoute newRoute model =
  let
    routeSwitch = case (prevRoute, newRoute) of
      (Admin _, Admin _) ->
        InAdmin
      _ ->
        Global
    newModel = { model | routeSwitch = routeSwitch }
  in
    case newRoute of
      ...

Then you have everything in your hands in order to show animation in the right view, be it global content or admin content only.

elm-transit-router's People

Contributors

etaque avatar fluxxu avatar sgillis 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

Watchers

 avatar  avatar  avatar  avatar

elm-transit-router's Issues

Router does not respond to window.history.pushState()

Hi!,
I just dropped in this router into my app.
I was trying to trigger route changes through window.history.pushState() but application remain calm and did not route to a new Route.
There might be several use cases where your application is embedded and other not elm parts of apps could trigger changes in browsers history.

Refresh page didn't work with route

I don't if its just me. And I m totally newbi on this. But if I m on some page link and if I refresh page it didn't work. Normally it should go to that page (route view).

Let me know if any further details are needed.

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.