जब एक @Input () मान कोणीय में बदल जाता है तो कैसे पता लगाएं?


468

मैं एक माता पिता के घटक (है CategoryComponent ), एक बच्चे घटक ( videoListComponent ) और एक ApiService।

मेरे पास काम करने के लिए यह ठीक है यानी प्रत्येक घटक जन्स एपी तक पहुंच सकता है और वेधशालाओं के माध्यम से इसका प्रासंगिक डेटा प्राप्त कर सकते हैं।

वर्तमान में वीडियो सूची घटक को केवल सभी वीडियो मिलते हैं, मैं इसे केवल एक विशेष श्रेणी में वीडियो के लिए फ़िल्टर करना चाहूंगा, मैंने इस श्रेणी को बच्चे के माध्यम से पास करके प्राप्त किया @Input()

CategoryComponent.html

<video-list *ngIf="category" [categoryId]="category.id"></video-list>

यह काम करता है और जब मूल @Input()श्रेणीकॉम्पेनेंट श्रेणी बदलती है तो श्रेणी आईड वैल्यू से होकर गुजरती है लेकिन मुझे इसके बाद वीडियोलिस्टकंपोनेंट में यह पता लगाने और एपीआईएसईआरएस (नए कैटिगरी के साथ) के माध्यम से वीडियो सरणी को फिर से अनुरोध करने की आवश्यकता है।

AngularJS में मैंने $watchवेरिएबल पर किया होगा । इसे संभालने का सबसे अच्छा तरीका क्या है?



इनपुट परिवर्तन देखें: - angulartutorial.net/2017/12/watch-input-changes-angular-4.html
Prashobh

सरणी में बदलाव के लिए: stackoverflow.com/questions/42962394/…
dasfdsa

जवाबों:


717

दरअसल, एंगुलर 2 + में चाइल्ड कंपोनेंट में इनपुट परिवर्तन होने पर पता लगाने और अभिनय करने के दो तरीके हैं:

  1. आप ngOnChanges () जीवन चक्र विधि का उपयोग कर सकते हैं जैसा कि पुराने उत्तरों में भी उल्लेख किया गया है:
    @Input() categoryId: string;

    ngOnChanges(changes: SimpleChanges) {

        this.doSomething(changes.categoryId.currentValue);
        // You can also use categoryId.previousValue and 
        // categoryId.firstChange for comparing old and new values

    }

प्रलेखन लिंक: ngOnChanges, SimpleChanges, SimpleChange
डेमो उदाहरण: इस प्लंकर को देखें

  1. वैकल्पिक रूप से, आप इनपुट संपत्ति सेटर का उपयोग निम्नानुसार भी कर सकते हैं :
    private _categoryId: string;

    @Input() set categoryId(value: string) {

       this._categoryId = value;
       this.doSomething(this._categoryId);

    }

    get categoryId(): string {

        return this._categoryId;

    }

प्रलेखन लिंक: यहाँ देखें

डेमो उदाहरण: इस प्लंकर को देखें

जो आप का उपयोग करना चाहते हैं?

यदि आपके घटक में कई इनपुट हैं, तो, यदि आप ngOnChanges () का उपयोग करते हैं, तो आपको ngOnChanges () के भीतर एक बार में सभी इनपुट के लिए सभी परिवर्तन मिलेंगे। इस दृष्टिकोण का उपयोग करके, आप इनपुट के वर्तमान और पिछले मूल्यों की तुलना भी कर सकते हैं जो बदल गए हैं और तदनुसार कार्रवाई करते हैं।

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

EDIT 2017-07-25: ANGULAR परिवर्तन की रिपोर्ट अब तक नहीं देखी गई है कि कुछ CIRCUMSTANCES

आम तौर पर, सेटर और एनकोऑन्गेज दोनों के लिए परिवर्तन का पता लगने पर आग लग जाएगी जब भी माता-पिता घटक बच्चे को दिए गए डेटा को बदलते हैं, बशर्ते कि डेटा एक जेएस आदिम डेटाटाइप (स्ट्रिंग, संख्या, बूलियन) हो । हालांकि, निम्नलिखित परिदृश्य में, यह आग नहीं करेगा और आपको इसे काम करने के लिए अतिरिक्त कार्रवाई करनी होगी।

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

  2. यदि आप कोणीय संदर्भ (अर्थात, बाह्य रूप से) के बाहर डेटा उत्परिवर्तन कर रहे हैं, तो कोणीय परिवर्तनों के बारे में पता नहीं होगा। बाहरी परिवर्तनों से कोणीय के बारे में जागरूक करने और इस प्रकार परिवर्तन का पता लगाने के लिए आपको अपने घटक में ChangeDetectorRef या NgZone का उपयोग करना पड़ सकता है। का संदर्भ लें इस


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

