मैं कोणीय 2 में घटकों के बीच डेटा कैसे साझा करूं?


84

कोणीय 1.xx में आप बस एक ही सेवा के लिए पूछते हैं और आप एक ही उदाहरण के साथ समाप्त होते हैं, जिससे सेवा में डेटा साझा करना संभव हो जाता है।

अब एंगुलर 2 में मेरे पास एक घटक है जिसमें मेरी सेवा का संदर्भ है। मैं सेवा में डेटा को पढ़ और संशोधित कर सकता हूं, जो अच्छा है। जब मैं उसी सेवा को किसी अन्य घटक में इंजेक्ट करने की कोशिश करता हूं, तो ऐसा लगता है जैसे मुझे एक नया उदाहरण मिलता है।

मैं क्या गलत कर रहा हूं? क्या यह वही पैटर्न है जो गलत है (डेटा साझा करने के लिए किसी सेवा का उपयोग करके) या क्या मुझे सेवा को एक सिंगलटन (ऐप के एक उदाहरण के भीतर) या कुछ और के रूप में चिह्नित करने की आवश्यकता है?

मैं 2.0.0-alpha.27/ btw पर हूँ

मैं एनोटेशन में एक सेवा के माध्यम से appInjector(संपादित करें: अब providers) इंजेक्ट करता हूं @Componentऔर फिर कंस्ट्रक्टर में एक संदर्भ सहेजता हूं । यह घटक में स्थानीय रूप से काम करता है - बस घटकों के पार नहीं (वे उसी सेवा उदाहरण को साझा नहीं करते हैं) जैसे मैंने सोचा था कि वे करेंगे।

अद्यतन : कोणीय 2.0.0 के रूप में, अब हमारे पास @ngModule है, जहां आप इस providersसंपत्ति को सेवा के तहत परिभाषित करेंगे @ngModule। यह उस मॉड्यूल में प्रत्येक घटक, सेवा आदि को पारित करने के लिए उस सेवा का एक ही उदाहरण सुनिश्चित करेगा। https://angular.io/docs/ts/latest/guide/ngmodule.html#providers

अद्यतन : सामान्य रूप से कोणीय और फे विकास के लिए बहुत कुछ हुआ है। जैसा कि @noririco ने उल्लेख किया है, आप एक राज्य प्रबंधन प्रणाली का भी उपयोग कर सकते हैं जैसे NgRx: https://ngrx.io/


कोणीय घटकों के बीच डेटा साझा करने के लिए छह तरीके: - angulartutorial.net/2017/12/…
Prashobh

यदि आप यहां पहुंचें तो कृपया STATE मैनेजमेंट सिस्टम का उपयोग करने पर विचार करें
noririco

जवाबों:


63

एक सर्विस सिंगलटन एक अच्छा उपाय है। अन्य तरीका - data/events bindings

यहाँ दोनों का एक उदाहरण दिया गया है:

class BazService{
  n: number = 0;
  inc(){
    this.n++;
  }
}

@Component({
  selector: 'foo'
})
@View({
  template: `<button (click)="foobaz.inc()">Foo {{ foobaz.n }}</button>`
})
class FooComponent{
  constructor(foobaz: BazService){
    this.foobaz = foobaz;
  }
}

@Component({
  selector: 'bar',
  properties: ['prop']
})
@View({
  template: `<button (click)="barbaz.inc()">Bar {{ barbaz.n }}, Foo {{ prop.foobaz.n }}</button>`
})
class BarComponent{
  constructor(barbaz: BazService){
    this.barbaz = barbaz;
  }
}

@Component({
    selector: 'app',
    viewInjector: [BazService]
})
@View({
  template: `
    <foo #f></foo>
    <bar [prop]="f"></bar>
  `,
  directives: [FooComponent, BarComponent]
})
class AppComponent{}

bootstrap(AppComponent);

लाइव देखें


20
मैं यह समझ गया। आप केवल एक सेवा उदाहरण - 'ऐप' में इंजेक्ट करते हैं। वही उदाहरण स्वचालित रूप से विरासत में मिला है, जब बाल रचनाकारों को पैरामीटर जोड़ते हैं :) मैंने एक और appInjector को बाल घटकों में जोड़ने की गलती की जो नए उदाहरण बनाता है।
प्रति हॉर्नशोज-शियरबेक

