Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

For data-value binding allow developer to pick different event (right now 'change' is hard coded in) #122

Open
kdocki opened this issue Feb 13, 2013 · 7 comments

Comments

@kdocki
Copy link

kdocki commented Feb 13, 2013

If you were to change the binding for 'data-value' to do something like...

value: {
  publishes: true,
  bind: function(el) {
    var changeOn = 'change';
    var selector = (rivets.config.prefix) ? rivets.config.prefix + '-' : '';
    selector += 'change-on';
    if (jQuery && jQuery(el).data(selector)) {
        changeOn = jQuery(el).data(selector);
    }
            return this.currentListener = bindEvent(el, changeOn, this.publish);
},

Then we could do something like this:
< input type="text" data-value="foo.bar" data-change-on="keyup" >

Currently I only know 2 ways to do a keyup

  1. write a mutator function... something like what is below. This works but means we have to write a bunch of change functions just to set the value of the object which gets repetitive and old if you've got several data-values binded.
    < input type="text" data-on-keyup="foo.changeBar" >
    var foo = Backbone.Model({ bar: 'test", changeBar: function() { ... change bar here }});

  2. write a binding to do this for me (called it data-model below, but this seems a little hackish)
    < input type="text" data-model="foo.bar" data-change-on="keyup" >

For those of us from the angularjs world we are used to the model changing on keyup instead of change. This flexibility to change the event handling would allow the developer to choose when they want to change their data-value binding.

@kdocki
Copy link
Author

kdocki commented Feb 13, 2013

Not really an issue but a feature enhancement request.

@mikeric
Copy link
Owner

mikeric commented Apr 8, 2013

Not sure why I didn't think of it before, but having the ability to pass options to binding declarations would solve this problem very elegantly and eliminate the need to create separate binders with duplicate logic (or dependencies on other attributes on that node).

To keep the syntax of Rivets.js reminiscent of a unix shell, it might look like this.

# set the item.name value on keyup
<input data-value="item.name --on keyup">

# set the item.name value on input
<input data-value="item.name --on input">

The nice thing about doing it this way, is that we can store all the defaults on the binder directly, which could then be changed by the user. So if you want the default event for changes to be input, for example.

rivets.binders.value.options.on = 'input'

That would make all value bindings listen on input by default. If you don't want to listen on input for a particular value binding, you can easily just specify a different event.

<input data-value="item.name --on change">

Another core binder that could make use of this would be the each-[item] binder, for a couple of reasons.

  1. People have asked to be able to access the current index in each iteration. Options would provide a nice interface to specify which variable to use for the index/count to prevent context collisions.

    <li data-each-item="list.items --index itemIndex">
      <span data-text=":itemIndex"></span>
      <span data-text="item.name"></span>
    </li>
  2. For users to implement iteration binding/unbinding on other collections instead of arrays, such as backbone collections, etc. without having to create a separate binder that shares the same routine.

    <li data-each-item="list.items --type backbone"></li>

@yocontra
Copy link
Contributor

yocontra commented Apr 8, 2013

@mikeric - Really liking the idea of being able to pass flags in. I think with that and maybe an improvement or two to the way arguments are passed to formatters the binding syntax will be 👍

@pcorcoran
Copy link
Contributor

Along these lines, I'm not sure how to manually trigger an update to bindings.

The use case is a binding with data-show="thing:customShowLogic". I want this binding to be recomputed from time to time, and not necessarily only when a model field has changed. (Though "thing" does represent the model and the model will be considered when determining the new return value.)

Currently a call to bindings.sync() would seem to accomplish this. But such a call has side-effects that aren't desirable. (For instance, bind the model's main "change" event to a call to bindings.sync() seems to create an infinite work loop. At least that's my experience when doing so within a more complex app.)

For my purposes, I could make do with a general purpose "any change is fine" watch parameter, such as: data-show="thing:customShowLogic < *". Or instead, riffing on the above suggestions, I could also use a data-show="thing:customShowLogic --on mycustomevent", whereupon I can trigger mycustomevent whenever I want a recalc.

But it might be more convenient for me to instead be able to call a method like bindings.recalculate(), which updates the model -> view display of the binding by recomputing everything as if it were being rendered anew, but without the view -> model sync that sync() seems to invoke.

@mikeric
Copy link
Owner

mikeric commented Jun 3, 2013

@pcorcoran In the mean time, have you tried calling Rivets.View#update with the model you want to update? This will update only the bindings for that model.

bindings.update thing: thing

I definitely agree though that it would be nice to have a function that loops through only the adapter-bypassed bindings (the ones that use :) and updates them. This would be analogous to re-rendering a static template, but not as intensive because we don't need to parse and re-render the entire thing, only the static bindings in the view. Further, it would be even better if we could only recompute a specific model or model + property.

# recomputes all static bindings in the view
bindings.recompute()

# recomputes all static bindings on thing
bindings.recompute thing

# recomputes only the static bindings on the
# customShowShowLogic property on thing.
bindings.recompute thing, "customShowLogic"

Until then, you can do this manually using the Rivets.View#select, but it's not going to be as nice.

for binding in bindings.select (b) -> b.model is thing
  binding.sync()

@kdocki
Copy link
Author

kdocki commented Jun 4, 2013

@mikeric I like the parameters stuff too. The whole idea is that rivets could be flexible enough to handle different events (like keyup). I mean... it might even be flexible enough to do something like this?

<input class="foobars" data-value="item.name --on foobarEvent"> 
<button onclick="$('.foobars').trigger('foobarEvent');">Click me</button>

@franciscolourenco
Copy link
Contributor

+1 to the ability to pass options to binding declarations.
In the meanwhile it would be useful to have a rv-input binder by default in rivets.. it would make the example for this article simpler: http://jsfiddle.net/gh3Zy/3/

Btw, is there a better way to do it than to use the formatter?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants