Class: ElementView

maria. ElementView

new ElementView(model, controller, document)

A constructor function to create new element view objects.

var elementView = new maria.ElementView();

This constructor function takes three optional arguments.

var model = new maria.Model();
var controller = new maria.Controller();
var myFrameDoc = window.frames['myFrame'].document;
var elementView =
    new maria.ElementView(model, controller, myFrameDoc);

The null or undefined value can be passed for any of these three parameters to skip setting it.

The purpose of the third document parameter is to allow the creation of element views in one window that will be shown in another window. At least some older browsers do not allow a DOM element created with one document object to be appended to another document object.

An element view is a view (inheriting from maria.View) and so has a model and controller. See maria.View for more documentation about setting and getting the model and controller objects.

What makes maria.ElementView different from the more abstract maria.View is that an element view has the concept of a "root element" which is the main DOM element that acts as a container for all the other DOM elements that are part of the element view.

The DOM is built using the getTemplate method which should return a fragment of HTML for a single DOM element and its children. By default the template is just an empty div element. You can redefine or override this to suit your needs.

maria.ElementView.prototype.getTemplate = function() {
    return '<div>' +
               '<span class="greeting">hello</span>, ' +
               '<span class="name">world</span>' +
           '</div>';
};

When an element view is created and its HTML template is rendered as a DOM element, the view will automatically start listening to the DOM element or its children for the events specified in the map returned by the getUIActions method. This map is empty by default but you can redefine or override as necessary and supply the necessary handler functions which usually delegate to the controller.

maria.ElementView.prototype.getUIActions = function() {
    return {
        'mouseover .greeting': 'onMouseoverGreeting',
        'click .name'        : 'onClickName'
    };
};

maria.ElementView.prototype.onMouseoverGreeting = function(evt) {
    this.getController().onMouseoverGreeting(evt);
};

maria.ElementView.prototype.onClickName = function(evt) {
    this.getController().onClickName(evt);
};

Only a few simple CSS selectors are allowed in the keys of the UI action map. An id can be used like "#alpha" but this is not recommended. A class name like ".greeting", a tag name like "div", or a combination of tag name and class name like "div.greeting" are acceptable. In almost all cases, a single class name is sufficient and recommended as the best practice. (If you need more complex selectors you can use a different query library to replace the Grail library used by default in Maria.)

You can find an element or multiple elements in a view using the element view's find and findAll methods.

elementView.find('.name');   // returns a DOM element
elementView.findAll('span'); // returns an array

Because maria.View objects are composite views, so are maria.ElementView objects. This means that sub-element-view objects can be added to an element view. By default the sub-element-view object's root DOM element will be added to the parent element view's root DOM element. You can change the element to which they are added by redefining or overridding the getContainerEl function.

maria.ElementView.prototype.getContainerEl = function() {
    return this.find('.name');
};

A particularly useful pattern is using maria.ElementView as the "superclass" of your application's element views. The following example shows how this can be done at a low level for a to-do application. See maria.ElementView.subclass for a much more compact way to accomplish the same.

checkit.TodoView = function() {
    maria.ElementView.apply(this, arguments);
};
checkit.TodoView.superConstructor = maria.ElementView;
checkit.TodoView.prototype = maria.create(maria.ElementView.prototype);
checkit.TodoView.prototype.constructor = checkit.TodoView;
checkit.TodoView.prototype.getDefaultControllerConstructor = function() {
    return checkit.TodoController;
};
checkit.TodoView.prototype.getTemplate = function() {
    return checkit.TodoTemplate;
};
checkit.TodoView.prototype.getUIActions = function() {
    return {
        'click     .check'       : 'onClickCheck'     ,
        'dblclick  .todo-content': 'onDblclickDisplay',
        'keyup     .todo-input'  : 'onKeyupInput'     ,
        'keypress  .todo-input'  : 'onKeypressInput'  ,
        'blur      .todo-input'  : 'onBlurInput'
    };
};
checkit.TodoView.prototype.onClickCheck = function(evt) {
    this.getController().onClickCheck(evt);
};
checkit.TodoView.prototype.onDblclickDisplay = function(evt) {
    this.getController().onDblclickDisplay(evt);
};
checkit.TodoView.prototype.onKeyupInput = function(evt) {
    this.getController().onKeyupInput(evt);
};
checkit.TodoView.prototype.onKeypressInput = function(evt) {
    this.getController().onKeypressInput(evt);
};
checkit.TodoView.prototype.onBlurInput = function(evt) {
    this.getController().onBlurInput(evt);
};
checkit.TodoView.prototype.buildData = function() {
    var model = this.getModel();
    var content = model.getContent();
    this.find('.todo-content').innerHTML = checkit.escapeHTML(content);
    this.find('.check').checked = model.isDone();
    aristocrat[model.isDone() ? 'addClass' : 'removeClass'](this.find('.todo'), 'done');
};
checkit.TodoView.prototype.update = function() {
    this.buildData();
};
checkit.TodoView.prototype.showEdit = function() {
    var input = this.find('.todo-input');
    input.value = this.getModel().getContent();
    aristocrat.addClass(this.find('.todo'), 'editing');
    input.select();
};
checkit.TodoView.prototype.showDisplay = function() {
    aristocrat.removeClass(this.find('.todo'), 'editing');
};
checkit.TodoView.prototype.getInputValue = function() {
    return this.find('.todo-input').value;
};
checkit.TodoView.prototype.showToolTip = function() {
    this.find('.ui-tooltip-top').style.display = 'block';
};
checkit.TodoView.prototype.hideToolTip = function() {
    this.find('.ui-tooltip-top').style.display = 'none';
};
Parameters:
Name Type Argument Description
model maria.Model <optional>
controller maria.Controller <optional>
document Document <optional>
Source:
  • maria.js, line 2730

