forked from marionettejs/backbone.marionette
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
773 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
# Marionette.Behavior | ||
|
||
|
||
A `Behavior` is an isolated set of DOM / user interactions interactions that can be mixed into any `View`. `Behaviors` allow you to blackbox `View` specific interactions into portable logical chunks, keeping your `views` simple and your code DRY. | ||
|
||
## Documentation Index | ||
|
||
* [Motivation](#the-motivation) | ||
* [Using Behaviors](#using) | ||
* [API](#api) | ||
* [Event proxy](#the-event-proxy) | ||
* [$](#$) | ||
* [$el](#$el) | ||
* [Defaults](#defaults) | ||
* [View](#view) | ||
|
||
## The Motivation | ||
|
||
As you build more and more complex views you will find that your `view` becomes less about displaying model data, and more about interactions. | ||
|
||
These interactions tend to be chunks of logic that you want to use in multiple views. | ||
|
||
## Using | ||
|
||
Here is an example of a simple `itemView`. Let's take a stab at simplifying it, and abstracting behaviors from it. | ||
|
||
```js | ||
var MyView = Marionette.ItemView.extend({ | ||
ui: { | ||
"close": ".close-btn" | ||
}, | ||
|
||
events: { | ||
"click @ui.close": "warnBeforeClose" | ||
}, | ||
|
||
warnBeforeClose: function() { | ||
alert("you are closing all your data is now gone!"); | ||
this.close(); | ||
}, | ||
|
||
onShow: function() { | ||
this.$('.tooltip').tooltip({ | ||
text: "what a nice mouse you have" | ||
}); | ||
} | ||
}); | ||
``` | ||
|
||
Interaction points such as tooltips and warning messages are generic concepts. There is no need to recode them within your views. They are prime for abstraction into a higher level non-coupled concept, which is exactly what Behaviors provide you with. | ||
|
||
Here is the syntax for declaring which behaviors get used within a view. | ||
The keys in the hash are passed to `getBehaviorClass` to lookup the correct `Behavior` class. | ||
The options for each behavior are also passed to said Behavior during initialization. The options are then stored within each behavior under `options`. | ||
|
||
```js | ||
var MyView = Marionette.ItemView.extend({ | ||
behaviors: { | ||
CloseWarn: { | ||
message: "you are closing all your data is now gone!" | ||
}, | ||
ToolTip: { | ||
text: "what a nice mouse you have" | ||
} | ||
} | ||
}); | ||
``` | ||
|
||
Now let's create the `CloseWarn` behavior. | ||
|
||
```js | ||
var CloseWarn = Marionette.Behavior.extend({ | ||
// you can set default options | ||
// just like you can in your Backbone Models | ||
// they will be overriden if you pass in an option with the same key | ||
defaults: { | ||
"message": "you are closing!" | ||
}, | ||
|
||
// behaviors have events that are bound to the views DOM | ||
events: { | ||
"click .close": "warnBeforeClose" | ||
}, | ||
|
||
warnBeforeClose: function() { | ||
alert(this.options.message); | ||
// every Behavior has a hook into the | ||
// view that it is attached to | ||
this.view.close(); | ||
} | ||
}); | ||
``` | ||
|
||
And onto the `Tooltip` behavior. | ||
|
||
```js | ||
var ToolTip = Marionette.Behavior.extend({ | ||
onShow: function() { | ||
// this.$ is another example of something | ||
// that is exposed to each behavior instance | ||
// of the view | ||
this.$('.tooltip').tooltip({ | ||
text: this.options.text | ||
}); | ||
} | ||
}); | ||
``` | ||
|
||
There is one final piece to finalizing this. The user must define a location for where their `behaviors` are stored. | ||
A simple example of this would look like this: | ||
|
||
```js | ||
Marionette.Behaviors.behaviorsLookup = function() { | ||
return window.Behaviors; | ||
} | ||
``` | ||
|
||
In this example you would then store your behaviors like this: | ||
|
||
```js | ||
window.Behaviors.ToolTip = ToolTip; | ||
window.Behaviors.CloseWarn = CloseWarn; | ||
``` | ||
|
||
## API | ||
|
||
### the event proxy | ||
Behaviors are powered by an event proxy. What this means is that any events that are triggered by the view's `triggerMethod` function are passed to each Behavior on the view as well. | ||
|
||
As a real world example, whenever in your `view` you would have `onShow`, your behavior can also have this `onShow` method defined. The same follows for `modelEvents` and `collectionEvents`. Think of your behavior as a receiver for all of the events on your view instance. | ||
|
||
This concept also allows for a nice decoupled method to communicate to behaviors from your view instance. | ||
You can just call from within your view `this.triggerMethod("SomeEvent", {some: "data"})`. then your `behavior` class would look like this: | ||
|
||
```js | ||
Marionette.Behavior.extend({ | ||
onSomeEvent: function(data) { | ||
console.log("wow such data", data); | ||
} | ||
}); | ||
``` | ||
|
||
|
||
### $ | ||
`$` is a direct proxy of the views `$` lookup method. | ||
```js | ||
Marionette.Behavior.extend({ | ||
onShow: function() { | ||
this.$('.zerg') | ||
} | ||
}); | ||
``` | ||
|
||
### $el | ||
`$el` is a direct proxy of the views `el` cached as a jquery selector. | ||
```js | ||
Marionette.Behavior.extend({ | ||
onShow: function() { | ||
this.$el.fadeOut('slow') | ||
} | ||
}); | ||
``` | ||
|
||
### defaults | ||
`defaults` can be a `hash` or `function` to define the default options for your behavior. | ||
The default options will be overridden depending on what you set as the options per behavior (this works just like a `backbone.model`). | ||
|
||
```js | ||
Marionette.Behavior.extend({ | ||
defaults: function() { | ||
return { | ||
'deepSpace': 9 | ||
} | ||
} | ||
}); | ||
``` | ||
|
||
```js | ||
Marionette.Behavior.extend({ | ||
defaults: { | ||
'dominion': 'invasion', | ||
'doge': 'amaze' | ||
} | ||
} | ||
}); | ||
``` | ||
|
||
### view | ||
The `view` is a reference to the view instance that the `behavior` is on. | ||
|
||
```js | ||
Marionette.Behavior.extend({ | ||
onShow: function() { | ||
this.view.close(); | ||
} | ||
}); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
# Marionette.Behaviors | ||
|
||
'Marionette.Behaviors' is a utility class that takes care of glueing your `behavior` instances to their given `View`. | ||
The most important part of this class is that you **MUST** override the class level `behaviorsLookup` method for things to work properly. | ||
|
||
## Documentation Index | ||
* [API](#api) | ||
* [Behaviors Lookup](#behaviorsLookup) | ||
* [getBehaviorClass](#getBehaviorClass) | ||
* [behaviorClass](#behaviorClass) | ||
|
||
## API | ||
|
||
There are two class level methods that you can override on the `Behaviors` class. The rest of the class is tied to under the hood implementation details of views. | ||
|
||
### behaviorsLookup | ||
|
||
This method defines where your behavior classes are stored. A simple implementation might look something like this. | ||
|
||
```js | ||
Marionette.Behaviors.behaviorsLookup = function() { | ||
return window.Behaviors; | ||
} | ||
``` | ||
|
||
By default the behaviors are looked up by their key value in a given views behavior hash. | ||
|
||
In this sample (using the default `getBehaviorClass` implementation) your code will expect the following behaviors to be present in `window.Behaviors.CloseWarn` and `window.Behaviors.ToolTip` | ||
|
||
```js | ||
var MyView = Marionette.ItemView.extend({ | ||
behaviors: { | ||
CloseWarn: { | ||
message: "you are closing all your data is now gone!" | ||
}, | ||
ToolTip: { | ||
text: "what a nice mouse you have" | ||
} | ||
} | ||
}); | ||
``` | ||
|
||
### getBehaviorClass | ||
|
||
This method has a default implementation that is simple to override. It is responsible for the lookup of single behavior from within the `Behaviors.behaviorsLookup` or elsewhere. | ||
|
||
```js | ||
getBehaviorClass: function(options, key) { | ||
if (options.BehaviorClass) { | ||
return options.BehaviorClass; | ||
} | ||
|
||
return Behaviors.behaviorsLookup[key]; | ||
} | ||
``` | ||
|
||
### behaviorClass | ||
|
||
This property lets you pass a `class` in for the `behavior` to use (bypassing the normal key based lookup). This is nice to have when the behavior is a dependency of the view in [requirejs](http://requirejs.org/). Properties passed in this way will be used in `getBehaviorClass`. | ||
|
||
```js | ||
define(['lib/tooltip'], function(Tooltip) { | ||
var View = Marionette.ItemView.extend({ | ||
behaviors: { | ||
Tooltip: { | ||
behaviorClass: Tooltip, | ||
message: "hello world" | ||
} | ||
} | ||
}); | ||
}); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.