Нажмите события на 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}}
Теперь вот мои вопросы:
- Почему определение действий как для файла компонента, так и для файла hbs не изменило результат?
- Почему LinkComponent не обрабатывает события щелчка по умолчанию? Я понимаю, что ссылка должна перенаправлять пользователей на новую страницу (которая до сих пор спорно), но событие 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"
является параметром позиции иargName
это названный параметр.low_to_high
без кавычек - это ссылка на свойство, определенное в текущей области видимости. Вы, вероятно, имели в виду строку вместо:"low_to_high"
,
Никогда не используйте 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'}}>
Ответы на ваши вопросы
- Почему определение действий как для файла компонента, так и для файла hbs не изменило результат?
Потому что вы определили их в разных сферах.
Если вы определяете действие в app/components/foo-bar.js
, действие должно быть применено в app/templates/components/foo-bar.hbs
,
Если вы определяете действие в app/controllers/index.js
, действие должно быть применено в app/templates/index.hbs
,
- Почему не
LinkComponent
обрабатывать события кликов изначально? Я понимаю, что ссылка должна перенаправлять пользователей на новую страницу (которая до сих пор спорно), но событие DOM еще уволят, так же Ember намеренно игнорировать его и выбрать, чтобы не позволить разработчикам справиться с этим? Я хочу знать логику этого.
В 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}}
Вот рабочая демка.