Нажмите события на 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}}
Теперь вот мои вопросы:
- Почему определение действий как для файла компонента, так и для файла hbs не изменило результат?
- Почему LinkComponent не обрабатывает события click изначально? Я понимаю, что ссылка должна быть перенаправление пользователей на новую страницу (что по-прежнему спорно), но событие DOM все еще запускается, поэтому Ember намеренно игнорирует его и не позволяет разработчикам обрабатывать его? Я хочу знать логику, стоящую за этим. Есть ли лучший подход, чем мое решение?
Спасибо.
1 ответ:
Ура за изучение EmberJS и размещение красивого, явного вопроса!
Ваши ошибки
Никогда не изменяйте код внутри папок
node_modules/
иbower_components/
. Если вам действительно нужно что-то исправить, вы можете сделать это в инициализаторе. Но ваш вариант использования не требует исправления обезьяны.Вы попытались определить действие в компоненте элемента прейскуранта, но применили его в Родительском шаблоне. Это действие должно быть определено в шаблоне этого родителя компонент / контроллер.
Этот вызов неверен:
{{#ddm.link-to "index" action "sortByPrice" low_to_high}}
Вот проблемы:
Предполагается, что компонент
ddm.link-to
создает ссылку на другой маршрут. Он, кажется, не поддерживает передачу действия в него.Вы просто передаете компоненту набор позиционных параметров. Если
ddm.link-to
действительно поддерживает принятие действия, правильный вызов будет выглядеть следующим образом:{{#ddm.link-to "index" argName=(action "sortByPrice" low_to_high)}}
В этом случае
"index"
является позиция param иargName
является именованной param.
low_to_high
без кавычек-это ссылка на свойство, определенное в текущей области видимости. Вы, вероятно, имели в виду строку вместо:"low_to_high"
.Никогда не используйте код 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'}}>
Ответы на ваши вопросы
Потому что вы определили их в разных областях.
- Почему определение действий как для файла компонента, так и для файла hbs не изменило результат?
Если вы определяете действие в
app/components/foo-bar.js
, действие должно быть применено вapp/templates/components/foo-bar.hbs
.Если вы определяете действие в
app/controllers/index.js
, действие должно быть применено вapp/templates/index.hbs
.
- Почему бы и нет?
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}}
Вотрабочая демонстрация .