petermichaux / maria

The MVC framework for JavaScript applications. The real MVC. The Smalltalk MVC. The Gang of Four MVC.
BSD 2-Clause "Simplified" License
764 stars 51 forks source link

add uiOutlets #80

Closed petermichaux closed 10 years ago

petermichaux commented 10 years ago

A view's buildData method frequently calls this.find

buildData: function () {
    var model = this.getModel();
    this.find('.firstName').innerHTML = model.getFirstName();
    this.find('.lastName').innerHTML = model.getLastName();
}

The above code is good because it is late binding. When build needs an element in the DOM, it finds it just when it needs it. That means the DOM can change but the right thing will still be updated.

Late binding is not usually needed for this as the DOM for the view usually has a fixed set of nodes. Late binding does have a look-up cost.

It would be nice to be able to write

`uiOutlets`: {
    // prop : CSS selector
    firstName: '.firstName',
    lastName: '.lastName',
},
properties: {
    buildData: function () {
        var model = this.getModel();
        this.getFirstName().innerHTML = model.getFirstName();
        this.getLastName.innerHTML = model.getLastName();
    }

Note that uiOutlets has the CSS selector as the value of each property. In uiActions the CSS selector is part of the key. This reversal is because outlets are conceptually for sending data from the view to the DOM. On the other hand actions are conceptually for accepting events from the DOM to the view. The directions are opposite.

Also add moreUIOutlets like moreUIActions.

The terminology "outlet" comes from Apple iOS/Mac/Cocoa/XCode programming.

petermichaux commented 10 years ago

Could add a method refreshOutlets that would rebind the view's cached DOM nodes to the current DOM.

petermichaux commented 10 years ago

I suppose outlets could still be late binding. The getFirstName method could call this.find(selector);

petermichaux commented 10 years ago

In our work programs, there are 22 uses of this.findAll and 240 uses of this.find. Clearly finding single elements in the DOM has been more important to us than finding multiple elements. Even so, it seems wrong to build something for Maria that only works for single elements.

There are many possiblities. In the following examples suppose there is one element in the DOM that shows the first name but several elements that show the last name.

// option 1: forget about plural
//
uiOutlets: {
    firstName: '.firstName',
    lastNames: '.lastName'
},
properties: {
    buildData: function () {
        var model = this.getModel();
        this.getFirstName().innerHTML = model.getFirstName();
        this.findAll('.lastName').forEach(function(el) {
            el.innerHTML = model.getLastName();
        });      

// option 2: singular and plural methods
//
uiOutlets: {
    firstName: '.firstName',
    lastNames: '.lastName'
},
properties: {
    buildData: function () {
        var model = this.getModel();
        this.getOutlet('firstName').innerHTML = model.getFirstName();
        this.getOutlets('lastNames').forEach(function(el) {
            el.innerHTML = model.getLastName();
        });

// option 3: separate singular and plural configration
//
uiOutlet: {
    firstName: '.firstName'
},
uiOutlets: {
    lastNames: '.lastName'
},
properties: {
    buildData: function () {
        var model = this.getModel();
        this.getFirstName().innerHTML = model.getFirstName();
        this.getLastNames().forEach(function(el) {
            el.innerHTML = model.getLastName();
        });

// option 4: combined singular and plural configration
//
uiOutlets: {
    "one firstName": '.firstName',
    "all lastNames": '.lastName'
},
properties: {
    buildData: function () {
        var model = this.getModel();
        this.getFirstName().innerHTML = model.getFirstName();
        this.getLastNames().forEach(function(el) {
            el.innerHTML = model.getLastName();
        });

What about getFirstName vs. findFirstName?

The right thing to do is write this as a plugin, use it for a while, and if something surfaces as great then integrate it into Maria.

jamesladd commented 10 years ago

I'm leaning towards option #4

uiOutlets: { "firstName": '.firstName', "lastName[]": '.lastName' },

I'd be happier with this syntax (also ok with [] being at front of selector as in [] lastName).

This might help in the cases where the selector is a plural already. Dipss anyone?

petermichaux commented 10 years ago

I thought about using a terminal 's' character to indicate plural. It doesn't work with all languages. It doesn't even work with English in all cases. I don't want to end up with "sheeps" as a key in the configuration to indicate returning an array.

The brackets is a good option. Thanks. I think I would still pluralize so that the getter is this.getLastNames() or this.findLastNames().

uiOutlets: {
    "firstName": '.firstName',
    "lastNames[]": '.lastName'
},

I think the square brackets is the candidate leading the polls.

jamesladd commented 10 years ago

Thank you for asking me/us.

Sent from the holodeck.

On 28 Jun 2014, at 4:01 pm, Peter Michaux notifications@github.com wrote:

I thought about using a terminal 's' character to indicate plural. It doesn't work with all languages. It doesn't even work with English in all cases. I don't want to end up with "sheeps" as a key in the configuration to indicate returning an array.

The brackets is a good option. Thanks. I think I would still pluralize so that the getter is this.getLastNames() or this.findLastNames().

uiOutlets: { "firstName": '.firstName', "lastNames[]": '.lastName' }, I think the square brackets is the candidate leading the polls.

— Reply to this email directly or view it on GitHub.

petermichaux commented 10 years ago

Late binding means the view doesn't hold strong references to DOM objects. This possibly helps garbage collection.

petermichaux commented 10 years ago

I'm in favour of "uiOutlets", "lastName[]", late binding, and this.findLastName().

jamesladd commented 10 years ago

+1

Sent from the holodeck.

On 29 Jun 2014, at 6:21 am, Peter Michaux notifications@github.com wrote:

I'm in favour of "uiOutlets", "lastName[]", late binding, and this.findLastName().

— Reply to this email directly or view it on GitHub.

racino commented 10 years ago

+1 Very good idea with the square brackets.

petermichaux commented 10 years ago

Implemented as a Maria plugin. If it is generally useful will consider integration into Maria core.

https://github.com/petermichaux/maria-outlets

Went with "outlets" instead of "uiOutlets".

jamesladd commented 10 years ago

Awesome!

Sent from the holodeck.

On 3 Jul 2014, at 11:50 am, Peter Michaux notifications@github.com wrote:

Implemented as a Maria plugin. If it is generally useful will consider integration into Maria core.

https://github.com/petermichaux/maria-outlets

Went with "outlets" instead of "uiOutlets".

— Reply to this email directly or view it on GitHub.