0

I'm using latest ember js and have the following view:

App.PeriodSelectorView = Em.View.extend
  classNames: "period-selector"
  templateName: "period_selector"

  didInsertElement: ->
    @$().draggable()
    @setupTimeSlider()

  setupTimeSlider: ->
    @$(".time-slider").slider
      value: 20
      min: 20 # 0500 in the morning
      max: 83 # 2045 in the evening
      step: 1
      slide: @updateTimeValue

  updateTimeValue: (event, ui) ->
    @set("time", ui.value)

Now when the slider is changed the callback fires, but this is set to window instead of the view instance. So calling this.set fails.

I already tried binding the method updateTimeValue to the instance using coffeescript's fat arrow (=>) operator, but it doesn't work.

How to get this point to the view instance instead of window?

gucki
  • 4,582
  • 7
  • 44
  • 56
  • could you elaborate on exactly *how* you tried using `=>`? this answer seems to imply it should work : http://stackoverflow.com/questions/8965855/coffeescript-when-to-use-fat-arrow-over-arrow-and-vice-versa – Frances McMullin Nov 17 '13 at 13:53
  • I just use => insteaf of -> for updateTimeValue. But I just saw from the compiled code, that in fact that this is doing nothing. The reasons seems to be I don't use "class App.PeriodSelectorView extends Em.View". But I cannot use this form, because then nothing works and only a bunch of exceptions are thrown...I'll have to dig deeper into this. – gucki Nov 17 '13 at 14:01

1 Answers1

0

Problem

I am not a coffeescript expert, but in my tests, it seems that using the => operator. Generate the _this = this, in the parent function scope. For example:

Using:

App = Ember.Application.create()

App.PeriodSelectorView = Em.View.extend  
  ...
  updateTimeValue: (event, ui) =>
    @set("time", ui.value)

Generates the following:

var App,
  _this = this;

App = Ember.Application.create();

App.PeriodSelectorView = Em.View.extend({
  ...
  updateTimeValue: function(event, ui) {
    // _this here is window object, this isn't what you want
    return _this.set("time", ui.value);
  }
});

Solution 1

Following this logic using an anonymous function you will get the expected result:

Updating to the following:

App = Ember.Application.create()

App.PeriodSelectorView = Em.View.extend
  ...
  setupTimeSlider: ->
    @$(".time-slider").slider
      value: 20
      min: 20 # 0500 in the morning
      max: 83 # 2045 in the evening
      step: 1
      slide: (event, ui) => #slide now is an anonymous function 
        @set("time", ui.value)

Generates:

var App;

App = Ember.Application.create();

App.PeriodSelectorView = Em.View.extend({
  ...
  setupTimeSlider: function() {
    // now _this is the view context
    var _this = this;

    return this.$(".time-slider").slider({
      value: 20,
      min: 20,
      max: 83,
      step: 1,
      slide: function(event, ui) {
        // this will work
        return _this.set("time", ui.value);
      }
    });
  }
});

Solution 2

If you want to keep the name of the function, and the function declarion in the same place. You can use the jQuery.proxy:

App = Ember.Application.create

App.PeriodSelectorView = Em.View.extend
  ...
  setupTimeSlider: ->
    @$(".time-slider").slider
      value: 20
      min: 20 # 0500 in the morning
      max: 83 # 2045 in the evening
      step: 1
      slide: Ember.$.proxy @updateTimeValue, @

  updateTimeValue: (event, ui) ->
    @set("time", ui.value) 

I hope it helps

Marcio Junior
  • 19,078
  • 4
  • 44
  • 47
  • Thank you Marcio! I cannot try your approach anymore, as I changed my implementation completely and it's now based on https://github.com/lukemelia/jquery-ui-ember, but I'm sure I'll need those concepts in the future. – gucki Nov 17 '13 at 15:15