PureMVC Architects Lounge

PureMVC Manifold => Multicore Version => Topic started by: mikebritton on September 21, 2012, 11:03:54



Title: Using JS-Signals with View Components
Post by: mikebritton on September 21, 2012, 11:03:54
I wanted to post this because I'm having a lot of luck with JS-Signals http://millermedeiros.github.com/js-signals/ (http://millermedeiros.github.com/js-signals/) in the Views and Mediators of a jQuery-based application, specifically around the area of handling user interaction from viewComponent.  Obviously there are alternatives, but this one is turning out to be fairly clean and straightforward.

I'm using:
  • PureMVC Javascript http://trac.puremvc.org/PureMVC_JS/browser/branches/native-multicore/ (http://trac.puremvc.org/PureMVC_JS/browser/branches/native-multicore/)
  • jQuery http://jquery.com/
  • Underscore http://underscorejs.org/

I'm instantiating a new view component on the Mediator's on Register, and calling setViewComponent(). 

:
/**
 * @author Mike Britton
 *
 * @class ScrollerMediator
 *
 *
 *
 */

puremvc.define({
    name : 'rps.view.mediator.ScrollerMediator',
    parent : puremvc.Mediator
},
// INSTANCE MEMBERS
{
    /** @override */
    listNotificationInterests : function() {
        return [rps.AppConstants.NOTE_PAGES_RETRIEVED,rps.AppConstants.NOTE_APP_RESIZE];
    },
    /** @override */
    onRegister : function() {
       
        // Create the viewComponent
        this.setViewComponent(new rps.view.component.ScrollerComponent);
       
        // Establish signal listeners
        this.doSignals();
       
    },
    /** @override */
    handleNotification : function(note) {
        //console.log('ScrollerMediator::handleNotification - ' + note.getName());

        switch (note.getName()) {
            case rps.AppConstants.NOTE_APP_RESIZE:
                this.getViewComponent().updateUI(note.getBody());
                this.doSignals();
                break;
            case rps.AppConstants.NOTE_PAGES_RETRIEVED:
                this.getViewComponent().build(note.getBody());
                break;
        }
    },
    doSignals:function(){
        var target = this;
        $.each(this.getViewComponent().signals, function(index, item) {
           if (!item.has(target.handleEvent)) {
               // Second arg is scope
               item.add(target.handleEvent, target);
           }
        });     
    },
    handleEvent : function(signal) {
       switch(signal){
           case rps.view.component.ScrollerComponent.SIGNAL_READY:
              //console.log('ScrollerMediator::Signal '+signal+' received');
           break;
       };

    }
},
// STATIC MEMBERS
{
    /**
     * @static
     * @type {string}
     */
    NAME : 'ScrollerMediator'
});

Inside the view component, I call build() and use underscore.js to retrieve templates:

:
var comp = _.template($('#stripsTmpl').html());

An underscore template looks like this in HTML:

:
<script type="text/template" id="stripsTmpl">
    <div id="pagesX" class="pagesX" style="width:<%- pagesXWidth %>px;height:<%- pagesXHeight %>px;"></div>
    <div id="pagesY" style="position:absolute;width:<%- pagesYWidth %>px;height:<%- pagesYHeight %>px;"></div>
</script>

Back in my component class, I have public signals[], each key being a new signals.Signal(). In my Mediator, I call doSignals() once the viewComponent has been created, and set a single handler (see above) for all signals.  All user interactions in the viewComponent dispatch Signals back to the Mediator's handleEvent().

Scope issues between viewComponent and Mediator are handled with a Signals context argument:

:
doSignals:function(){
    var target = this;
    $.each(this.getViewComponent().signals, function(index, item) {
       if (!item.has(target.handleEvent)) {
           // Second arg is scope
           item.add(target.handleEvent, target);
       }
    });     
},

Why use Signals?  I don't want to troubleshoot native events until their implementation stabilizes across browsers and platforms.  (At least not for client projects.)  I want to abstract them, to keep my architecture safe from contamination by proprietary hocus-pocus with respect to event programming.  Not sure if this is the right approach, but it feels right.

Hope this proves useful, either directly or as an example of how not to do it!   ;D


Mike