Extends

Members

<static> superConstructor

Properties:
Name Type Description
maria.ElementView.superConstructor
Source:
  • maria.js, line 2740

Methods

<static> subclass()

A function that makes subclassing maria.ElementView more compact.

The following example creates a checkit.TodoView constructor function equivalent to the more verbose example shown in the documentation for maria.ElementView.

maria.ElementView.subclass(checkit, 'TodoView', {
    uiActions: {
        'click     .check'       : 'onClickCheck'     ,
        'dblclick  .todo-content': 'onDblclickDisplay',
        'keyup     .todo-input'  : 'onKeyupInput'     ,
        'keypress  .todo-input'  : 'onKeypressInput'  ,
        'blur      .todo-input'  : 'onBlurInput'
    },
    properties: {
        buildData: function() {
            var model = this.getModel();
            var content = model.getContent();
            this.find('.todo-content').innerHTML = checkit.escapeHTML(content);
            this.find('.check').checked = model.isDone();
            aristocrat[model.isDone() ? 'addClass' : 'removeClass'](this.find('.todo'), 'done');
        },
        update: function() {
            this.buildData();
        },
        showEdit: function() {
            var input = this.find('.todo-input');
            input.value = this.getModel().getContent();
            aristocrat.addClass(this.find('.todo'), 'editing');
            input.select();
        },
        showDisplay: function() {
            aristocrat.removeClass(this.find('.todo'), 'editing');
        },
        getInputValue: function() {
            return this.find('.todo-input').value;
        },
        showToolTip: function() {
            this.find('.ui-tooltip-top').style.display = 'block';
        },
        hideToolTip: function() {
            this.find('.ui-tooltip-top').style.display = 'none';
        }
    }
});

This subclassing function implements options following the "convention over configuration" philosophy. The checkit.TodoView will, by convention, use the checkit.TodoController and checkit.TodoTemplate objects. All of these can be configured explicitly if these conventions do not match your view's needs.

