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

Receive arguments to binder #258

Closed
andriijas opened this issue Jan 10, 2014 · 13 comments
Closed

Receive arguments to binder #258

andriijas opened this issue Jan 10, 2014 · 13 comments

Comments

@andriijas
Copy link

Hi

I cant figure this one out, perhaps its a documentation issue. id like to do an utility helper that utilizes my frameworks url reversal methods (similar to these in django and rails)

<a rv-href="controller#method" rv-params="{id:model:id}"></a>

Example:

<a rv-href="controller#method" rv-params="{id:3}"></a>
rivets.binders.href = (el, value) ->
   # Example  utils.reverse 'controller#method', id: 3
   utils.reverse value, <params>

Thanks

@jhnns
Copy link
Contributor

jhnns commented Jan 10, 2014

Which arguments? I don't understand the question ^^

@andriijas
Copy link
Author

Update the post with proper markdown so that the examples are available :)

@jhnns
Copy link
Contributor

jhnns commented Feb 3, 2014

You need to get the params from the element:

var params = element.getAttribute("rv-params");

Or more precisely

var params = element.getAttribute(this.view.config.prefix + "-params");

@andriijas
Copy link
Author

Yupp but the problem that way would be to get the actual value of model.id id like to take advantage of model bindings here.

@jhnns
Copy link
Contributor

jhnns commented Feb 3, 2014

Well, you don't have any reference to the model...

I don't think that a function call with arguments should be notated inside of html. It gets way to complicated and requires evaluating of inline JavaScript. Reminds me of the good old times of onclick="alert('Everything\'s ok');" 😉

Imho it's better to bind a function that already has access to the model's reference. Your controller should know the model.

@andriijas
Copy link
Author

I was just thinking perhaps someone else would have already solved how to use their frontend frameworks reverse url lookup solved with bindings :) all i care for is to set the href dynamically without needing to much hassle

@jhnns
Copy link
Contributor

jhnns commented Feb 3, 2014

You're trying to generate the href depending on the model? Something like:

<a rv-href="myModel" route="blog/:blogId/post/:postId/edit" ></a>

and then:

rivets.binders.href = function (el, value) {
    var route = el.getAttribute("route");
    var href = generateHref(route, value);
    // assuming that generateHref() turns
    // blog/:blogId/post/:postId/edit into blog/2/post/3/edit

    el.setAttribute("href", href);
};

?

@MiguelCastillo
Copy link
Contributor

@jhnns Nice one. 👍

@jeron-diovis
Copy link

This should be a question similar to source one.

I have a wizard form and want to implement transition between steps using on-click binder. It seems to be logical that step name/index is also stored somewhere in bounded element. So I need to extract it and pass to model's method.

Here I have a lot of options, and I can't understand which one is correct.

  • Create a custom binder, like "rv-change-step". Just like in example above. So I can extract step from any custom attribute, create some closures and use them as click handlers in "on-click" binder (not tested):
rivets.binders.changestep = 
  bind: (el) -> 
      @args = ["click"]
      rivets.binders['on-*'].routine.call @, @el, =>
         @model.set "step", el.getAttribute("rv-change-step")
  unbind: -> rivets.binders['on-*'].unbind.call @, @el
<div rv-change-step="2">

But - isn't it too complex? Source task is dead simple - call function with argument on click - and I need some incomprehensible workaround, need new binders to do it?

  • Create a special formatter which will create new function with pre-bound arguments. It will look nice enough, like this:
<div rv-on-click="model.setStep | partial 2">

But this also means that new function will be created on each click. Which is not good, of course, so this solution looks more like a hack.

  • Forget about arguments and create a bunch of separate methods each leads to certain step. So it will be just:
<div rv-on-click="model.goToStep2">

Methods can be auto-generated, so it will be not so much code. But this is like some kind of china-code, as for me....

Please help me to understand which path is right.

@jhnns
Copy link
Contributor

jhnns commented Aug 18, 2014

I have a fourth solution 😀 :

rivets.configure({

    /**
     * The base event handler when working with dom events (e.g. when using bind-on-click).
     *
     * The handler looks for the presence of a data-[eventType]-attribute that specifies which argument should be
     * passed to the event listener. If no argument is specified, the original dom event and the binding is passed.
     *
     * The event listener is finally called on the view (which usually contains all event listeners).
     *
     * @param {Element} target
     * @param {Event} event
     * @param {rivets.Binding} binding
     */
    handler: function (target, event, binding) {
        var eventType = binding.args[0];
        var arg;

        if (target.dataset && (arg = target.dataset[eventType])) {
            this.call(binding.view.models.self, binding.view.models[arg] || arg);
        } else {
            // that's rivets' default behavior afaik
            this.call(binding.view.models.self, event, binding);
        }
    }
});

Then you can pass custom arguments to any event handler:

<a rv-on-click="model.goToStep" data-on-click="2">

The argument will be typeof string of course. To turn it into a primitive take a look at example implementation

Be careful: In my implementation the value of data-on-click is first looked up on the view. So if you got a property with this name, the value of that property is passed:

var myView = {
    "2": "Two"
};

Will pass "Two" to model.goToStep.

@jeron-diovis
Copy link

Hm, very nice... Although additional data-attributes can be confusing, it's definitely better than my first suggested solution.

However, I've also read existing issues, and now I believe that the best solution would be this.
Maybe, a PR can speed up including this ability to Rivets.

@vvo
Copy link
Contributor

vvo commented Jan 21, 2015

For anyone wondering, the good implementation of the config handler would be:

var rivets = require('rivets');

rivets.configure({
  // extracted from: https://github.com/mikeric/rivets/issues/258#issuecomment-52489864
  // This configuration allows for on- handlers to receive arguments
  // so that you can onclick="steps.go" data-on-click="share"
  handler: function (target, event, binding) {
    var eventType = binding.args[0];
    var arg = target.getAttribute('data-on-' + eventType);

    if (arg) {
      this.call(binding.model, arg);
    } else {
      // that's rivets' default behavior afaik
      this.call(binding.model, event, binding);
    }
  }
});
<a rv-on-click="steps.go" data-on-click="homePage">home</a>

Previous code was not working, surely because of changes in rivets.

@ericxin1982
Copy link

Hi @jhnns

#682
I have an open issue, like what you described, not sure how to fix, would you please help me take a look at it?

Thanks
Eric Xin

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

No branches or pull requests

6 participants