"রাউটার-আউটলেট" শিশু উপাদানগুলিতে ডেটা পাস করা


112

আমার কাছে একটি প্যারেন্ট উপাদান রয়েছে যা সার্ভারে যায় এবং একটি জিনিস নিয়ে আসে:

// 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একইভাবে কাজের মতো বলে মনে হচ্ছে না ।

উত্তর:


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

শুধু অবৈধ। রাউটার দ্বারা যুক্ত উপাদানটি সহোদর হিসাবে যুক্ত করা হয় <router-outlet>এবং এটি প্রতিস্থাপন করে না।

এছাড়াও https://angular.io/guide/comp घटक-interation# 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

গন্টার্সের উত্তরটি দুর্দান্ত, আমি অবজারভেবলগুলি ব্যবহার না করেই অন্য কোনওভাবে নির্দেশ করতে চাই।

এখানে যদিও আমাদের মনে রাখতে হবে যে এই বস্তুগুলি রেফারেন্সের মাধ্যমে পাস হয়েছে, সুতরাং আপনি যদি সন্তানের মধ্যে কোনও বিষয়ে কাজ করতে চান এবং প্যারেন্ট অবজেক্টকে প্রভাবিত না করেন, তবে আমি গন্তারের সমাধানটি ব্যবহার করার পরামর্শ দেব। তবে যদি এটি গুরুত্বপূর্ণ না হয়, বা আসলে পছন্দসই আচরণ হয় তবে আমি নিম্নলিখিতটি প্রস্তাব করব।

@Injectable()
export class SharedService {

    sharedNode = {
      // properties
    };
}

আপনার পিতামাতার মধ্যে আপনি মান নির্ধারণ করতে পারেন:

this.sharedService.sharedNode = this.node;

এবং আপনার বাচ্চাদের (এবং পিতামাতার), আপনার নির্মাতায় ভাগ করা পরিষেবাটি ইনজেক্ট করুন। আপনি যদি মডিউলের সমস্ত উপাদানগুলির মধ্যে একটি সিঙ্গলটন পরিষেবা চান তবে মডিউল স্তর সরবরাহকারী অ্যারেতে পরিষেবা সরবরাহ করতে ভুলবেন না। অন্যথা, শুধু বাবা-মা এ প্রদানকারীর অ্যারের মধ্যে পরিষেবা যোগ শুধুমাত্র , তারপর পিতা বা মাতা এবং শিশু সেবা একই উদাহরণস্বরূপ ভাগ করবে।

node: Node;

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

এবং নিউম্যান দয়া করে নির্দেশিত হিসাবে, আপনি this.sharedService.sharedNodeএইচটিএমএল টেমপ্লেট বা একটি গিটারেও থাকতে পারেন :

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

4
আপনি সরাসরি এইচটিএমএলে শেয়ারড ਸਰਵਿਸ.সারেড নোডে বাঁধতে পারেন / উচিত। এইভাবে, ভাগ করা নোডের আপডেটগুলি সিঙ্কে রাখা হবে।
নিউম্যান

15

হ্যাঁ, আপনি রাউটার আউটলেটগুলির মাধ্যমে প্রদর্শিত উপাদানগুলির ইনপুটগুলি সেট করতে পারেন । দুঃখের বিষয়, অন্যান্য উত্তর হিসাবে উল্লিখিত হিসাবে আপনি এটি প্রোগ্রামিয়ালি করতে হবে। পর্যবেক্ষকরা জড়িত থাকাকালীন (নীচে বর্ণিত) এর একটি বড় সতর্কতা রয়েছে।

এখানে কীভাবে:

(1)activate প্যারেন্ট টেম্পলেটে রাউটার-আউটলেট ইভেন্টটি সম্পর্কে জড়িত:

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

