ripplejs / ripple

A tiny foundation for building reactive views
http://ripplejs.github.io
1.28k stars 66 forks source link

Event handlers to Views created with selectors #38

Closed pltod closed 10 years ago

pltod commented 10 years ago

1. Creating view with selector

When I run the test suite the following test is running well:

  it('should create a view with a selector', function () {
    var test = document.createElement('div');
    test.id = 'foo';
    document.body.appendChild(test);
    View = ripple('#foo');
    var view = new View();
    assert(view.template = '<div id="foo"></div>');
  });

But in reality when I try to create a view with selector out of existing DOM it cuts out the wrapper. For example:

html -> <button id='myButton'>Save</button>

js -> var View = ripple('#myButton'); var viewInstance = new View()

I end up having viewInstance.template = 'Save'. I guess due to this code in getTemplate:

  if (typeof template.innerHTML === 'string') {
    template = template.innerHTML;
  }

2. View with selector + Event Handlers (events plugin)

What is the best practice of attaching event handlers to Views created with selectors?

Again:

html -> <button id='myButton' on-click="{{ this.save }}">Save</button>

js -> var View = ripple('#myButton'); ....

I found that I must do viewInstance.replace('#myButton') (probably to trigger mount event and make it work). And note that this is only going to work if I avoid the problem in 1. I put myButton in kind of wrapper - lets say:

<div id='d'><button id='myButton' on-click="{{ this.save }}">Save</button></div>

and then var View = ripple('#d');

anthonyshort commented 10 years ago

The original idea for creating views from selectors was to store the templates in a script tag,

<script id="template" type="text/template">
  <button on-click="{{ this.save }}">Save</button>
</script>

So then you'd do ripple('#template') and have a view whose this.el was a button element. Then you'd place that in the DOM somewhere.

I can definitely see how it could be nice to select an element and just replace it on the spot as well. It probably won't work directly with the current syntax. It might be something that would be good for a plugin or just it's own module.

module.exports = function(selector) {
   var el = document.querySelector(selector) || throw new Error('missing element');
   var template = el.outerHTML;
   var View = ripple(template);
   View.once('ready', function(view){
      view.replace(el);
   });
   return View;
};

Now whenever this view is created it will automatically mount itself in the DOM and replace the original element. This could be a little weird since any time an instance is created it'll try and replace that element.

pltod commented 10 years ago

Now all make sense. Thanks for explaining the intended usage.

Refactoring existing application (giving powers without writing new DOM) is the possible use case for what I tried to do. For example in Twitter Flight we could define component Button and directly attach it to existing DOM with:

Button.attachTo('#myButton', {options});

I will re-think all this again to see if similar behaviour is relevant and could fit well in the context of ripple.

anthonyshort commented 10 years ago

It's definitely something I've been thinking about too, because I want to have server-rendered elements automatically attach to views.