maria.ElementView.subclass(checkit, 'TodoView', {
    controllerConstructor: checkit.TodoController,
    template             : checkit.TodoTemplate  ,
    uiActions: {
    ...

Alternately you can use late binding by supplying string names of objects in the application's namespace object (i.e. the checkit object in this example).

maria.ElementView.subclass(checkit, 'TodoView', {
    controllerConstructorName: 'TodoController',
    templateName             : 'TodoTemplate'  ,
    uiActions: {
    ...

You can augment uiActions in your subclass by specifying the declarative moreUIActions property (instead of using uiActions.)

checkit.TodoView.subclass(checkit, 'ReminderView', {
    moreUIActions: {
        'click .reminder': 'onClickReminder'
    },
    properties: {
        showReminder: function() {
            this.find('.todo-reminder').style.display = 'block';
        },
        hideReminder: function() {
            this.find('.todo-reminder').style.display = 'none';
        }
    }
});

The ReminderView will inherit the properties defined in uiActions from TodoView and augment it with moreUIActions. The subclassing function will generate the equivalent of the following function.

checkit.TodoView.prototype.getUIActions = function () {
    var uiActions = checkit.TodoView.superConstructor.prototype.getUIActions.call(this);
    uiActions['click .reminder'] = 'onClickReminder';
    return uiActions;
};
Source:
  • maria.js, line 3542

build() → {Element}

Builds the root DOM element for the view from the view's template returned by getTemplate, attaches event handlers to the root and its descendents as specified by the UI actions map returned by getUIActions, calls the buildData method to allow model values to be inserted into the root DOM element and its descendents, and calls buildChildViews. This construction of the root DOM element is lazy and only done when this method is called.

Source:
  • maria.js, line 2810
Returns:

The root DOM Element of the view.

Type
Element

buildData()

Does nothing by default. To be overridden by subclasses.

The intended use of this method is to populate the built root DOM element and its descendents with model data.

Source:
  • maria.js, line 2874

buildTemplate()

Parses the HTML template string returned by getTemplate to create a DocumentFragment. The first child of that DocumentFragment is set as the root element of this view. All other sibling elements of the DocumentFragment are discarded.

Source:
  • maria.js, line 2828

buildUIActions()

Attaches event handlers to the root and its descendents as specified by the UI actions map returned by getUIActions.

Source:
  • maria.js, line 2848

find(selector) → {Element}

Find the first element in this view that matches the CSS selector. The view's root element can be the result.

By default Maria uses the Grail library as its DOM query engine. This is to support older browsers that do not have querySelector. The Grail engine only a limited set of simple selectors.

.class
tag
tag.class
#id

If your application only needs to work in newer browsers then you can create a Maria plugin to use querySelector. Consider if you want the root element to be returned if it matches selector.

If your application needs to work in older browsers but you need more complex CSS selector strings then you can create a Maria plugin to use some libray other than Grail.

Parameters:
Name Type Description
selector string

A CSS selector.

Source:
  • maria.js, line 2962
Returns:

The first DOM element matching selector.

Type
Element

findAll(selector) → {Array}

Find all the elements in this view that matches the CSS selector. The view's root element can be in the result set.

See find for more details.

Parameters:
Name Type Description
selector string

A CSS selector.

Source:
  • maria.js, line 2978
Returns:

An array of the DOM elements matching selector.

Type
Array

getContainerEl() → {Element}

See buildChildViews for more details.

Source:
  • maria.js, line 2899
Returns:

The DOM Element to which child view's should be attached.

Type
Element

getController() → {maria.Controller}

If this view has not yet had its controller set then this method creates a controller and sets it as this view's controller.

Inherited From:
Source:
  • maria.js, line 2487
Returns:

The controller object.

Type
maria.Controller

getDefaultController() → {maria.Controller}

Creates a new default controller for this view.

Inherited From:
Source:
  • maria.js, line 2473
Returns:

The controller object.

Type
maria.Controller

getDefaultControllerConstructor() → {function}

Returns a controller constructor function to be used to create a controller for this view.

Inherited From:
Source:
  • maria.js, line 2462
Returns:

The controller constructor function.

Type
function

getDocument() → {Document}

Returns the web page document for the view. This document is the one used to create elements to be added to the page, for example.

Source:
  • maria.js, line 2754
Returns:

The document object.

Type
Document

getModel() → {maria.Model}

Returns the current model object of this view.

Inherited From:
Source:
  • maria.js, line 2439
Returns:

The model object.

Type
maria.Model

getModelActions() → {Object}

When the model is set for this view, the view will automatically observe the events which are keys of the returned object. The values for each key is the view's handler method to be called when the corresponding event is dispatched on the model.

By default, a view will observe the model for change events and handle those events with the view's update method.

You can override this method but, beware, doing so can lead to the dark side.

Inherited From:
Source:
  • maria.js, line 2521
Returns:

The map of model events and view handers.

Type
Object

getTemplate() → {string}

Returns the template for this view used during the build process.

Source:
  • maria.js, line 2780
Returns:

The template HTML string.

Type
string

getUIActions() → {Object}

The UI actions object maps a UI action like a click on a button with a handler method name. By default, the handler will be called on the controller of the view.

Source:
  • maria.js, line 2793
Returns:

The UI actions map.

Type
Object

insertBefore(newChild, oldChild)

Add a new child view before an existing child view. If the oldChild parameter is not supplied then the newChild is appened as the last child.

Parameters:
Name Type Description
newChild maria.ElementView

The child to be inserted.

oldChild maria.ElementView

The child to insert before.

Source:
  • maria.js, line 2913

removeChild(oldChild)

Remove an existing child view.

Parameters:
Name Type Description
oldChild maria.ElementView

The child to be removed.

Source:
  • maria.js, line 2927

setController(The)

Set the current controller for this view.

Parameters:
Name Type Description
The maria.Controller

controller object.

Inherited From:
Source:
  • maria.js, line 2501

setDocument()

Set the web page document for the view. This document is the one used to create elements to be added to the page, for example.

Source:
  • maria.js, line 2765

setModel(model)

Set the current model object of this view.

Parameters:
Name Type Description
model maria.Model

The model object.

Inherited From:
Source:
  • maria.js, line 2450

update(event)

By default, a view will observe its model for change events. When a change event is dispatched on the model then this update method is the handler. (The "change" and "update" names are inherited directly from Smalltalk implementations.)

To be overridden by subclasses.

Parameters:
Name Type Description
event object

The event object.

Inherited From:
Source:
  • maria.js, line 2428