1
@AlexanderCrush क्या आप अपना उत्तर अपडेट कर सकते हैं? चूँकि बाद के अल्फा संस्करणों (अल्फा 30+) ऐप में इंजेक्टर हटा दिया गया था । सही उत्तर, अभी के लिए, उपयोग करने के लिए होना चाहिए viewInjector
एरिक मार्टिनेज

1
@EricMartinez धन्यवाद, उत्तर और प्लंकर अपडेट किया गया है।
अलेक्जेंडर एर्मोलोव

1
यह क्यों और कैसे काम करता है, यह समझने के लिए दिलचस्प संसाधन: blog.thoughtram.io/angular/2015/08/20/…
सोयूका

2
मेरे पास एक ही समस्या थी, क्योंकि मैं मुख्य ऐप में सेवा को इंजेक्ट कर रहा था, और घटक में भी उपयोग कर रहा था providers: [MyService]। प्रदाताओं को
हटाते हुए

43

@Maufarinelli की टिप्पणी अपने स्वयं के जवाब की हकदार है क्योंकि जब तक मैंने इसे देखा, मैं तब भी इस मुद्दे के साथ दीवार के खिलाफ अपने सिर को कोस रहा था, यहां तक ​​कि @Alexander Ermolov के जवाब के साथ।

समस्या यह है कि जब आप providersअपने को जोड़ते हैं component:

@Component({
    selector: 'my-selector',
    providers: [MyService],
    template: `<div>stuff</div>`
})

यह आपकी सेवा के एक नए उदाहरण को इंजेक्ट होने का कारण बनता है ... एक सिंगलटन होने के बजाय ।

तो providers: [MyService]अपने आवेदन में अपने सभी उदाहरणों को हटा दें module, सिवाय और यह काम करेगा!


2
बस एक टिप्पणी है, यह कभी एक सिंगलटन नहीं है - यह सिर्फ एक ही उदाहरण है जो चारों ओर से गुजर रहा है। आप अभी भी एक नए उदाहरण का अनुरोध कर सकते हैं ...
प्रति हॉर्न्ज-शियरबेक

10

आपको @Component डेकोरेटर के इनपुट और आउटपुट का उपयोग करना चाहिए। यहां दोनों का उपयोग करने का सबसे बुनियादी उदाहरण है;

import { bootstrap } from 'angular2/platform/browser';
import { Component, EventEmitter } from 'angular2/core';
import { NgFor } from 'angular2/common';

@Component({
  selector: 'sub-component',
  inputs: ['items'],
  outputs: ['onItemSelected'],
  directives: [NgFor],
  template: `
    <div class="item" *ngFor="#item of items; #i = index">
      <span>{{ item }}</span>
      <button type="button" (click)="select(i)">Select</button>
    </div>
  `
})

class SubComponent {
  onItemSelected: EventEmitter<string>;
  items: string[];

  constructor() {
    this.onItemSelected = new EventEmitter();
  }

  select(i) {
    this.onItemSelected.emit(this.items[i]);
  }
}

@Component({
  selector: 'app',
  directives: [SubComponent],
  template: `
    <div>
      <sub-component [items]="items" (onItemSelected)="itemSelected($event)">
      </sub-component>
    </div>
  `
})

class App {
  items: string[];

  constructor() {
    this.items = ['item1', 'item2', 'item3'];
  }

  itemSelected(item: string): void {
    console.log('Selected item:', item);
  }
}

bootstrap(App);

7
आयात करने की कोई आवश्यकता नहीं है ngFor,
रिचर्ड हैमिल्टन

7

मूल घटक टेम्पलेट में:

<hero-child [hero]="hero">
</hero-child>

बच्चे में घटक:

@Input() hero: Hero;

स्रोत: https://angular.io/docs/ts/latest/cookbook/component-communication.html


हो सकता है, लेकिन इसके लिए अधिक विवरण की आवश्यकता होगी। वास्तविक दुनिया में यह इतना आसान नहीं है। कल्पना करें कि आपके पास एक वर्ग है जिसे आप कई घटकों के बीच साझा करना चाहते हैं, और डेटा तक पहुंच प्राप्त कर सकते हैं। वह काम नहीं करता।
संकलोट

मैं कई घटकों के बीच डेटा साझा करने के लिए एक बड़े समाधान में इस दृष्टिकोण का उपयोग कर रहा हूं। आपके पास एक ही वस्तु प्राप्त करने वाले कई चिल्ड और प्रत्येक हो सकते हैं। क्या आपने यह कहने से पहले यह करने की कोशिश की कि यह काम नहीं करता है?
एलेक्सिस गामरा

