AngularInDepth уходит от Medium. Более свежие статьи размещаются на новой платформе inDepth.dev. Спасибо за то, что участвуете в глубоком движении!

Как Питер Кролик усвоил урок из сказки о нем Беатрикс Поттер, так же поступил и я при переносе маршрутизации моего приложения с AngularJS UI Router на новый Angular Router. Тяжелые уроки стоили Питеру его туфель и синей куртки, а мне - долгих часов работы. Но мы оба вышли немного мудрее и более подготовленными к будущим испытаниям.

Теперь, после месяца работы, я наконец закончил миграцию. Поэтому я хочу поделиться с вами тем, что я узнал. Есть случаи с новым маршрутизатором, которые сначала могут показаться очевидными, но которые будут такими же сложными, как огород мистера МакГрегора, если вы попытаетесь их внедрить.

Имейте в виду, я здесь не для того, чтобы рассказывать вам, как настроить маршрутизатор, его основные идеи или API. Есть много хороших ресурсов. Скорее, я хочу поделиться парой историй, которые могут случиться с любым разработчиком, переносящим маршрутизацию своего приложения.

Само приложение. Допустим, у меня есть приложение со списком кроликов, в котором я могу управлять своими кроликами: добавлять новорожденных, удалять тех, которые убежали в лес, редактировать их профили, когда кто-то становится толще или меняет цвет на времена года меняются. Помните о кроликах и прогуляйтесь со мной по рассказам.

История I. Как программно вернуться на предыдущую страницу?

На панели инструментов есть кролики. Когда вы нажимаете на кролика в списке, показанном выше, вы попадаете в ее профиль. Затем есть небольшая кнопка возврата, которая, неудивительно, когда вы нажимаете на нее, перемещает вас обратно на панель инструментов. Но как мы можем реализовать это первое тривиальное поведение? Хитрость заключается в использовании Observables и оператора RxJS попарно, подписки на события маршрутизатора и фильтрации только тех, которые определяют успешную навигацию (NavigationEnd). P airwise дает вам текущее и предыдущее значение, и, следовательно, у вас будет доступ к текущим и предыдущим событиям маршрутизатора. Первый из пары содержит ваш предыдущий URL. Ознакомьтесь с кодом:

Решение было вдохновлено этим ответом на переполнение стека.

История II. О том, как перенаправить на один из дочерних маршрутов по умолчанию, когда пользователь переходит на родительский маршрут.

Это все та же пушистая приборная панель. Но теперь мы хотим видеть наших ушастых друзей двумя способами: списком и плитками. Вот как выглядит конфигурация:

Когда вы переходите к панели управления с помощью URL-адреса / dashboard, вы по умолчанию хотите перейти в / dashboard / list. Таким образом, каким-то образом настройки маршрутизатора должны быть изменены для перенаправления на дочерний маршрут list при навигации по родительскому маршруту панели мониторинга. Решение состоит в том, чтобы добавить еще одну настройку дочернего маршрута, имеющую чисто техническую цель. Маршрутизатор работает так: когда сопоставляется родительский объект, не имеющий связанного компонента или перенаправления, он начинает обход своих дочерних элементов. Первый (технический) дочерний элемент будет соответствовать, потому что у него пустой путь и pathMatch = ‘full’. Но он также перенаправляется на свой родственный маршрут. И это то, что мы хотели.

История III: Как настроить маршрутизатор для перехода по тому же URL-адресу с параметром или без него?

Когда я нажимаю кнопку Добавить кролика на панели управления, я попадаю на страницу с URL-адресом rabbitapp.fun/rabbit. После того, как я нажму кнопку "Сохранить информацию о кролике", он станет доступен через rabbitapp.fun/rabbit/:newRabbitId. Поэтому мне нужна конфигурация маршрутизатора, которая позволит нам переходить по тому же URL-адресу. с параметрами маршрута или без них ( rabbit и rabbit /: rabbitId). Это довольно частый случай, когда вы попадете в любое милое создание, которым вы хотите управлять. Итак, я настроил маршрут:

и ожидал, что маршрутизатор будет использовать его независимо от того, перейду ли я к / rabbit url (создать нового кролика) или / rabbit /: rabbitId ( отредактировать информацию о кролике ) . Но при переходе к голому кролику без id я был перенаправлен на свой URL-адрес перенаправления по умолчанию. После того, как я закомментировал свой URL перенаправления по умолчанию, я получил ошибку времени выполнения «Не удается сопоставить ни один маршрут» (, что, конечно, означает, что маршрут не соответствует).

Я был весьма удивлен, узнав, что мне придется продублировать настройку моих маршрутов и создать одну конфигурацию маршрута с параметром rabbitId, а другую - без. Неудобным моментом здесь является настройка дочерних маршрутов. Их тоже придется продублировать. А поскольку мы не особенно любим повторение кода и громоздкие конфигурации, я бы порекомендовал извлечь конфигурацию дочерних маршрутов в отдельный объект.

Небольшой совет ^^: Интересно, что есть еще один способ: вы можете иметь единственную конфигурацию маршрута и передавать какое-то значение по умолчанию для параметра и проверять его в своем компоненте, чтобы решить, какой поток активировать - с помощью или без параметра.

История IV: Как получить все параметры URL?