2
जब भी अभिभावक इनपुट में बदलाव करेगा, @trichetriche, सेटर (सेट विधि) को कॉल किया जाएगा। इसके अलावा, ngOnChanges () के लिए भी यही सच है।
एलन सीएस

जाहिर है नहीं ... मैं यह पता लगाने की कोशिश करेंगे, यह शायद कुछ गलत है जो मैंने किया।

1
मैं सिर्फ इस सवाल पर लड़खड़ाया, नोट किया कि आपने कहा कि सेटर का उपयोग करने से मूल्यों की तुलना करने की अनुमति नहीं होगी, हालांकि यह सच नहीं है, आप अपनी doSomethingपद्धति को कॉल कर सकते हैं और नए मूल्य निर्धारित करने से पहले नए और पुराने मूल्यों के 2 तर्क ले सकते हैं , एक और तरीका उसके बाद विधि को सेट करने और कॉल करने से पहले पुराने मान को संग्रहीत करना होगा।
T.Aoukar

1
@ T.Aoukar मैं जो कह रहा हूं, वह यह है कि इनपुट सेटर पुराने / नए मूल्यों जैसे ngOnChanges () की तुलना में मूल रूप से समर्थन नहीं करता है। नए मूल्य के साथ तुलना करने के लिए आप पुराने मूल्य को संग्रहीत करने के लिए हमेशा हैक का उपयोग कर सकते हैं (जैसा कि आप उल्लेख करते हैं)।
एलन सीएस

105

उपयोग ngOnChanges()अपने घटक में जीवनचक्र विधि का ।

डेटा-बाउंड प्रॉपर्टीज़ की जाँच के बाद और देखने से पहले और कंटेंट बच्चों की जाँच की जाती है, अगर उनमें से कम से कम एक को बदल दिया गया है, तो ngOnChanges को सही कहा जाता है।

यहाँ डॉक्स हैं


6
यह तब काम करता है जब एक चर को नए मान पर सेट किया जाता है MyComponent.myArray = [], उदाहरण के लिए , लेकिन यदि इनपुट मान को बदल दिया जाता है MyComponent.myArray.push(newValue), ngOnChanges()तो ट्रिगर नहीं किया जाता है। इस बदलाव को पकड़ने के बारे में कोई विचार?
लेवी फुलर

4
ngOnChanges()जब किसी नेस्टेड ऑब्जेक्ट को बदल दिया जाता है तो उसे कॉल नहीं किया जाता है। शायद आपको यहाँ
muetzerich

33

SimpleChangesफ़ंक्शन सिग्नेचर में टाइप का उपयोग करते समय मुझे कंसोल के साथ-साथ कंपाइलर और आईडीई में भी त्रुटियां हो रही थीं । त्रुटियों को रोकने के लिए, anyहस्ताक्षर में कीवर्ड का उपयोग करें ।

ngOnChanges(changes: any) {
    console.log(changes.myInput.currentValue);
}

संपादित करें:

जैसा कि जॉन ने नीचे बताया है, आप SimpleChangesडॉट नोटेशन के बजाय ब्रैकेट नोटेशन का उपयोग करते समय हस्ताक्षर का उपयोग कर सकते हैं ।

ngOnChanges(changes: SimpleChanges) {
    console.log(changes['myInput'].currentValue);
}

1
क्या आपने SimpleChangesअपनी फ़ाइल के शीर्ष पर इंटरफ़ेस आयात किया था ?
जॉन कैटमुल

@ जॉन - हाँ। समस्या केवल हस्ताक्षर की नहीं थी, बल्कि उन मापदंडों तक पहुंच की है जो कि सिंपलचेंज ऑब्जेक्ट पर रनटाइम में सौंपी जाती हैं। उदाहरण के लिए, मेरे घटक में मैंने अपने उपयोगकर्ता वर्ग को इनपुट (यानी <my-user-details [user]="selectedUser"></my-user-details>) के लिए बाध्य किया है । इस संपत्ति को कॉल करके SimpleChanges क्लास से एक्सेस किया जाता है changes.user.currentValue। नोटिस userरनटाइम पर बाध्य है और सिंपलचेंज ऑब्जेक्ट का हिस्सा नहीं है
डार्सी 16

