-
Notifications
You must be signed in to change notification settings - Fork 2
viewcontroller
The ViewController Object has two primary differentiating abilities from a View Object. The first is a solution to a 'page-lifecycle' issue. Sometimes a Rails partial may want to instantiate a Javascript Class, but you would like that class to be added as a child to a View Class that is instantiated on the Rails view 'hosting' the partial. Since the scripts on the partial will be evaluated first, the desired 'parent' View Class will not exist yet. To solve this the Rails partial can push descriptor objects into the sudo.descriptors
array:
// script block in _foo_partial.html.erb
sudo.descriptors.push({
is_a: sudo.View,
el: '#bar',
data: {baz: '<%= qux %>} // 'qux' assumed to be a 'local' to this partial
});
The recognized keys for a descriptor are:
-
is_a: A 'path' to an existing Class definition (as viewed from
window
). The value here is not a string and is expected to be callable via new. - el: Any acceptable View el argument.
- data: Any acceptable View data argument.
- name: An optional name the ViewController may fetch the child by. See Container.
- observe(s): An optional hash used to establish observation of a model.
Given an array of descriptors in its model, a ViewController will instantiate them automagically, adding them as children as it goes. So the Rails view 'hosting' the partial that pushed to the sudo.descriptors
would instantiate its ViewController:
new sudo.ViewController('#foo', {
descriptors: sudo.descriptors
});
###Descriptors
Objects representing an instance of an existing Class Definition that you want a ViewController to instantiate and add as a child. The format of the child descriptor should be as follows:
{is_a: sudo.View}
Only the is_a
attribute is required, this would result in a new
instance of a sudo.View class Object
being located at parent.children[0]
. Usually you will want to name the child to take advantage of
the parent's ability to fetch a child by name:
{
is_a: sudo.View,
name: 'foo'
}
parent.getChild('foo')
could then be used.
####Other Options for Descriptors
As with any sudo.View
type object if an el
is not specified one will be created as a fragment, follow the same rules as you would for a View type when providing an el
(or not). The same applies for the data
object argument:
{
is_a: sudo.View,
el: '#foo',
name: 'bar'
data: {
baz: false,
qux: true
}
}
Obviously this View will encapsulate the DOM Element with the id
of 'oldMan'. If Desired you can also specify a callback on an observable instance (or an array of them for multiple 'observers')
{
is_a: sudo.View,
el: '#foo',
name: 'bar'
data: {
baz: false,
qux: true
},
observe: {
object: 'vot.model',
cb: 'zim'
}
}
#####The Observe Object
-
object: Optional Model type Object (or subclass) extended with the observable extension. Notice that the value is entered as a string, this allows sudo to look up the object at runtime thus avoiding the problem of an
undefined
reference as the descriptors may be evaluated first. This value should be a full path to the object from the Global level. Thus, if you wanted to observe a global-level Object named 'foo' you would useobject: "foo"
, if "foo" were a namespace however, use apath
argument from there. For examle,object: "foo.bar"
,bar
being anobservable
contained in thefoo
namespace. If omitted, the ViewController's model is observed. -
cb: Mandatory function that will be called by the 'observable' when the observed value changes. The string is assumed to be a method existing on the class object being created, thus that will be the scope of the function.
###UJS Abstraction
As the ViewController is intended to be a Rails nicety it makes sense to have a strategy for 'ujs'. If you have a :remote => true
enabled control in use on your page, include a ujsEvent (or ujsEvents when observing multiple) in your data argument or model reference:
var foo = new sudo.ViewController('#bar', {
ujsEvent: 'ajax:complete'
});
Or:
var foo = new sudo.ViewController('#bar', {
ujsEvents: ['ajax:success', 'ajax:error']
});
The format ajax:foo
is it accordance with the jquery-rails plugin. A ViewController instance will map the following virtual methods to any of the seven 'ujs' style custom events found:
{
'ajax:before': 'onAjaxBefore',
'ajax:beforeSend': 'onAjaxBeforeSend',
'ajax:success': 'onAjaxSuccess',
'ajax:error': 'onAjaxError',
'ajax:complete': 'onAjaxComplete',
'ajax:aborted:required': 'onAjaxAbortedRequired',
'ajax:aborted:file': 'onAjaxAbortedFile'
}
Therefore, once you have 'subscribed' to one of these you need to provide an overriden method in your ViewController to serve as the callback. Method signatures can be found in the jquery-ujs docs:
var Foo = function(el, data) {
this.construct(el, data);
};
Foo.prototype = Object.create(sudo.ViewController.prototype);
Foo.prototype.onAjaxComplete = function(event, xhr, status) {
// do stuff
};
This subclass could then be instantiated var foo = new Foo('#bar', {ujsEvent: 'ajax:complete'});