"राउटर-आउटलेट" बाल घटकों में डेटा पास करना


100

मुझे एक मूल घटक मिला है जो सर्वर पर जाता है और एक ऑब्जेक्ट प्राप्त करता है:

// 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उसी तरह काम नहीं लगता है ।

जवाबों:


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

क्या इसका उपयोग बच्चे को आईडी देने के लिए किया जा सकता है? मैंने उन सभी को बदलने की कोशिश की है nodeजहां यह एक प्रकार के रूप में है stringऔर यह काम नहीं करता है या मैं कुछ गलत कर रहा हूं
वंजिया

आप किसी भी डाटा को चाइल्ड कंपोनेंट में पास कर सकते हैं लेकिन चाइल्ड कंपोनेंट को आईडी खुद सेट करना होगा। आप ElementRefराउटर आउटलेट से ईवेंट सेट करने के लिए इसका उपयोग करने के लिए किसी ईवेंट से प्राप्त करने का प्रयास कर सकते हैं , लेकिन मैं दिल से नहीं जानता कि क्या करना है या कैसे करना है (केवल मेरे फोन पर)
गुंटर जोचबॉयर

46

Günters का जवाब बहुत अच्छा है, मैं सिर्फ ऑब्जर्वबल्स का उपयोग किए बिना एक और तरीका बताना चाहता हूं।

हालांकि हमें यह याद रखना होगा कि ये ऑब्जेक्ट्स संदर्भ द्वारा पारित किए गए हैं, इसलिए यदि आप बच्चे में ऑब्जेक्ट पर कुछ काम करना चाहते हैं और मूल ऑब्जेक्ट को प्रभावित नहीं करना चाहते हैं, तो मैं गुंटर के समाधान का उपयोग करने का सुझाव दूंगा। लेकिन अगर यह मायने नहीं रखता है, या वास्तव में वांछित व्यवहार है , तो मैं निम्नलिखित सुझाव दूंगा।

@Injectable()
export class SharedService {

    sharedNode = {
      // properties
    };
}

अपने माता-पिता में आप मूल्य निर्दिष्ट कर सकते हैं:

this.sharedService.sharedNode = this.node;

और अपने बच्चों (और माता-पिता) में, अपने कंस्ट्रक्टर में साझा सेवा को इंजेक्ट करें। यदि आप उस मॉड्यूल में सभी घटकों पर एक सिंगलटन सेवा चाहते हैं तो मॉड्यूल स्तर प्रदाता सरणी में सेवा प्रदान करना याद रखें। वैकल्पिक रूप से, सिर्फ माता-पिता में प्रदाताओं सरणी में सेवा जोड़ने केवल , तो माता-पिता और बच्चे सेवा का एक ही उदाहरण साझा करेंगे।

node: Node;

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

और जैसा कि न्यूमैन ने बताया है, आप this.sharedService.sharedNodehtml टेम्पलेट या एक गटर में भी हो सकते हैं :

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

5
आप सीधे html में shareService.saredNode को बाँध सकते हैं / कर सकते हैं। इस तरह, शेयर्डनोड में अपडेट सिंक में रखे जाएंगे।
न्यूमैन

11

हां, आप राउटर आउटलेट के माध्यम से प्रदर्शित घटकों के इनपुट सेट कर सकते हैं । अफसोस की बात है, आपको इसे प्रोग्रामेटिक रूप से करना होगा, जैसा कि अन्य उत्तरों में बताया गया है। वहाँ एक बड़ा चेतावनी है कि जब वेधशालाएँ शामिल हैं (नीचे वर्णित है)।

ऐसे:

(1)activate अभिभावक टेम्पलेट में राउटर-आउटलेट की घटना तक हुक :

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

(2) माता-पिता की टाइपस्क्रिप्ट फ़ाइल पर स्विच करें और बच्चे के इनपुट को प्रोग्रामेटिक रूप से सक्रिय होने पर हर बार सेट करें:

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

onOutletLoadedस्पष्टता के लिए उपर्युक्त संस्करण को सरल बनाया गया है, लेकिन केवल तभी काम करता है जब आप गारंटी दे सकते हैं कि सभी बाल घटकों के पास ठीक वही इनपुट हैं जो आप असाइन कर रहे हैं। यदि आपके पास अलग-अलग इनपुट के साथ घटक हैं, तो गार्ड का उपयोग करें:

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

सेवा पद्धति पर इस पद्धति को क्यों पसंद किया जा सकता है?

बाल घटकों के साथ संवाद करने के लिए न तो यह विधि और न ही सेवा पद्धति "सही तरीका" है (दोनों विधियाँ शुद्ध टेम्पलेट बाइंडिंग से दूर हैं), इसलिए आपको बस यह तय करना होगा कि परियोजना के लिए कौन सा तरीका अधिक उपयुक्त लगता है।