1
क्या आपने यह कोशिश की है? ngOnChanges(changes: {[propName: string]: SimpleChange}) { console.log('onChanges - myProp = ' + changes['myProp'].currentValue); }
जॉन कैटमुल

@Jon - ब्रैकेट नोटेशन पर स्विच करने से ट्रिक आती है। मैंने विकल्प के रूप में इसे शामिल करने के लिए अपना उत्तर अपडेट किया।
डार्सी

1
'@ कोणीय / कोर' से {SimpleChanges} आयात करें; यदि यह कोणीय डॉक्स में है, और मूल प्रकार का नहीं है, तो यह संभवतः कोणीय मॉड्यूल से है, सबसे अधिक संभावना 'कोणीय / कोर' है
बेंटऑन कोडिंग

13

सबसे सुरक्षित शर्त एक पैरामीटर के बजाय एक साझा सेवा के साथ जाना है @Input। इसके अलावा,@Input पैरामीटर जटिल नेस्टेड ऑब्जेक्ट प्रकार में परिवर्तनों का पता नहीं लगाता है।

एक सरल उदाहरण सेवा इस प्रकार है:

Service.ts

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';

@Injectable()
export class SyncService {

    private thread_id = new Subject<number>();
    thread_id$ = this.thread_id.asObservable();

    set_thread_id(thread_id: number) {
        this.thread_id.next(thread_id);
    }

}

Component.ts

export class ConsumerComponent implements OnInit {

  constructor(
    public sync: SyncService
  ) {
     this.sync.thread_id$.subscribe(thread_id => {
          **Process Value Updates Here**
      }
    }

  selectChat(thread_id: number) {  <--- How to update values
    this.sync.set_thread_id(thread_id);
  }
}

आप अन्य घटकों में समान कार्यान्वयन का उपयोग कर सकते हैं और आपके सभी घटक समान साझा मूल्यों को साझा करेंगे।


1
थैंक्यू संकेट यह बनाने के लिए एक बहुत अच्छा बिंदु है और जहां इसे करने का एक बेहतर तरीका उपयुक्त है। मैं स्वीकार किए गए उत्तर को छोड़ दूंगा क्योंकि यह @Input परिवर्तनों का पता लगाने के बारे में मेरे विशिष्ट प्रश्नों के उत्तर देता है।
जॉन कैटमुल

1
कोई @Input पैरामीटर किसी जटिल नेस्टेड ऑब्जेक्ट प्रकार के अंदर परिवर्तनों का पता नहीं लगाता है , लेकिन यदि ऑब्जेक्ट स्वयं बदलता है, तो यह सही होगा? उदाहरण के लिए मेरे पास इनपुट पैरामीटर "पैरेंट" है, इसलिए अगर मैं माता-पिता को एक पूरे के रूप में बदल दूं, तो परिवर्तन का पता लग जाएगा, लेकिन अगर मैं पेरेंट.नाम बदलूं, तो यह नहीं होगा?
योगींबी

आपको एक कारण प्रदान करना चाहिए कि आपका समाधान क्यों सुरक्षित है
जोशुआ केमर

1
@JoshuaKemmerer @Inputपैरामीटर जटिल नेस्टेड ऑब्जेक्ट प्रकार में परिवर्तनों का पता नहीं लगाता है लेकिन यह साधारण देशी वस्तुओं में करता है।
साकेत बेर्डे

6

मैं सिर्फ यह जोड़ना चाहता हूं कि एक और जीवनचक्र हुक कहा जाता DoCheckहै जो उपयोगी है यदि@Input मूल्य एक आदिम मूल्य नहीं है।

मेरे पास एक ऐरे है, क्योंकि Inputयह OnChangesसामग्री के बदलने पर इस घटना को आग नहीं देता है (क्योंकि जाँच जो कोणीय करता है वह 'सरल' है और गहरी नहीं है इसलिए एरे अभी भी एक ऐरे है, भले ही एरे पर सामग्री बदल गई हो)।

फिर मैं यह तय करने के लिए कुछ कस्टम चेकिंग कोड लागू करता हूं कि क्या मैं बदले हुए ऐरे के साथ अपने विचार को अपडेट करना चाहता हूं।


6
  @Input()
  public set categoryId(categoryId: number) {
      console.log(categoryId)
  }

कृपया इस विधि का उपयोग करके देखें। उम्मीद है की यह मदद करेगा


4

आपके पास, एक अवलोकन योग्य भी हो सकता है जो मूल घटक (श्रेणी) में परिवर्तन पर ट्रिगर होता है और वह करें जो आप बच्चे के घटक की सदस्यता में करना चाहते हैं। (videoListComponent)

service.ts 
public categoryChange$ : ReplaySubject<any> = new ReplaySubject(1);

-----------------
CategoryComponent.ts
public onCategoryChange(): void {
  service.categoryChange$.next();
}

-----------------
videoListComponent.ts
public ngOnInit(): void {
  service.categoryChange$.subscribe(() => {
   // do your logic
});
}

2

जब आपकी इनपुट प्रॉपर्टी में बदलाव होगा, तो ngOnChanges हमेशा ट्रिगर होगा:

ngOnChanges(changes: SimpleChanges): void {
 console.log(changes.categoryId.currentValue)
}

1

यह समाधान प्रॉक्सी वर्ग का उपयोग करता है और निम्नलिखित लाभ प्रदान करता है:

