Verileri "yönlendirici çıkışı" alt bileşenlerine geçirme


114

Sunucuya giden ve bir nesneyi getiren bir ana bileşenim var:

// 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);
                }
            );
    }

Ve birkaç çocuk ekranından birinde:

export class ChildDisplay implements OnInit{

    @Input()
    node: Node;

    ngOnInit(): void {
        console.log(this.node);
    }

}

Görünüşe göre router-outlet. Görünüşe göre web konsolunda hatayı alıyorum:

Can't bind to 'node' since it isn't a known property of 'router-outlet'.

Bu biraz mantıklı, ancak aşağıdakileri nasıl yapacağım:

  1. Sunucudaki "düğüm" verilerini ana bileşenin içinden almak mı?
  2. Sunucudan aldığım verileri alt yönlendirici çıkışına iletmek mi?

router-outletsAynı şekilde çalışmak gibi görünmüyor .

Yanıtlar:


87
<router-outlet [node]="..."></router-outlet> 

sadece geçersiz. Yönlendirici tarafından eklenen bileşen, kardeş olarak eklenir <router-outlet>ve onun yerine geçmez.

Ayrıca bkz. 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);
    }
}

Bu çocuğa kimlik vermek için kullanılabilir mi? Değiştim denedim tüm nodenerede bir türü olarak var stringve bu işin görünmüyor ya da ben bir şey yanlış yapıyorum
Wanjia

Alt bileşene herhangi bir veri iletebilirsiniz, ancak alt bileşenin kimliği kendisinin ayarlaması gerekir. ElementRefKimliği ayarlamak için yönlendirici çıkışından bir olaydan bir olay almayı deneyebilirsiniz, ancak bunu nasıl yapacağımı veya nasıl yapacağımı ezbere bilmiyorum (sadece telefonumda)
Günter Zöchbauer

46

Günter'in cevabı harika, sadece Gözlemlenebilirleri kullanmadan başka bir yol göstermek istiyorum.

Burada, bu nesnelerin referansla aktarıldığını hatırlamamız gerekiyor, bu nedenle, çocuktaki nesne üzerinde biraz çalışma yapmak ve ana nesneyi etkilememek istiyorsanız, Günther'in çözümünü kullanmanızı öneririm. Ama önemli değilse veya aslında istenen bir davranışsa , aşağıdakileri öneririm.

@Injectable()
export class SharedService {

    sharedNode = {
      // properties
    };
}

Ebeveyninizde şu değeri atayabilirsiniz:

this.sharedService.sharedNode = this.node;

Ve çocuklarınızda (VE ebeveyn), paylaşılan Hizmeti kurucunuza enjekte edin. Bu modüldeki bileşenlerin tamamına tek bir hizmet istiyorsanız, hizmeti modül düzeyinde sağlayıcılar dizisinde sağlamayı unutmayın. Alternatif olarak, sadece ebeveyn de sağlayıcıları dizideki hizmeti eklemek sadece , üst hem de alt hizmeti aynı örneğini paylaşacak.

node: Node;

ngOnInit() {
    this.node = this.sharedService.sharedNode;    
}

Newman'ın da işaret ettiği gibi, this.sharedService.sharedNodehtml şablonunda veya alıcıda da olabilir:

get sharedNode(){
  return this.sharedService.sharedNode;
}

5
doğrudan html'de sharedService.sharedNode'a bağlanabilir / bağlamalısınız. Bu şekilde, sharedNode'daki güncellemeler senkronize olarak tutulacaktır.
newman

18

Evet, yönlendirici çıkışları aracılığıyla görüntülenen bileşenlerin girişlerini ayarlayabilirsiniz . Ne yazık ki, diğer yanıtlarda da belirtildiği gibi bunu programlı olarak yapmanız gerekiyor. Gözlenebilirler söz konusu olduğunda buna büyük bir uyarı var (aşağıda açıklanmıştır).

Bunu nasıl yapacağınız aşağıda açıklanmıştır:

(1)activate Ana şablondaki yönlendirici çıkışının etkinliğine bağlayın :

<router-outlet (activate)="onOutletLoaded($event)"></router-outlet>

(2) Üst öğenin tipkript dosyasına geçin ve her etkinleştirildiğinde alt bileşenin girişlerini programlı olarak ayarlayın:

onOutletLoaded(component) {
    component.node = 'someValue';
} 

Bitti.

Ancak, yukarıdaki sürüm onOutletLoadednetlik açısından basitleştirilmiştir. Yalnızca, tüm alt bileşenlerin atadığınız aynı girdilere sahip olmasını garanti edebiliyorsanız çalışır. Farklı girişlere sahip bileşenleriniz varsa, tip korumaları kullanın:

onChildLoaded(component: MyComponent1 | MyComponent2) {
  if (component instanceof MyComponent1) {
    component.someInput = 123;
  } else if (component instanceof MyComponent2) {
    component.anotherInput = 456;
  }
}

