Skip to content
lubelski edited this page Nov 17, 2014 · 5 revisions

Adapters are the most unique part of pipeline. They specify an interface between the state held in the stores and some external place. They can listen to some external events and fire actions, and can listen to store change events and respond accordingly.

A common example is RouteAdapter. In contrast to a view based router like the excellent react-router, we'd like to hold our canonical location state in a store rather than the URL bar. The url bar just becomes a projection of app state from a store (and is helpful on a refresh).

Blog = pipeine.createApp()
Blog.createStore('location', 
  pages: ['home', 'post', 'list']

  API: 
    getPage: -> @get('page')
    getId: -> @get('id')
      
  actions: 
    goHome: ->
      @update(page:'home', id: null)
    goToList: ->      
      @update(page:'list', id: @action.id)
    goToPost: ->
      @update(page:'post', id: @action.id)
    navigate: -> 
      if _.contains(@pages, @action.page)
        @update(page: @action.page, id: @action.id)
Blog.createAdapter('route', 
  stores: 
    location: -> 
      page = @stores.location.getPage()
      id = @stores.location.getId()
      switch page
        when 'home' then window.pushState({}, '/')
        when 'post' then window.pushState({}, "post/#{id}/"
        when 'list' then window.pushState({}, "list/#{id}/"

Examples:

A Route Adapter projects internal state into the URL bar via the pushState API and interprets user changes to the route (back button, etc) via popState events and fires actions accordingly.

A Network Adapter makes network requests based on the state of a store.

React views are a special case because they can be so complex, but they are really just DOM Adapters. They project internal application state into the DOM for the user to see and interact with, and they interpret user events and fire actions accordingly.

Any source of Asynchrony should be accessed via an adapter.

App.createAdapter(name, options)
Pantry.createApp()

Pantry.createStore 'crackers', 
  API: 
    getPrice: -> @get('price')
  actions: 
    newCrackersPrice: -> @update('price', @action.price)
      
Pantry.createAdapter('crackersAdapter', 
 
  syncCrackerPrice: -> 
    $.ajax
      type: 'PUT'
      url: 'api/0/crackers/price/'
      data: @stores.crackers.getPrice()
      success: @actions.crackers.priceSynced
      error: (xhr, error) -> 
        @actions.crackers.priceSyncError(error)

  stores: 
    'crackers': -> 
       if @stores.crackers.needsSync() then @syncCrackerPrice()

Clone this wiki locally