  • उपभोक्ता को आरजेजेएस की शक्ति का लाभ उठाने की अनुमति देता है
  • अधिक कॉम्पैक्टअब तक प्रस्तावित अन्य समाधानों की तुलना में
  • उपयोग करने से अधिक प्रकारngOnChanges()

उदाहरण उपयोग:

@Input()
public num: number;
numChanges$ = observeProperty(this as MyComponent, 'num');

उपयोगिता समारोह:

export function observeProperty<T, K extends keyof T>(target: T, key: K) {
  const subject = new BehaviorSubject<T[K]>(target[key]);
  Object.defineProperty(target, key, {
    get(): T[K] { return subject.getValue(); },
    set(newValue: T[K]): void {
      if (newValue !== subject.getValue()) {
        subject.next(newValue);
      }
    }
  });
  return subject;
}

0

यदि आप ngOnChange कार्यान्वयन og (onChange) विधि का उपयोग नहीं करना चाहते हैं, तो आप valueChanges event , ETC द्वारा किसी विशिष्ट आइटम के परिवर्तन की सदस्यता भी ले सकते हैं ।

 myForm= new FormGroup({
first: new FormControl()   

});

this.myForm.valueChanges.subscribe(formValue => {
  this.changeDetector.markForCheck();
});

इस घोषणा में उपयोग करने के कारण markForCheck () रिटेन:

  changeDetection: ChangeDetectionStrategy.OnPush

3
यह सवाल से पूरी तरह से अलग है और यद्यपि मददगार लोगों को यह पता होना चाहिए कि आपका कोड एक अलग प्रकार के परिवर्तन के बारे में है। डेटा बदलने के बारे में पूछा गया सवाल जो OUTSIDE एक घटक से है और फिर आपके घटक को पता है और इस तथ्य पर प्रतिक्रिया दें कि डेटा बदल गया है। आपका उत्तर घटक के भीतर होने वाले परिवर्तनों का पता लगाने के बारे में बात कर रहा है, जैसे कि प्रपत्र पर इनपुट्स जो घटक के लिए LOCAL हैं।
rmcsharry

0

आप इनपुट के रूप में एक EventEmitter भी पास कर सकते हैं। यकीन नहीं है कि अगर यह सबसे अच्छा अभ्यास है ...

CategoryComponent.ts:

categoryIdEvent: EventEmitter<string> = new EventEmitter<>();

- OTHER CODE -

setCategoryId(id) {
 this.category.id = id;
 this.categoryIdEvent.emit(this.category.id);
}

CategoryComponent.html:

<video-list *ngIf="category" [categoryId]="categoryIdEvent"></video-list>

और VideoListComponent.ts में:

@Input() categoryIdEvent: EventEmitter<string>
....
ngOnInit() {
 this.categoryIdEvent.subscribe(newID => {
  this.categoryId = newID;
 }
}

कृपया अपने समाधान का समर्थन करने के लिए उपयोगी लिंक, कोड स्निपेट प्रदान करें।
मिसेक्स

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