Search code examples
ember.jsslidermouseup

Handling MouseUp on Slider in Ember.js


I've been working on incorporating a slider into a page in an app I'm working on. My first attempt was to use the following in my template:

<span class="value">{{scaledDistThreshold}}%</span>
{{input type="range" min="0" max="100" step="1" value=scaledDistThreshold}}
<button class="set" {{action "setDistThreshold"}}>Set</button>

This works; that is, I can use the slider and see the bound value change, and pressing the button will persist whatever value to the server.

What I'd like to do now is to remove the 'Set' button and persist on mouseup from the slider itself, and I'd prefer to do it with Ember as opposed to, say, a direct jQuery hook. So far, my searches for sliders using Ember has turned up basically nothing.

Any ideas how I might accomplish this? Thanks in advance!


FOLLOW-UP EDIT

Per Justin's answer, I was able to do the following:

App.InputRangeComponent = Em.TextField.extend({
  type: 'range',

  action: 'mouseUp',

  mouseUp: function () {
    var value = this.get('value');
    this.sendAction('action', value);
  }
});

I was then able to use this component in my markup as follows:

{{input-range min="0" max="100" step="1" value=scaledDistThreshold action="setDistThreshold"}}

The action I named gets called on mouse-up and passes along the current value of the slider, all as intended. Thanks again to Justin for the answer!


Solution

  • My first thought, and this isn't, strictly-speaking, an answer to your question, but another option might be just saving the bound value on change, and throttling it to only do so, say, once every quarter-second or so.

    Now, as for answering your actual question:

    (Please note: I'm still fairly new to Ember, so if what I say doesn't make sense, it's probably me, not you)

    I didn't know that type="range" was an option for the {{input}} helper. Learn something new every day. :)

    Take a look at the Ember docs on the {{input}} helper. When you use type="text", Ember is creating an instance of Ember.TextField. You have a couple of options:

    1. You can reopen Ember.TextField and add a mouseup event to it.
    2. You can create your own, new helper, that uses a new view (that you create) that extends Ember.TextField.

    I'd recommend #2 for fairly obvious reasons (you probably don't want every textfield you make doing the same thing on mouseup).

    SO, option 2.

    I think this is how it would go down. If not, hopefully, it will at least point you in the right direction, or someone will correct me.

    First, you'll want to create a new view that extends Ember.TextEdit. Let's call it "rangeSlider".

    var rangeSlider = Ember.TextField.extend({
    
    });
    

    Here is where you should add your mouseup event:

    App.RangeSlider = Ember.TextField.extend({
        mouseUp: function(){
            //Do stuff here
        } 
    });
    

    Now, if you don't want to use {{view "App.RangeSlider"}}, you can create a new helper:

    Ember.Handlebars.helper('rangeSlider', App.RangeSlider);
    

    Then you just have to use {{rangeSlider}} to insert that view.

    I'm not 100% sure how adding attributes via your new helper works, though.

    Looking at the ember.js code, the {{input}} helper had a bit more going for it at declaration:

    Ember.Handlebars.registerHelper('input', function(options) {
      Ember.assert('You can only pass attributes to the `input` helper, not arguments', arguments.length < 2);
    
      var hash = options.hash,
          types = options.hashTypes,
          inputType = hash.type,
          onEvent = hash.on;
    
      delete hash.type;
      delete hash.on;
    
      if (inputType === 'checkbox') {
        Ember.assert("{{input type='checkbox'}} does not support setting `value=someBooleanValue`; you must use `checked=someBooleanValue` instead.", options.hashTypes.value !== 'ID');
        return Ember.Handlebars.helpers.view.call(this, Ember.Checkbox, options);
      } else {
        if (inputType) { hash.type = inputType; }
        hash.onEvent = onEvent || 'enter';
        return Ember.Handlebars.helpers.view.call(this, Ember.TextField, options);
      }
    });
    

    Now that I think about it, I wonder if there's a way to just extend an existing helper... Not sure. I'm not seeing anything in the API.

    Anyway, hopefully, this will point you in the right direction. There may be a totally easier way, but this was the first thing that popped into my head when I read your question. :)