Проблема с областью действия при попытке вызвать метод CoffeeScript внутри обратного вызова Fancybox

У меня есть следующий модуль CoffeeScript с именем Course. У меня есть небольшой фрагмент кода, который я хотел бы использовать повторно, я создал метод с именем preSelectItemSize.

Я хотел бы вызвать этот метод при вызове init, а также в обратном вызове afterShow Fancybox. Следующий код работает, но он не считает правильным использовать имя модуля, и вместо этого я должен использовать ссылку @ на "это".

Что я делаю не так? (Фрагмент кода сокращен для краткости)

$ = window.jQuery = require("jquery")
Course =

  init: ->

    $('.js-product-overlay').on 'click', (e) =>
      @viewProductClickHandler(e, MediaDetection)

    @preSelectItemSize()

  viewProductClickHandler: (e, mediaDetection) =>

    $('.js-product-overlay').fancybox({
      href: wishlist_overlay_href
      maxWidth: '775px'
      minHeight: '495px'
      autoCenter: '!isTouch'
      height: 'auto'
      scrolling: true
      fitToView: false
      autoSize: false
      padding: 0
      tpl:
        closeBtn: '<a class="fancybox-item modal__close fancybox-close" href="javascript:;">Close</a>'
      afterShow: ->
        $('.js-fancybox-close').on 'click', (e) ->
          e.preventDefault()
          $.fancybox.close()

        Course.preSelectItemSize()
    })

  preSelectItemSize: ->
    itemId = $('.modal__product-info').attr('data-item-id')
    $('#size-' + itemId).click()

module.exports = Course

person crmpicco    schedule 08.01.2016    source источник
comment
Вы просто хотите afterShow: => вместо afterShow: ->?   -  person mu is too short    schedule 08.01.2016
comment
@muistooshort Нет, изначально я использовал жирную стрелку =>1, но это не работает. Я только что попробовал еще раз и получил _this.preSelectItemSize is not a function   -  person crmpicco    schedule 08.01.2016
comment
Правильно, потому что у вас нет класса, у вас просто литерал объекта, пропустил это.   -  person mu is too short    schedule 08.01.2016
comment
В этой скрипте есть рабочий пример jsfiddle.net/L5u31Lzr/1.   -  person crmpicco    schedule 11.01.2016
comment
Вы можете самостоятельно ответить на вопрос с таким подходом, если он вам подходит.   -  person mu is too short    schedule 11.01.2016
comment
@muistooshort Спасибо за помощь   -  person crmpicco    schedule 18.01.2016


Ответы (2)


Я думаю, что ваша реальная проблема заключается в том, что вы используете простой литерал объекта, а не класс, поэтому => ведет себя не совсем так, как вы ожидаете, и вам остается ссылаться на Course по имени.

Если мы посмотрим на упрощенный пример:

o =
  m: =>

мы можем увидеть, что происходит, взглянув на созданный JavaScript:

var o;
o = {
  m: (function(_this) {
    return function() {};
  })(this)
};

Поскольку у нас есть только простая структура данных (т. е. старый простой литерал объекта), нет конструктора для привязки m к любому экземпляру, и он ведет себя так, как если бы вы сказали:

m = =>
o = m: m

поэтому любые свойства функции o (или Course в вашем случае) - это просто старые свойства, которые являются функциями, а не методами.

Вы можете отбросить все толстые стрелки и обратиться к Course по имени, или вы можете переключиться на класс, чтобы был экземпляр для CoffeeScript для привязки вещей:

class Course
  #...
module.exports = new Course
person mu is too short    schedule 08.01.2016
comment
Использование литерала объекта - это шаблон, используемый во всей системе, поэтому я бы нарушил шаблон, если бы изменил его на класс. Нет ли другого способа вызвать этот метод без рефакторинга класса? - person crmpicco; 11.01.2016

Следующее работает, изменив viewProductClickHandler на тонкую стрелку и изменив обратный вызов afterShow на толстую стрелку:

Course =

  init: ->

    $('.js-product-overlay').on 'click', (e) =>
      @viewProductClickHandler(e, MediaDetection)

    @preSelectItemSize()

  viewProductClickHandler: (e, mediaDetection) ->

    $('.js-product-overlay').fancybox({
      href: wishlist_overlay_href
      maxWidth: '775px'
      minHeight: '495px'
      autoCenter: '!isTouch'
      height: 'auto'
      scrolling: true
      fitToView: false
      autoSize: false
      padding: 0
      tpl:
        closeBtn: '<a class="fancybox-item modal__close fancybox-close" href="javascript:;">Close</a>'
      afterShow: =>
        $('.js-fancybox-close').on 'click', (e) ->
          e.preventDefault()
          $.fancybox.close()

        @preSelectItemSize()
    })

  preSelectItemSize: ->
    alert "preSelectItemSize executed."
    itemId = $('.modal__product-info').attr('data-item-id')
    $("#size-#{itemId}").click()

Course.init()

См. скрипт для примера рабочего кода: https://jsfiddle.net/L5u31Lzr/1/

person crmpicco    schedule 18.01.2016