Neden bu yöntem servis yöntemine tercih edilebilir?

Ne bu yöntem ne de hizmet yöntemi alt bileşenler ile iletişim kurmanın "doğru yolu" değildir (her iki yöntem de saf şablon bağlamadan uzaklaşır), bu nedenle proje için hangi yolun daha uygun olduğuna karar vermeniz yeterlidir.

Bununla birlikte, bu yöntem, "iletişim için bir hizmet yaratma" yaklaşımı ile ilişkili sıkı bağlantıdan kaçınır (yani, ebeveynin hizmete ihtiyacı vardır ve çocukların hepsi hizmete ihtiyaç duyarak çocukları başka yerde kullanılamaz hale getirir). Ayrıştırma genellikle tercih edilir.

Çoğu durumda, bu yöntem aynı zamanda "açısal yola" daha yakın hissettirir, çünkü verileri çocuğunuzun bileşenlerine @Inputs aracılığıyla aktarmaya devam edebilirsiniz (bu, ayrıştırma kısmıdır - bu, başka yerlerde yeniden kullanımı sağlar). Ayrıca, hizmetinizle sıkı bir şekilde birleştirmek istemediğiniz veya bağlayamayacağınız halihazırda mevcut veya üçüncü taraf bileşenler için de uygundur.

Öte yandan, açısal yoldan daha az hissedebilir ...

Uyarı

Bu yöntemle ilgili uyarı, dizgi dosyasındaki verileri ilettiğiniz için, artık {{ myObservable$ | async }}gözlemlenebilir verilerinizi otomatik olarak kullanmak ve alt bileşenlere aktarmak için şablonlarda (örn. ) Kullanılan eşzamansız boru modelini kullanma seçeneğinizin olmamasıdır .

Bunun yerine, onChildLoaded işlev her çağrıldığında mevcut gözlemlenebilir değerleri almak için bir şeyler ayarlamanız gerekir . Bu muhtemelen ana bileşenin onDestroyişlevinde bir miktar kopma gerektirecektir . Bu çok alışılmadık bir şey değil, genellikle şablona bile ulaşmayan bir gözlemlenebilir nesneyi kullanırken bunun yapılması gereken durumlar vardır.


1
Teşekkürler! bu harika bir cevap 👍
Elad

10

Hizmet:

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());
  })
}

Bileşen:

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--);
  }
}

8

Verileri Ebeveynden Çocuklara aktarmanın 3 yolu vardır

  1. Paylaşılabilir hizmet aracılığıyla: Çocuklarla paylaşmak istediğiniz verileri bir hizmette depolamalısınız
  2. Çocuklar Yönlendirici Çözümleyici aracılığıyla, farklı veriler almanız gerekiyorsa

    this.data = this.route.snaphsot.data['dataFromResolver'];
    
  3. Ebeveynden aynı verileri almanız gerekiyorsa, Ebeveyn Yönlendirici Çözümleyici aracılığıyla

    this.data = this.route.parent.snaphsot.data['dataFromResolver'];
    

Not 1: Sen Resolverde okuyabilirsiniz burada . Ayrıca bir çözümleyici örneği ve çözümleyicinin modüle nasıl kaydedileceği ve ardından çözücüden bileşene nasıl veri alınacağı da vardır. Çözümleyici kaydı ebeveynde ve çocukta aynıdır.

Not 2: Sen okuyabilirsiniz ActivatedRoute burada yönlendirici verileri elde edebilmek için


1

Bu soruyu takiben , Angular 7.2'de geçmiş durumunu kullanarak verileri ebeveynden çocuğa aktarabilirsiniz. Böylece bir şey yapabilirsin

Gönder:

this.router.navigate(['action-selection'], { state: { example: 'bar' } });

Al:

constructor(private router: Router) {
  console.log(this.router.getCurrentNavigation().extras.state.example);
}

Ancak tutarlı olmaya dikkat edin. Örneğin, bir yönlendirici çıkışı kullanarak sol taraftaki çubukta bir liste ve sağda seçili öğenin ayrıntılarını görüntülemek istediğinizi varsayalım. Gibi bir şey:


Öğe 1 (x) | ..............................................

Öğe 2 (x) | ...... Seçili Ürün Ayrıntıları .......

Öğe 3 (x) | ..............................................

Öğe 4 (x) | ..............................................


Şimdi, bazı öğeleri zaten tıkladığınızı varsayalım. Tarayıcının geri düğmelerine tıklamak, önceki öğenin ayrıntılarını gösterecektir. Peki ya bu arada (x) işaretine tıkladıysanız ve bu öğeyi listenizden silerseniz ne olur? Ardından geri tıklamayı gerçekleştirmek size silinmiş bir öğenin ayrıntılarını gösterecektir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.