Подтвердить что ты не робот

Angular router: как передать данные в ленивый модуль загрузки?

У меня есть следующие пути маршрутизации для модуля моего приложения Angular:

@NgModule({
    imports: [
        RouterModule.forChild([
            {
                path: 'documents',
                data: { myObject: MyConstants.OPTION_ONE },
                children: [
                    {
                        path: ':ID_DOC',
                        children: [
                            { path: 'edit', component: EditDocumentComponent },
                            { path: '', component: DocumentDetailsComponent },
                        ]
                    },
                    { path: 'add', component: AddDocumentComponent },
                    { path: '', component: DocumentsListComponent }
                ]
            }
        ])
    ],
    exports: [
        RouterModule
    ]
})

export class DocumentsManagementRoutingModule {
}

Как вы можете видеть, я использую свойство data для передачи некоторых данных каждому пути в "документах", поэтому я могу получить его из любого из компонентов, объявленных в маршрутах маршрутизации:

Например, вот как я получаю данные в DocumentDetailsComponent:

export class DocumentDetailsComponent implements OnDestroy {
    private obsData: Subscription;
    private option: any;

    constructor(private route: ActivatedRoute) {
        this.obsData = this.route.data.subscribe(data => {
            this.option = data['myObject'];
        });
    }

    ngOnDestroy(): void {
        this.obsData.unsubscribe();
    }
}

Теперь я изменил структуру маршрутизации всего приложения, и я вызываю вышеуказанный модуль из других модулей, в ленивой загрузке, используя атрибут loadChildren. И я передаю данные таким же образом:

@NgModule({
    imports: [
        RouterModule.forChild([
            {
                path: 'users',
                loadChildren: 'app/documents/documents.module#DocumentsModule',
                data: { myObject: MyConstants.OPTION_ONE }},
            {
                path: ':ID_USER',
                children: [
                    { path: 'edit', component: EditUserComponent },
                    { path: '', component: UserDetailsComponent },
                ]
            },
            { path: 'add', component: AddUserComponent },
            { path: '', component: UserListComponent }
        ])
    ],
    exports: [
        RouterModule
    ]
})

export class UsersManagementRoutingModule {
}

И я сделал то же самое для всех других модулей, которые называет DocumentsManagementRoutingModule, изменяя свойство myObject на MyConstants.OPTION_TWO, MyConstants.OPTION_THREE и т.д. согласно моим потребностям.

Тогда, поскольку я не знаю модуль и связанный с ним путь, который вызывает мой ленивый модуль загрузки, как получить свойство data из модуля вызывающего абонента?

4b9b3361

Ответ 1

Вы можете перемещаться по родительским маршрутам с помощью activateRoute.pathFromRoot и получать данные от ближайшего предка, у которого есть это. Кажется, что-то вроде этого:

  ngOnInit(): void {
    let idx = this.activatedRoute.pathFromRoot.length - 1;
    while(this.sharedData == null && idx > 0){
      this.sub = this.activatedRoute.pathFromRoot[idx].data.subscribe(subData => {

        if(subData.id)
          this.sharedData = subData;

        console.log('shared data', this.sharedData);
      });
      idx--;
    }
  }

https://plnkr.co/edit/K5Rb1ZvTvSQNM6tOLeFp

Ответ 2

Думаю, я понимаю, о чем спрашивает вопрос.


Проблема

Вот график маршрутизации предоставляемой plunker @smartmouse.

- home
  - shop
  - contact
    - map
  - about

В конфигурации маршрута home настроен объект data. Прямые дочерние маршруты могут обращаться к этому объекту данных. Проблема заключается в том, что непрямой дочерний элемент map хочет получить доступ к объекту data, но, по-видимому, он не может.

И мы можем знать, что @smartmouse хочет нажать, что еще дальше - вложенные не прямые прямые маршруты могут обращаться к данным от предка.

Почему это не может?

См. плункер, который я изменил. https://plnkr.co/edit/FA7mGmspUXHhU8YvgDpT

Вы можете видеть, что я определяю дополнительный дочерний компонент DefaultComponent для contact. Он показывает, что это прямой и по умолчанию ребенок маршрута contact, который может быть интерпретирован, так как он также является прямым ребенком высшего маршрута home. Таким образом, он может получить доступ к объекту data.

Решение

Посмотрите на плункер, предоставленный мной снова.

ПРИМЕЧАНИЕ. Пакеты Angular, которые я использую, - v4.3.0

Подход №1 - параметры запроса

Я определяю некоторые параметры запроса в home.component.ts для маршрута contact. Вы можете увидеть, как его использовать.

Pros

  • вы можете получить доступ к параметрам запроса на любом уровне маршрутов.
  • хорошо работает с модулями lazyload

против

  • вы не можете определить параметры запроса в конфигурации маршрута.

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

Подход №2 - сервис

Определите службу обмена данными на верхнем уровне приложения, играющего в качестве шаблона Singleton. Кроме того, используйте некоторые утилиты, чтобы предотвратить его запуск дважды. Затем вы можете поместить в него некоторые данные и получить их в любом месте.

Pros

  • глобально видимый через DI;
  • хорошо работает с модулями lazyload

против

  • вы не можете обновлять данные в конфигурации маршрута.
  • вам нужно определить данные в другом месте. Если вы не можете контролировать источник, это может быть проблемой.

Подход № 3 - разрешение маршрута

Кто-то может узнать, что я также определил код образца resolve в plunker. Он показывает, что он имеет такое же поведение, как data в конфигурации маршрута, за исключением того, что он действительно предназначен для получения динамических данных.

https://vsavkin.com/angular-router-understanding-router-state-7b5b95a12eab#5400
Свойство data используется для передачи фиксированного объекта в активированный маршрут. Он не меняется на протяжении всего срока службы приложения. Свойство resol используется для динамических данных.

Возьмите @smartmouse plunkr в качестве примера.

У нас есть data, определенный в конфигурации "home" route. Мы можем определить преобразователь данных в ContactModule для маршрута контакта по умолчанию и проксировать данные, переданные с более высокого маршрута. Затем все его прямые дочерние маршруты могут получить доступ к разрешенному объекту данных.

Pros

  • хорошо работает с любым уровнем вложенных маршрутов.
  • хорошо работает с модулями lazyload

против

  • Возможно, вам придется объявить это свойство разрешения в каждом родительском маршруте, чьи дочерние маршруты хотят получить доступ к этим данным. Это своего рода грязная работа.

На сегодняшний день нет идеального и универсального решения с общим использованием Angular. Кто-то должен взвесить плюсы и минусы и выбрать правильный.

Ответ 3

@NgModule({
    imports: [
        RouterModule.forChild([
            {
                path: 'users',
                loadChildren: 'app/documents/documents.module#DocumentsModule',
                resolve : {
                     data: DataResolver
                }
            {
        ])
    ],
    exports: [
        RouterModule
    ]
})

export class UsersManagementRoutingModule {
}


@Injectable()
export class DataResolverimplements Resolve<Data> {
  resolve() {
    return this.serice.getData();
  }
}

Ответ 4

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

Служба может иметь функции для установки и получения значений и, следовательно, вы можете использовать эти функции в службах для получения необходимых данных.