(২) পিতামাতার টাইপ স্ক্রিপ্ট ফাইলে স্যুইচ করুন এবং প্রতিবার সক্রিয় হওয়ার সাথে সাথে শিশু উপাদানটির ইনপুটগুলি প্রোগ্রামিকভাবে সেট করুন:

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

পরিষেবা পদ্ধতির চেয়ে কেন এই পদ্ধতিটিকে প্রাধান্য দেওয়া যেতে পারে?

শিশু উপাদানগুলির সাথে যোগাযোগের জন্য এই পদ্ধতি বা পরিষেবা পদ্ধতি উভয়ই "সঠিক উপায়" নয় (উভয় পদ্ধতি খাঁটি টেমপ্লেট বাঁধাই থেকে দূরে সরে যায়), সুতরাং আপনাকে কেবল সিদ্ধান্ত নিতে হবে যে প্রকল্পের জন্য কোন উপায়ে আরও উপযুক্ত মনে হচ্ছে।

এই পদ্ধতিটি তবে "যোগাযোগের জন্য একটি পরিষেবা তৈরি করুন" পদ্ধতির (যেমন, পিতা-মাতার পরিষেবাটি প্রয়োজন, এবং বাচ্চাদের অন্য যে কোনও জায়গায় অকেজো হয়ে ওঠার জন্য বাচ্চাদের সকলের পরিষেবা প্রয়োজন) সম্পর্কিত সংযুক্ত কৃপণতা এড়ানো যায়। ডিকোপলিং সাধারণত পছন্দ হয়।

অনেক ক্ষেত্রে এই পদ্ধতিটি "কৌণিক উপায়ে" আরও কাছাকাছি অনুভূত হয় কারণ আপনি @ ইনপুটসের মাধ্যমে আপনার সন্তানের উপাদানগুলিতে ডেটা প্রেরণ চালিয়ে যেতে পারেন (ডিকোপলিং অংশটি - এটি অন্য কোথাও পুনরায় ব্যবহার সক্ষম করে)। এটি ইতিমধ্যে বিদ্যমান বা তৃতীয় পক্ষের উপাদানগুলির জন্যও বেশ উপযুক্ত যা আপনি চান না বা আপনার পরিষেবার সাথে শক্তভাবে দম্পতি করতে পারবেন না।

অন্যদিকে, কৌণিক উপায়ে কম মনে হতে পারে যখন ...

গুহা

এই পদ্ধতির সহিত সতর্কতাটি হ'ল যেহেতু আপনি টাইপ স্ক্রিপ্ট ফাইলটিতে ডেটা পাস করছেন, আপনার আর টেমপ্লেটগুলিতে ব্যবহৃত পাইপ-অ্যাসিঙ্ক প্যাটার্ন ব্যবহার করার বিকল্প নেই (উদাহরণস্বরূপ {{ myObservable$ | async }}) স্বয়ংক্রিয়ভাবে ব্যবহারযোগ্য এবং আপনার পর্যবেক্ষণযোগ্য ডেটা শিশু উপাদানগুলিতে প্রেরণ করতে।

পরিবর্তে, যখনই 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: রাউটার থেকে ডেটা পেতে সক্ষম হতে আপনি এখানে অ্যাক্টিভেটেড রুট সম্পর্কে পড়তে পারেন


1

এই প্রশ্নের অনুসরণ করে , কৌণিক .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 (এক্স) | ..............................................


এখন, ধরুন আপনি ইতিমধ্যে কিছু আইটেম ক্লিক করেছেন। ব্রাউজারগুলির ব্যাক বোতামে ক্লিক করা হলে পূর্ববর্তী আইটেমের বিবরণ দেখাবে। তবে, যদি ইতিমধ্যে, আপনি (এক্স) ক্লিক করেছেন এবং আপনার তালিকা থেকে সেই আইটেমটি মুছবেন? তারপরে ব্যাক ক্লিকটি সম্পাদন করে, আপনাকে মুছে ফেলা আইটেমের বিশদ প্রদর্শন করবে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.