यह विधि, हालांकि, आपको मध्य-पुरुष वस्तु (सेवा) बनाने से बचने की अनुमति देती है, जो सेवा और बाल घटकों को कसकर जोड़े। कई मामलों में यह "कोणीय तरीके" के करीब महसूस होता है क्योंकि आप @Inputs के माध्यम से अपने बच्चे के घटकों को डेटा भेजना जारी रख सकते हैं। यह पहले से मौजूद या थर्ड-पार्टी घटकों के लिए एक अच्छा फिट है जो आप नहीं चाहते हैं या उस सेवा के साथ जोड़े को कसकर नहीं कर सकते हैं। दूसरी ओर, यह कोणीय तरीके से कम महसूस हो सकता है जब ...

चेतावनी

इस विधि के साथ चेतावनी यह है कि चूंकि आप डेटा को प्रोग्रामिक रूप से पास कर रहे हैं, इसलिए आपके पास अब आपके टेम्प्लेट (आश्चर्य!) में अवलोकन डेटा पास करने का विकल्प नहीं है। इसका मतलब है कि जब आप पाइप-एसिंक्स पैटर्न का उपयोग करते हैं, तो आप के लिए अवलोकन योग्य जीवनचक्र का प्रबंधन करने वाले कोणीय का बड़ा लाभ खो देते हैं।

जब भी onChildLoaded फ़ंक्शन कहा जाता है , इसके बजाय, आपको वर्तमान अवलोकन मूल्यों को प्राप्त करने के लिए कुछ सेट करना होगा । यह संभवतः मूल घटक के onDestroyकार्य में कुछ छेड़छाड़ की आवश्यकता होगी । यह कुछ भी असामान्य नहीं है, ऐसे अन्य मामले भी हैं जहां ऐसा करने की आवश्यकता होती है, जैसे कि एक अवलोकनीय का उपयोग करते समय जो टेम्पलेट तक भी नहीं पहुंचता है।


9

सर्विस:

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

8

माता-पिता से बच्चों तक डेटा पास करने के 3 तरीके हैं

  1. साझा करने योग्य सेवा के माध्यम से: आपको उन सेवाओं में संग्रहीत करना चाहिए, जो डेटा आप बच्चों के साथ साझा करना चाहते हैं
  2. चिल्ड्रेन राउटर रिज़ॉल्वर के माध्यम से यदि आपको अलग-अलग डेटा प्राप्त करना है

    this.data = this.route.snaphsot.data['dataFromResolver'];
    
  3. पेरेंट राउटर रिज़ॉल्वर के माध्यम से यदि आपके पास माता-पिता से समान डेटा प्राप्त करना है

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

नोट 1: आप यहाँ रिज़ॉल्वर के बारे में पढ़ सकते हैं । रिज़ॉल्वर का एक उदाहरण भी है और रिज़ॉल्वर को मॉड्यूल में कैसे पंजीकृत किया जाए और फिर रिज़ॉल्वर से डेटा को घटक में पुनः प्राप्त किया जाए। रिज़ॉल्वर पंजीकरण माता-पिता और बच्चे पर समान है।

टिप्पणी 2: आप के बारे में पढ़ सकते हैं ActivatedRoute यहाँ रूटर से डेटा प्राप्त करने में सक्षम हो


1

इस प्रश्न के बाद , एंगुलर 7.2 में आप इतिहास की स्थिति का उपयोग करके माता-पिता से बच्चे के लिए डेटा पास कर सकते हैं। तो आप कुछ ऐसा कर सकते हैं

भेजें:

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

प्राप्त करें:

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

लेकिन लगातार सावधान रहें। उदाहरण के लिए, मान लें कि आप किसी राउटर-आउटलेट का उपयोग करके बाईं ओर पट्टी पर एक सूची और दाईं ओर चयनित आइटम का विवरण प्रदर्शित करना चाहते हैं। कुछ इस तरह:


आइटम 1 (x) | ..............................................

आइटम 2 (x) | ...... चयनित आइटम विवरण ......।

आइटम 3 (x) | ..............................................

आइटम 4 (x) | ..............................................


अब, मान लीजिए कि आपने पहले ही कुछ आइटम क्लिक कर लिए हैं। ब्राउज़र्स बैक बटन पर क्लिक करने से पिछले आइटम का विवरण दिखाई देगा। लेकिन क्या होगा अगर, इस बीच, आपने (x) पर क्लिक किया है और उस आइटम को अपनी सूची से हटा दिया है? फिर बैक क्लिक करते हुए, आपको हटाए गए आइटम का विवरण दिखाएगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.