Предположим, вы хотите узнать об игровых предпочтениях кролика. В приложении вы переходите по следующему URL-адресу: rabbitapp.fun/rabbit/: parentId / babies /: babyId /isure & game = HippityHop. Конфигурация маршрутизатора для страницы, показывающей это, будет довольно длинной и будет содержать множество параметров:

Теперь в вашем LeisureComponent вы хотите получить эти параметры - rabbitId, babyId, а также параметр запроса game. . Итак, каков код для получения ВСЕХ параметров из URL? Наивное решение, с которого я начал, заключалось в том, чтобы извлечь параметры из ActivatedRoute и его родителей:

Но потом стало раздражать каждый раз выяснять, насколько глубоко эти параметры скрыты. Хотелось чего-нибудь аккуратного, например:

Поэтому для удобства я реализовал эту функцию. Вы можете использовать его и изменять по своему усмотрению.

Короче говоря, getRouteParams выполняет итерацию по переданному массиву параметров. И для каждого из них он рекурсивно вызывает функцию getParam, которая будет искать в параметрах маршрута или queryParams. А если не найден - в родительских параметрах и так далее. Он возвращает объект, в котором имя параметра является ключом, а значение - тем, чем оно является. ;)

Единственный недостаток, который я знаю, - это то, что у вас не может быть одинаковых имен параметров (кстати, это хорошая практика).

Добавьте эти методы в свой компонент напрямую или в выделенный сервис, как это сделал я. Тебе решать.

История V. Как перезагрузить текущий маршрут?

Когда моему кролику исполнится 1 год, его информация должна отображаться с совершенно другим графическим интерфейсом, чем у маленького кролика. Итак, в счастливый день я перехожу на страницу редактирования моего именинного кролика rabbit /: birthdayBunnyId и меняю его возраст. После того, как запрос к серверу будет выполнен, я хочу полностью перезагрузить страницу и показать другой набор виджетов, более подходящий для взрослого кролика. Но поскольку URL-адрес остается прежним - ничего не происходит. Если у вас есть опыт работы с AngularJS и UI Router, вы помните параметр $ state reload, который будет вызывать повторную инициализацию компонента.

Мы хотим того же поведения с новым маршрутизатором. Если у вас Angular 5.1 или выше - все в порядке. Вы можете добавить опцию onSameUrlNavigation в конфигурацию маршрутизатора. Я нашла эту статью. Надеюсь, это будет полезно. Если нет - у тебя, как и у меня, небольшие проблемы. Проблема в том, что когда вы используете router.navigate или router.navigateByUrl и переходите по тому же URL-адресу, по которому вы сейчас находитесь, это не будет иметь никакого эффекта, что означает, что компонент связанный с маршрутом, не будет обновлен.

Как вам следует перезагрузить текущий маршрут к данным страницы обновления, пока вы не перейдете на более новую версию Angular? Вы можете использовать эту хитрость. Помните, у меня в приложении есть RouteService. Я добавил к нему метод reloadCurrentPage. Сигнатура функции такая же, как для router.navigate.

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

Если вы хотите узнать больше и узнать, что вдохновило на решение, загляните в это обсуждение.

История VI: как определить, что пользователь переходит на определенную страницу?

Вы просматриваете приложение и наслаждаетесь фотографиями кроликов. На странице сведений о кролике есть CarrotNibbleWidget, который отображает количество морковок, съеденных кроликом за один прием пищи. Один и тот же виджет отображается на страницах для взрослых, подростков и для детей. У кроликов-подростков огромный аппетит, и они могут притвориться, что они голодают, хотя на самом деле это не так. Чтобы не перекармливать их, я хочу отобразить красное предупреждающее сообщение на подростковой странице, в котором говорится: «Здесь нет ошибки, кролик может съесть только одну морковь на один прием пищи. Он не теряет сознание или кружится голова от голода, а только пытается вас перехитрить !!! ». Итак, как мы можем определить, что пользователь переходит на определенную страницу или что виджет в настоящее время отображается на странице подростковая, а не на какой-либо другой, и это подходящее место для отображения сообщение? - Конечно, вы можете получить экземпляр маршрутизатора и текущий URL:

Но как узнать, страница это для подростков или для взрослых? Определенно, вы можете придумать какое-нибудь регулярное выражение, которое будет проверять ваш URL на соответствие ожидаемому, но это немного сложно и того не стоит. Я предпочитаю использовать данные маршрута. Вместе с конфигурацией роутера я добавил перечисление страниц приложения:

Затем я добавляю страницу для маршрутизации данных:

Теперь я импортирую APP_PAGES в CarrotNibbleWidget, получаю данные из activateRoute.snapshot и сравниваю их с ожидаемыми из перечисления.

Вот и все.

Вы достигли здесь? - Я горжусь тем, что могу помочь. Если вам понравились мои истории про кроликов или вы нашли несколько полезных советов - используйте кнопку хлопка ниже 👏👏👏. Они были вдохновлены Сказкой о кролике Питере, которую я упомянул в начале и недавно открыл для себя не в надлежащем возрасте, а благодаря тому, что взрослые оценили иллюстрации и сам рассказ. Если у вас есть вопросы, вы нашли ошибки или хотите выделить другие моменты, вы можете оставлять комментарии. Надеюсь, я сэкономил вам время на ромашковый чай и чернику.