Передача данных в дочерние компоненты "router-outlet"
У меня есть родительский компонент, который отправляется на сервер и получает объект:
// parent component
@Component({
selector : 'node-display',
template : '
<router-outlet [node]="node"></router-outlet>
'
})
export class NodeDisplayComponent implements OnInit {
node: Node;
ngOnInit(): void {
this.nodeService.getNode(path)
.subscribe(
node => {
this.node = node;
},
err => {
console.log(err);
}
);
}
И в одном из нескольких отображений детей:
export class ChildDisplay implements OnInit{
@Input()
node: Node;
ngOnInit(): void {
console.log(this.node);
}
}
Не похоже, что я могу просто вставить данные в router-outlet
. Похоже, я получаю сообщение об ошибке в веб-консоли:
Can't bind to 'node' since it isn't a known property of 'router-outlet'.
Это в некоторой степени имеет смысл, но как бы я поступил следующим образом:
- Захватите данные "узла" с сервера, из родительского
компонент?
- Передать данные, полученные с сервера, в дочерний маршрутизатор?
Похоже, что router-outlets
не работает так же.
Ответы
Ответ 1
Единственный способ - использовать общий сервис.
<router-outlet [node]="..."></router-outlet>
просто недействительно. Компонент, добавленный маршрутизатором, добавляется как элемент <router-outlet>
и не заменяет его.
Смотрите также https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service.
@Injectable()
export class NodeService {
private node:Subject<Node> = new BehaviorSubject<Node>([]);
get node$(){
return this.node.asObservable().filter(node => !!node);
}
addNode(data:Node) {
this.node.next(data);
}
}
@Component({
selector : 'node-display',
providers: [NodeService],
template : '
<router-outlet></router-outlet>
'
})
export class NodeDisplayComponent implements OnInit {
constructor(private nodeService:NodeService) {}
node: Node;
ngOnInit(): void {
this.nodeService.getNode(path)
.subscribe(
node => {
this.nodeService.addNode(node);
},
err => {
console.log(err);
}
);
}
}
export class ChildDisplay implements OnInit{
constructor(nodeService:NodeService) {
nodeService.node$.subscribe(n => this.node = n);
}
}
Ответ 2
Ответ Günters велик, я просто хочу указать другой способ, не используя Observables.
Здесь мы, однако, должны помнить, что эти объекты передаются по ссылке, поэтому, если вы хотите сделать некоторую работу над объектом в дочернем элементе и не повлиять на родительский объект, я бы предложил использовать решение Günther. Но если это не имеет значения или на самом деле это желаемое поведение, я бы предложил следующее.
@Injectable()
export class SharedService {
sharedNode = {
// properties
};
}
В своем родителе вы можете присвоить значение:
this.sharedService.sharedNode = this.node;
И в ваших дочерних элементах (И родительском) вставьте совместно используемую службу в свой конструктор. Не забудьте предоставить услугу в массиве поставщиков модулей, если вы хотите использовать однопользовательскую службу по всем компонентам этого модуля. В качестве альтернативы просто добавьте службу в массив поставщиков в родительском только, тогда родительский и дочерний будут использовать один и тот же экземпляр службы.
node: Node;
ngOnInit() {
this.node = this.sharedService.sharedNode;
}
И как любезно указал новый человек, вы можете также иметь this.sharedService.sharedNode
в шаблоне html или getter:
get sharedNode(){
return this.sharedService.sharedNode;
}
Ответ 3
Услуги:
import {Injectable, EventEmitter} from "@angular/core";
@Injectable()
export class DataService {
onGetData: EventEmitter = new EventEmitter();
getData() {
this.http.post(...params).map(res => {
this.onGetData.emit(res.json());
})
}
Компонент:
import {Component} from '@angular/core';
import {DataService} from "../services/data.service";
@Component()
export class MyComponent {
constructor(private DataService:DataService) {
this.DataService.onGetData.subscribe(res => {
(from service on .emit() )
})
}
//To send data to all subscribers from current component
sendData() {
this.DataService.onGetData.emit(--NEW DATA--);
}
}
Ответ 4
Есть 3 способа передачи данных от родителей к детям
- Через разделяемый сервис: вы должны хранить в сервисе данные, которыми вы хотели бы поделиться с детьми
Через Children Router Resolver, если вам нужно получать разные данные
this.data = this.route.snaphsot.data['dataFromResolver'];
Через Parent Router Resolver, если вы должны получать те же данные от родителя
this.data = this.route.parent.snaphsot.data['dataFromResolver'];
Примечание 1: Вы можете прочитать о распознавателе здесь. Существует также пример распознавателя и как зарегистрировать распознаватель в модуле, а затем извлечь данные из распознавателя в компонент. Регистрация распознавателя одинакова для родителей и детей.
Примечание 2: Вы можете прочитать об ActivatedRoute здесь, чтобы иметь возможность получать данные с маршрутизатора
Ответ 5
После этого вопроса в Angular 7.2 вы можете передавать данные от родителя к потомку, используя состояние истории. Таким образом, вы можете сделать что-то вроде
Послать:
this.router.navigate(['action-selection'], { state: { example: 'bar' } });
Получить:
constructor(private router: Router) {
console.log(this.router.getCurrentNavigation().extras.state.example);
}
Но будьте осторожны, чтобы быть последовательным. Например, предположим, что вы хотите отобразить список на левой боковой панели и детали выбранного элемента справа, используя розетку маршрутизатора. Что-то вроде:
Элемент 1 (х) |..............................................
Элемент 2 (х) |...... Выбранный пункт Подробнее.......
Элемент 3 (х) |..............................................
Элемент 4 (х) |..............................................
Теперь предположим, что вы уже нажали несколько пунктов. Нажатие кнопки назад браузера покажет детали из предыдущего элемента. Но что, если, тем временем, вы нажали (x) и удалили из списка этот элемент? Затем, выполнив обратный щелчок, вы увидите детали удаленного элемента.