Добавьте дополнительные действия в linkTo в октане

#ember.js

Вопрос:

У меня есть выпадающее меню со ссылками, при нажатии на которые я хотел бы, чтобы меню закрывалось.

Что-то вроде (a11y/i18n усечено):

 <ul class="menu">
    <li>
        <LinkTo @route="myprofile">
            Profile
        </LinkTo>
    </li>
    <li>
        <LinkTo @route="logout">
            Logout
        </LinkTo>
    </li>
</ul>
 

Я хотел бы добавить дополнительный обработчик кликов по ссылке на, что-то вроде:

 <ul class="menu">
    <li>
        <LinkTo @route="myprofile" {{on "click" this.closeMenu}}>
            Profile
        </LinkTo>
    </li>
    <li>
        <LinkTo @route="logout" {{on "click" this.closeMenu}}>
            Logout
        </LinkTo>
    </li>
</ul>
 

Однако это делает LinkTo бесполезным, поскольку он перезагружает страницу, как если бы переходил по ссылке, а не переходил на новый маршрут. В настоящее время мы делаем это с помощью действия hember-link, но я бы хотел найти более идиоматичный способ решения этой проблемы.

Ответ №1:

Если вам нужно выполнить дополнительную логику, вы можете реализовать перенаправление в действии вместо использования LinkTo помощника. Для этого вам нужно ввести RouterService в свой компонент, а затем вызвать его transitionTo метод. Что-то вроде:

 export default class ExampleComponent extends Component {
  @service router;

  @action
  navigate(route) {
    this.menuExpanded = false;
    this.router.transitionTo(route);
  }
}
 

Обратите внимание, что также существуют transitionTo() методы из маршрута и transitionToRoute() из контроллера, которые ведут себя как LinkTo помощник. Но сейчас эти методы устарели, и использование RouterService является рекомендуемым идиоматическим способом выполнения переходов в коде js.

Комментарии:

1. Это будет обрабатывать навигационную часть, но это не все, что делает linkTo. Он также создает семантически правильный a тег с допустимым href указанием на маршрут, а также добавляет некоторые классы, если текущий маршрут является активным, и в этом случае предотвращает переход. Это хорошее начало, но я надеюсь получить все LinkTo вместе с небольшим количеством большего.

Ответ №2:

Я написал компонент, который в основном справляется с этим, но я совершенно уверен, что в нем есть больше крайних LinkTo случаев, которые я рассмотрел (например, он не охватывает переданную модель или список моделей). Я позвонил сюда <LinkToWithAction /> , и это выглядит так:

 <a href={{this.href}} class={{if this.isActive "active"}} {{on "click" this.navigate}} >
    {{yield}}
</a>
 
 import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';

export default class LinkToWithActionComponent extends Component {
  @service router;

  get href() {
    return this.router.urlFor(this.args.route, {
      queryParams: this.queryParams,
    });
  }

  get isActive() {
    return this.router.isActive(this.args.route);
  }

  get queryParams() {
    return this.args.queryParams ?? {};
  }

  @action
  navigate(evt) {
    evt.preventDefault();
    this.args.action();
    this.router.transitionTo(this.args.route, {
      queryParams: this.queryParams,
    });
  }
}
 

и это называется как:

 <LinkToWithAction
  @route="mymaterials"
  @action={{set this.isOpen false}}
  @queryParams={{hash course=null}}
>
  {{t "general.myprofile"}}
</LinkToWithAction>
 

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