Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I bind an HTML select to a model value in Rivets.JS?

I'm trying to integrate Rivets.JS into my app. I'm getting the hang of binding values for basic form inputs and regular data in the page, but I can't figure out how to handle selects drop (down menus) with Rivets.

I can build a select with the each tag, like in this JSFiddle: http://jsfiddle.net/eimajenthat/94ca1xht/

But I want to bind the selected value in the menu to a model value (in my Fiddle, I would bind truck.job_id to the select).

Here is my JS:

$(document).ready(function(){
    window.view = rivets.bind($('#contentWrap'),{
        truck:{id:1,job_id:3},
        jobs:[
            {id:1,job_number:'thing1'},
            {id:2,job_number:'thing2'},
            {id:3,job_number:'thing3'},
            {id:4,job_number:'thing4'},
        ]
    });
});

Here is my HTML:

<div id="contentWrap">
    <select>
        <option rv-each-job="jobs" rv-value="job.id">{ job.job_number }</option>
    </select>
</div>

Bonus points: all the select elements in my app are augmented with Chosen. This means whenever I change the options or the selection via JavaScript, I need to trigger an update to Chosen for users to see it, like this:

$('#my-select').trigger('liszt:updated');

How do I trigger the code above whenever the model used for options (jobs in my Fiddle) is updated, or when the value of the select (trucks.job_id) is updated?

like image 785
eimajenthat Avatar asked Jan 29 '15 16:01

eimajenthat


1 Answers

Well, this turned out to be pretty easy. I considered deleting the question, but maybe I'm not the only idiot out there trying to do this. Here's my updated Fiddle: http://jsfiddle.net/eimajenthat/94ca1xht/2/

Here's the JS:

$(document).ready(function(){
  rivets.formatters.chosen = function(value,selector) {
    $(selector).val(value).trigger('liszt:updated');
    return value;
  };
  window.view = rivets.bind($('#contentWrap'),{
    truck:{id:1,job_id:3},
    jobs:[
      {id:1,job_number:'thing1'},
      {id:2,job_number:'thing2'},
      {id:3,job_number:'thing3'},
      {id:4,job_number:'thing4'},
    ]
  });

  $('#chosen-version').chosen();
});

Here's the HTML:

<div id="contentWrap">
  <select rv-value="truck.job_id">
    <option rv-each-job="jobs" rv-value="job.id">{ job.job_number }</option>
  </select>
  <br/>
  <select id="chosen-version" rv-value="truck.job_id | chosen '#chosen-version'">
    <option rv-each-job="jobs" rv-value="job.id">{ job.job_number }</option>
  </select>
  <p>
    { truck.job_id }
  </p>
</div>

So basically, I forgot that you can specify a value for a <select> just like an <input>. When I realized that, I tried it with rv-value and that works too. From that point, it's really just about the same as binding a text field.

Then there's the Chosen question. Just a note, my app uses an older version of Chosen, and I don't want to upgrade, because it works just fine. I think the event trigger may have a different name now. Anyway, in order to get the Chosen select menu to update, you have to trigger an update event every time the value on the original <select> is updated. I've done this a lot with jQuery, but never with Rivets, since I just started using Rivets last night.

I needed a way to watch the variable and trigger my update event on the variable's change event. Poking around the Rivets docs, it looked like Adapters might fit the bill, since they seem to have monitoring capabilities, but when I dug in, I got a little confused.

Then I started thinking about Rivets Formatters. They have to run every time the variable is updated, in order to update the template. And it turns you they're just functions which take the new value as a parameter, and output the formatted version of the value. So, if you take the value and return it untouched, you've got a little function that reliably gets executed when the variable is updated. You can put your vaguely Germanic event trigger right in there, but you have to manually update the original select first with a call to jQuery's val(), because you are executing before the <select> has actually been updated.

Formatters also provide support for additional parameters, which is quite handy.

Pro Tip: You have to declare the formatter before you call rivets.bind(). Because.

Well, I certainly learned a lot. I guess we'll see if anyone else can benefit. Yay!

like image 130
eimajenthat Avatar answered Nov 13 '22 16:11

eimajenthat