Git Product home page Git Product logo

snaplet-liftajax's Introduction

snaplet-liftajax

This Snaplet provides splices for AJAX-enabled forms and buttons, modeled off of AJAX elements in the Lift web framework for Scala. A nice feature of Lift is the ability to associate server-side callbacks directly with html elements, abstracting over the details of writing the appropriate client-side javascript and matching server-side routes. More detail is given in the book Exploring Lift.

Example

Here's an example of an ajax form using the digestive-functors package. We'll write a form to parse and add two integers server-side. If everything goes well, we alert the user with the result. If not, we show an alert with the errors.

First, some imports

import           Control.Applicative
import           Data.Monoid
import           Data.Text                    (Text)
import qualified Data.Text                    as T
import           Language.Javascript.JMacro
import qualified Snap.Snaplet.LiftAjax.Js     as Js
import qualified Snap.Snaplet.LiftAjax.Splice as Ajax
import           Text.Digestive
import           Text.Digestive.Heist
import           Text.Templating.Heist
import           Application

Now, define a form to add two integers

addInts :: Monad m => Form Text m Int
addInts = (+)
          <$> "x" .: stringRead "x must be an integer" Nothing
          <*> "y" .: stringRead "y must be an integer" Nothing

To this form, associate a function process which takes the result (or an error) and returns javascript to be executed client-side.

addIntsSplice :: Splice AppHandler
addIntsSplice = Ajax.formWithSplices digestiveSplices addInts process
    where
      process :: Either (View Text) Int -> AppHandler JStat
      process (Right z) = return $ Js.alert $ "the sum is " <> T.pack (show z)
      process (Left v)  = return $ Js.alert $ T.intercalate ", " $ childErrors "" v

If we bind addIntsSplice to the tag <addIntsForm>, then our heist template would look like this:

<addIntsForm class="classes for styling">
x = <dfInputText ref="x" />,
y = <dfInputText ref="y" />
<input type="submit" value="Add" />
</addIntsForm>

Setup

Add the snaplet to your application's state, and define a HasAjax instance:

data App = App
    { _heist :: Snaplet (Heist App)
    , _ajax  :: Snaplet (Ajax App)
    }

makeLens ''App

instance HasHeist App where
    heistLens = subSnaplet heist

instance HasAjax App where
    ajaxLens = ajax

type AppHandler = Handler App App

Call nestSnaplet appropriately in your application's initializer:

app = makeSnaplet "app" "An snaplet example application." Nothing $ do
    h <- nestSnaplet "" heist $ heistInit "templates"
    a <- nestSnaplet "ajax" ajax $ ajaxInit defaultAjaxState
    addRoutes [("/", serveDirectory "static")]
    addSplices [("addIntsForm", liftHeist addIntsSplice)]
    return $ App h a

Add jquery and liftAjax.js to your site's header (and place the files where they'll be served):

<script type="text/javascript" src="jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="liftAjax.js"></script>

Add the <ajaxFooter /> just before your site's </body> tag.

Notes

  • Currently, Jmacro is used for client-side javascript, but this package can be easily adapted to work with some other way of generating javascript. It would be nice to see if there's a natural way to incorporate a more haskelly solution like Fay.

  • liftAjax.js is taken almost verbatim from the lift web framework. I have intentionally made only minimal modifications.

  • the LiftAjax snaplet assigns each page a unique pageId, and keeps a map from pageIds to ajax handlers. In order to decide when to garbage collect these handlers, it also keeps track of "heartbeats" from each open page -- these are ajax calls automatically sent every minute or so (configurable in ajaxInit) to say "I'm still open!". A background process continually checks for pages with old heartbeats and discards their ajax handlers.

  • Since this snaplet is still in development, its behavior may not be completely consistent with Lift's.

snaplet-liftajax's People

Contributors

davidsd avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

beandipper

snaplet-liftajax's Issues

Can't cabal install snaplet-liftajax.cabal

When I try to build it through cabal install snaplet-liftajax.cabal, it yields this error message when compiling Js.hs:

src/Snap/Snaplet/LiftAjax/Js.hs:29:78:
Couldn't match expected type PP.Doc' with actual type wl-pprint-text-1.1.0.0:Text.PrettyPrint.Leijen.Text.Doc'
Expected type: a -> PP.Doc
Actual type: a
-> wl-pprint-text-1.1.0.0:Text.PrettyPrint.Leijen.Text.Doc
In the second argument of (.)', namely renderJs'
In the second argument of (.)', namely PP.renderStyle (PP.style {PP.mode = PP.OneLineMode}) . renderJs'

src/Snap/Snaplet/LiftAjax/Js.hs:32:80:
Couldn't match expected type PP.Doc' with actual type wl-pprint-text-1.1.0.0:Text.PrettyPrint.Leijen.Text.Doc'
Expected type: a -> PP.Doc
Actual type: a
-> wl-pprint-text-1.1.0.0:Text.PrettyPrint.Leijen.Text.Doc
In the second argument of (.)', namely renderJs'
In the second argument of (.)', namely PP.renderStyle (PP.style {PP.mode = PP.OneLineMode}) . renderJs'
cabal: Error: some packages failed to install:
snaplet-liftajax-0.0.1 failed during the building phase. The exception was:
ExitFailure 1

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.