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

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

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

{{#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* Компонент расширяет компонент LinkComponent. В конце концов я понял, что этот элемент не может обрабатывать события щелчка мышью, как это объясняется в этой теме.

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

{{#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 не обрабатывает события щелчка по умолчанию? Я понимаю, что ссылка должна перенаправлять пользователей на новую страницу (которая до сих пор спорно), но событие DOM еще уволят, так же Ember намеренно игнорировать его и выбрать, чтобы не позволить разработчикам справиться с этим? Я хочу знать логику этого.
  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" является параметром позиции и argName это названный параметр.

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

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

    <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. Эмбер переопределяет перезапись 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 еще уволят, так же Ember намеренно игнорировать его и выбрать, чтобы не позволить разработчикам справиться с этим? Я хочу знать логику этого.

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

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

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

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

Смотрите ниже для простейшего подхода, который использует 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}}

Вот рабочая демка.

Другие вопросы по тегам