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

Передача данных в дочерние компоненты "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'.

Это в некоторой степени имеет смысл, но как бы я поступил следующим образом:

  1. Захватите данные "узла" с сервера, из родительского компонент?
  2. Передать данные, полученные с сервера, в дочерний маршрутизатор?

Похоже, что router-outlets не работает так же.

4b9b3361

Ответ 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 способа передачи данных от родителей к детям

  1. Через разделяемый сервис: вы должны хранить в сервисе данные, которыми вы хотели бы поделиться с детьми
  2. Через Children Router Resolver, если вам нужно получать разные данные

    this.data = this.route.snaphsot.data['dataFromResolver'];
    
  3. Через 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) и удалили из списка этот элемент? Затем, выполнив обратный щелчок, вы увидите детали удаленного элемента.