हाँ, मैंने किया । यह काम करेगा .... लेकिन कुछ मुद्दों को हल करने के लिए "हैकिंग" के साथ। आपका उत्तर किसी को भी इसका उपयोग करने की अनुमति नहीं देता है।
संचलोट

2

बहुत तरीके हैं। यह एक अभिभावक और बच्चे के तत्वों के बीच प्रसार का उपयोग कर एक उदाहरण है। यह बहुत कुशल है।

मैंने एक उदाहरण प्रस्तुत किया जो दो रूपों के दो तरीकों के उपयोग को देखने की अनुमति देता है। अगर किसी को एक plunkr नमूना प्रदान कर सकते हैं यह बहुत अच्छा होगा ;-)

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

mymodel.ts (साझा करने के लिए डेटा)

// Some data we want to share against multiple components ...
export class mymodel {
    public data1: number;
    public data2: number;
    constructor(
    ) {
        this.data1 = 8;
        this.data2 = 45;
    }
}

याद रखें: एक माता-पिता होना चाहिए जो बच्चे के घटकों को "मायमॉडल" साझा करेगा।

जनक घटक

import { Component, OnInit } from '@angular/core';
import { mymodel } from './mymodel';
@Component({
    selector: 'app-view',
    template: '<!-- [model]="model" indicates you share model to the child component -->
        <app-mychild [model]="model" >
        </app-mychild>'

        <!-- I add another form component in my view,
         you will see two ways databinding is working :-) -->
        <app-mychild [model]="model" >
        </app-mychild>',
})

export class MainComponent implements OnInit {
    public model: mymodel;
    constructor() {
        this.model = new mymodel();
    }
    ngOnInit() {
    }
}

बाल घटक, mychild.component.ts

import { Component, OnInit,Input } from '@angular/core';
import { FormsModule }   from '@angular/forms'; // <-- NgModel lives here
import { mymodel } from './mymodel';

@Component({
    selector: 'app-mychild',
    template: '
        <form #myForm="ngForm">
            <label>data1</label>
            <input type="number"  class="form-control" required id="data1 [(ngModel)]="model.data1" name="data1">
            <label>val {{model.data1}}</label>

            label>data2</label>
            <input  id="data2"  class="form-control" required [(ngModel)]="model.data2" name="data2" #data2="ngModel">
            <div [hidden]="data2.valid || data2.pristine"
                class="alert alert-danger">
                data2 is required
            </div>

            <label>val2 {{model.data2}}</label>
        </form>
    ',
})

export class MychildComponent implements OnInit {
    @Input() model: mymodel ;  // Here keywork @Input() is very important it indicates that model is an input for child component
    constructor() {
    }
    ngOnInit() {
    }
}

नोट: कुछ दुर्लभ मामलों में, HTML कोड को पार्स किए जाने पर आपको त्रुटि हो सकती है, क्योंकि मॉडल पृष्ठ के आरंभ में उपयोग करने के लिए "तैयार" नहीं है। इस स्थिति में, एक ngIf शर्त के साथ HTML कोड को उपसर्ग करें:

<div *ngIf="model"> {{model.data1}} </div>

1

यह निर्भर करता है, अगर कोई साधारण मामला है

क) ए -> बी -> सी ए में दो बच्चे बी और सी हैं और यदि आप ए और बी या ए और सी के बीच डेटा साझा करना चाहते हैं तो उपयोग करें (इनपुट / आउटपुट)

यदि आप B और C के बीच साझा करना चाहते हैं तो आप भी (इनपुट / आउटपुट) का उपयोग कर सकते हैं, लेकिन यह सेवा का उपयोग करने का सुझाव दिया गया है।

b) यदि पेड़ बड़ा और जटिल है। (यदि माता-पिता और बच्चों के कनेक्शन के बहुत सारे स्तर हैं।) और इस मामले में यदि आप डेटा साझा करना चाहते हैं तो मैं ngrx सुझाव दूंगा

यह फ्लक्स आर्किटेक्चर को लागू करता है जो एक क्लाइंट साइड स्टोर बनाता है जिसमें कोई भी घटक सदस्यता ले सकता है और किसी भी दौड़ की स्थिति बनाए बिना अपडेट कर सकता है।

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