Нажмите события на Ember


Я открыл EmberJS и начал переносить существующий веб-сайт на эту платформу. У меня была проблема с раскрывающимся списком на основе Bootstrap. Этот вопрос на самом деле помог мне понять концепции Эмбера немного лучше, но у меня все еще есть некоторые вопросы.

Я использовал модуль ember-bootstrap для генерации этого выпадающего списка (среди прочего), и вот каким должен быть код:

{{#bs-dropdown as |dd|}}
  {{#dd.button}}
    Sort by
  {{/dd.button}}

  {{#dd.menu as |ddm|}}
    {{#ddm.item}}{{#ddm.link-to "index"}}Price low to high{{/ddm.link-to}}{{/ddm.item}}
    {{#ddm.item}}{{#ddm.link-to "index"}}Price high to low{{/ddm.link-to}}{{/ddm.item}}
  {{/dd.menu}}
{{/bs-dropdown}}

Теперь я хочу, чтобы некоторый код javascript выполнялся, когда пользователь нажимает на один из них из предметов. После проверки документации модуля , я нашел, где был определен компонент Пункт меню и отредактировал его код следующим образом:

export default Component.extend({
  layout,
  classNameBindings: ['containerClass'],

  /* ... */

  actions: {
    // My addition
    sortByPrice(param){
      alert("sorting");
    },
    // End of the addition

    toggleDropdown() {
      if (this.get('isOpen')) {
        this.send('closeDropdown');
      } else {
        this.send('openDropdown');
      }
    },
  },
});

Затем я обновил файл hbs следующим образом:

{{#dd.menu as |ddm|}}
   {{#ddm.item action "sortByPrice" low_to_high}}

    {{#ddm.link-to "index"  action "sortByPrice" low_to_high}}
      Prix croissant
    {{/ddm.link-to}}

  {{/ddm.item}}
{{/dd.menu}}

Это не сработало, и именно поэтому вы добавили *action* к элементу link-to, а также объявили аналогично действие на его компонентный файл.

import LinkComponent from '@ember/routing/link-component';

export default LinkComponent.extend({
  actions: {
    sortByPrice(param){
        alert("sorting");
      console.log("sorting");
      },
  },
});
Как вы можете видеть, компонент *link-to*расширяет компонент Linkcommon. Я в конце концов понятно, что этот элемент не может обрабатывать события click изначально, как описано в этом потоке.

От разочарования я в конечном итоге выбрал менее элегантный подход, который все еще делает трюк:

{{#bs-dropdown id="sort" as |dd|}}
  {{#dd.button}}
    Sort by
  {{/dd.button}}

  {{#dd.menu as |ddm|}}
    {{#ddm.item action "sortByPrice" low_to_high}}
      <a
        class="dropdown-item"
        onclick="sortByPrice('low_to_high'); return false;"
        href="#"
      >
        Price low to high
      </a>
    {{/ddm.item}}
  {{/dd.menu}}
{{/bs-dropdown}}

Теперь вот мои вопросы:

  1. Почему определение действий как для файла компонента, так и для файла hbs не изменило результат?
  2. Почему LinkComponent не обрабатывает события click изначально? Я понимаю, что ссылка должна быть перенаправление пользователей на новую страницу (что по-прежнему спорно), но событие DOM все еще запускается, поэтому Ember намеренно игнорирует его и не позволяет разработчикам обрабатывать его? Я хочу знать логику, стоящую за этим.
  3. Есть ли лучший подход, чем мое решение?

Спасибо.

1 3

1 ответ:

Ура за изучение EmberJS и размещение красивого, явного вопроса!

Ваши ошибки

  1. Никогда не изменяйте код внутри папок node_modules/ и bower_components/. Если вам действительно нужно что-то исправить, вы можете сделать это в инициализаторе. Но ваш вариант использования не требует исправления обезьяны.

  2. Вы попытались определить действие в компоненте элемента прейскуранта, но применили его в Родительском шаблоне. Это действие должно быть определено в шаблоне этого родителя компонент / контроллер.

  3. Этот вызов неверен:

    {{#ddm.link-to "index"  action "sortByPrice" low_to_high}}
    

    Вот проблемы:

    1. Предполагается, что компонент ddm.link-to создает ссылку на другой маршрут. Он, кажется, не поддерживает передачу действия в него.

    2. Вы просто передаете компоненту набор позиционных параметров. Если ddm.link-to действительно поддерживает принятие действия, правильный вызов будет выглядеть следующим образом:

      {{#ddm.link-to "index" argName=(action "sortByPrice" low_to_high)}}
      

      В этом случае "index" является позиция param и argName является именованной param.

    3. low_to_high без кавычек-это ссылка на свойство, определенное в текущей области видимости. Вы, вероятно, имели в виду строку вместо: "low_to_high".

  4. Никогда не используйте код JS непосредственно в шаблоне. Этого никогда не следует делать в Эмбере:

    <a onclick="sortByPrice('low_to_high'); return false;">
    

    Вместо этого передайте действие (определенное в локальной области видимости: в компоненте или контроллере):

    <a onclick={{action 'sortByPrice' 'low_to_high'}}>
    

    Имя свойства onclick является необязательным. Действие, определенное без свойство подразумевает onclick (вам нужно только указать имя свойства, если вам нужно прикрепить действие к другому событию):

    <a {{action 'sortByPrice' 'low_to_high'}}>
    

    Для правильного оформления ссылки в браузере требуется атрибут href. Но вам не нужно передавать ему значение '#'. Хэш-символ был необходим в приложениях старой школы, чтобы предотвратить перезапись URL-адреса ссылкой. Ember переопределяет перезапись URL для вас, поэтому вы можете просто передать пустой href.

    Вот окончательный правильный ответ. использование:

    <a href {{action 'sortByPrice' 'low_to_high'}}>
    

Ответы на ваши вопросы

  1. Почему определение действий как для файла компонента, так и для файла hbs не изменило результат?
Потому что вы определили их в разных областях.

Если вы определяете действие в app/components/foo-bar.js, действие должно быть применено в app/templates/components/foo-bar.hbs.

Если вы определяете действие в app/controllers/index.js, действие должно быть применено в app/templates/index.hbs.

  1. Почему бы и нет? LinkComponent обрабатывать события щелчка изначально? Я понимаю, что ссылка должна перенаправлять пользователей на новую страницу (что все еще спорно), но событие DOM все еще срабатывает, поэтому Эмбер намеренно игнорирует его и не позволяет разработчикам обрабатывать его? Я хочу знать логику, стоящую за этим.

В PWA не выполняется фактическое перенаправление страниц. Такой редирект перезагрузит все приложение.

Вместо этого LinkComponent переопределяет щелчок и сообщает системе маршрутизации Ember, чтобы выполнить переход. Маршруты должны быть настроены правильно, и маршрут, переданный в LinkComponent , должен существовать.

Похоже, что ваша цель состоит не в том, чтобы выполнить переход, а в том, чтобы изменить переменную, поэтому LinkComponent здесь неприменимо. Это если только вы не свяжете свойство порядка сортировки с параметром URL-запроса, в этом случае вы можете изменить порядок сортировки, перейдя к другому параметру запроса.

    Есть ли лучший подход, чем мое решение?

См. ниже для простейшего подхода, который использует выпадающий список ember-bootstrap.


Рабочий пример

Контроллер:

export default Ember.Controller.extend({
  isSortAccending: true,

  actions: {
    changeSortDirection (isSortAccending) {
      this.set('isSortAccending', isSortAccending);
    }
  }
});

Шаблон:

<p>
  Current sort order:
  {{if isSortAccending "ascending" "descending"}}
</p>

{{#bs-dropdown as |dd|}}
  {{#dd.button}}
    Sort by
  {{/dd.button}}

  {{#dd.menu as |ddm|}}
    {{#ddm.item}}
      <a href {{action "changeSortDirection" true}}>
        Price high to low
      </a>
    {{/ddm.item}}

    {{#ddm.item}}
      <a href {{action "changeSortDirection" false}}>
        Price high to low
      </a>
    {{/ddm.item}}
  {{/dd.menu}}
{{/bs-dropdown}}

Вотрабочая демонстрация .