-
Notifications
You must be signed in to change notification settings - Fork 222
Cookbook
The following are a collection of proven recipes that are too small to warrant an extension or a plugin but are not complete enough or too far out-of-scope to warrant inclusion in the core of Chaplin.
Traditionally binding via a micro-template can get messy; especially if the model has not finished syncing with the server when the view is rendered. Re-rendering the view when the model updates is more of an anti-pattern as there could be a lot of structure that is needlessly re-created.
Add the follow method to your base class that extends Chaplin.View and is extended by your Views.
pass: (selector, attribute) ->
return unless @model
# Initially bind the current value of the attribute to
# the template (if we are rendered).
$el = @$ selector
$el.text @model.get attribute if $el
# Then register a listener to respond to changes in the model
# to keep the view in sync with the model.
@listenTo @model, "change:#{attribute}", (model, value) =>
@$(selector).text valueAnd call this method as follows in a view that derives from that base view.
initialize: ->
@pass '.name', 'name'
@pass '.phone', 'phone'Which will set up 1-way data bindings for the model attributes name and phone
to the DOM elements in the view with the classes .name and .phone respectively.
This is limited to one-way binding and there isn't much allowance for complicated logic to generate the value, etc. For a more complete solution, refer to Backbone.Stickit.
By lukateake
You've gone ahead and built a big application. Congratulations! But now you've got a million bookmarkable states that the user wants to use in order to resume their work. Alas, we don't want to keep filtering them through the front door but we do need to make sure they're logged in. Here's what I did and, mind you, I don't like hash signs in my URLs as I feel their atrocious aesthetically so I used pushState which requires some server magic of its own.
(Note: my implementation certainly isn't perfect so if you improve upon it, please do let me know.)
First thing you want to do is make an additional Controller superclass, I called mine AuthController and cloned it from the out-of-the-box one that's provided by Chaplin. Then I added this sweet little method to it:
AuthController.coffee
'use strict'
Chaplin = require 'chaplin'
mediator = require 'mediator'
module.exports = class AuthController extends Chaplin.Controller
beforeAction:
'.*': ->
console.debug 'Controllers.Base.AuthController#beforeAction()'
console.debug 'path', window.location.pathname
if Chaplin.mediator.user == null
mediator.redirectUrl = window.location.pathname
@redirectToRoute 'auth_login' This does a couple of things, the biggest thing it does is intercept every action '.*' of every controller that will inherit/extend from AuthController. Secondly, I'm using the existence of mediator.user to check login state. (Hint: your 'logged in successfully' process would need to set this, of course.) Lastly, if mediator.user nulls out, two additional things happen: a) store the location of where I'm trying to get to, and b) redirect to the named route 'auth_login' as defined by routes.coffee thusly:
routes.coffee
# login/logout
match 'login', controller: 'auth/login', action: 'login', name: 'auth_login'
match 'logout', controller: 'auth/login', action: 'logout', name: 'auth_logout'Next, have every portion of your application that you want secured have its controller extend from AuthController. However, do not have the LoginController inherit/extend it though. Instead for it, use the vanilla one that doesn't have the beforeAction check. And speaking of LoginController, let's go ahead and create that now.
It's pretty straight forward from here on out: have your LoginController and its related View implement some sort of authentication mechanism. (Security processes are touchy point among developers and/or application requirements vary considerably, thus, I effectively 'punt the ball' and leave implementation details as an exercise to the reader.) From the routes.coffee file above, you can see mine is in auth/login.
When the user is successfully authenticated, do this:
login-view.coffee
loginSuccess: (user) =>
mediator.user = user
if mediator.redirectUrl == null
@publishEvent '!router:routeByName', 'site_home'
else
@publishEvent '!router:route', mediator.redirectUrl
@publishEvent 'loginStatus', true
I hope this helps someone.