कोणीय में रूप परिवर्तन के लिए कैसे देखें


151

कोणीय में, मेरा एक रूप हो सकता है जो इस तरह दिखता है:

<ng-form>
    <label>First Name</label>
    <input type="text" ng-model="model.first_name">

    <label>Last Name</label>
    <input type="text" ng-model="model.last_name">
</ng-form>

संबंधित नियंत्रक के भीतर, मैं आसानी से उस फॉर्म की सामग्री में बदलाव के लिए देख सकता था जैसे:

function($scope) {

    $scope.model = {};

    $scope.$watch('model', () => {
        // Model has updated
    }, true);

}

यहाँ JSFiddle पर एक कोणीय उदाहरण है

मुझे पता चल रहा है कि कोणीय में एक ही चीज़ को कैसे पूरा करना है। जाहिर है, हमारे पास अब $scope$ rootScope नहीं है। निश्चित रूप से एक विधि है जिसके द्वारा एक ही काम पूरा किया जा सकता है?

यहाँ प्लंकर पर एक कोणीय उदाहरण है


अपने नियंत्रक से कुछ डेटा देखने के बजाय, मुझे लगता है कि आपको अपने फॉर्म से एक घटना (पुराने एनजी-परिवर्तन) की तरह आग लगानी चाहिए।
डेब्लाटन जीन-फिलिप

btw, गुंजाइश को हटाने का कारण उन पहरेदारों से छुटकारा पाना है। मुझे नहीं लगता कि कोणीय 2 में कहीं एक घड़ी छिपी हुई है
डेब्लाटन जीन-फिलिप

4
अगर मैं आपको सही तरीके से समझ रहा हूं, तो आप सुझाव दे रहे हैं कि मैं इसे पूरा करने के लिए हर फॉर्म इनपुट में एक (ngModelChange)="onModelChange($event)"विशेषता जोड़ दूं?
टैबलर

1
क्या प्रपत्र उदाहरण स्वयं किसी प्रकार की परिवर्तन घटना का उत्सर्जन नहीं करता है? यदि हां, तो आप इसे कैसे एक्सेस करते हैं?
टैबलर

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

जवाबों:


189

युपीडी। उत्तर और डेमो को नवीनतम कोणीय के साथ संरेखित करने के लिए अद्यतन किया जाता है।


आप इस तथ्य के कारण संपूर्ण प्रपत्र परिवर्तनों की सदस्यता ले सकते हैं कि फ़ॉर्म का प्रतिनिधित्व करने वाला फ़ॉर्म समूह valueChangesसंपत्ति प्रदान करता है जो एक ऑब्ज़र्वर उदाहरण है:

this.form.valueChanges.subscribe(data => console.log('Form changes', data));

इस मामले में आपको फ़ॉर्मब्यूलर का उपयोग करके मैन्युअल रूप से निर्माण करने की आवश्यकता होगी । कुछ इस तरह:

export class App {
  constructor(private formBuilder: FormBuilder) {
    this.form = formBuilder.group({
      firstName: 'Thomas',
      lastName: 'Mann'
    })

    this.form.valueChanges.subscribe(data => {
      console.log('Form changes', data)
      this.output = data
    })
  }
}

valueChangesइस डेमो में एक्शन देखें : http://plnkr.co/edit/xOz5xaQyMlRzSrgtt7Wn?p=preview


2
यह निशान के बहुत करीब है। पुष्टि करने के लिए - क्या आप मुझे बता रहे हैं कि किसी प्रपत्र के इवेंट एमिटर को सब्सक्राइब करना संभव नहीं है अगर उस फॉर्म को केवल टेम्पलेट के भीतर परिभाषित किया गया है? दूसरे शब्दों में - एक घटक के निर्माता के भीतर, क्या उस रूप का संदर्भ प्राप्त करना संभव नहीं है जो केवल उस घटक के टेम्पलेट के भीतर परिभाषित किया गया था और फॉर्मब्यूलर की मदद से नहीं? valueChanges
तंबाल

यह सही जवाब है। यदि आपके पास कोई फॉर्म बिल्डर नहीं है तो आप टेम्पलेट संचालित फॉर्म कर रहे हैं। वहाँ शायद एक तरह से अभी भी प्रपत्र इंजेक्शन लेकिन अगर आप प्रत्यक्ष form.valueChanges चाहते आप निश्चित formBuilder का उपयोग करें और परित्याग एनजी मॉडल चाहिए पाने के लिए है
कोणीय विश्वविद्यालय

2
@tambler, आप NgForm का उपयोग करके एक संदर्भ प्राप्त कर सकते हैं @ViewChild()। देखिये मेरा अपडेटेड जवाब।
मार्क राजकॉक

1
आपको नष्ट करने के लिए सदस्यता समाप्त करने की आवश्यकता नहीं है?
Bazinga

1
@galvan मुझे नहीं लगता कि कोई रिसाव हो सकता है। प्रपत्र घटक का हिस्सा है और इसे इसके सभी क्षेत्रों और घटना श्रोताओं के साथ नष्ट करने पर ठीक से निपटाया जाएगा।
dfsq

107

यदि आप उपयोग कर रहे हैं FormBuilder, तो @ dfsq का उत्तर देखें।

यदि आप उपयोग नहीं कर FormBuilderरहे हैं, तो परिवर्तनों को अधिसूचित करने के दो तरीके हैं।

विधि 1

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

<input type="text" class="form-control" required [ngModel]="model.first_name"
         (ngModelChange)="doSomething($event)">

फिर अपने घटक में:

doSomething(newValue) {
  model.first_name = newValue;
  console.log(newValue)
}

फार्म पेज ngModel बारे में अतिरिक्त जानकारी है कि यहां प्रासंगिक है:

ngModelChangeएक नहीं है<input> तत्व घटना। यह वास्तव में NgModelनिर्देश की एक घटना संपत्ति है । जब एंगुलर फॉर्म में एक बाध्यकारी लक्ष्य देखता है [(x)], तो यह xनिर्देश देता है कि xइनपुट संपत्ति और xChangeआउटपुट संपत्ति है।

अन्य विषमता, टेम्पलेट अभिव्यक्ति है model.name = $event। हम $eventएक DOM इवेंट से आने वाली किसी वस्तु को देखने के लिए अभ्यस्त हैं। NgModelChange गुण DOM इवेंट का उत्पादन नहीं करता है; यह एक कोणीय EventEmitterगुण है जो आग लगने पर इनपुट बॉक्स मान लौटाता है।

हम लगभग हमेशा पसंद करते हैं [(ngModel)]। हम बंधन को विभाजित कर सकते हैं यदि हमें घटना से निपटने में कुछ विशेष करना था जैसे कि बहस या मुख्य स्ट्रोक को कुचलना।

आपके मामले में, मुझे लगता है कि आप कुछ विशेष करना चाहते हैं।

विधि 2

स्थानीय टेम्प्लेट चर को परिभाषित करें और इसे सेट करें ngForm
इनपुट तत्वों पर ngControl का उपयोग करें।
फॉर्म का NgForm निर्देश का एक संदर्भ पाएं @ViewChild का उपयोग करते हुए, फिर इसके लिए NgForm के ControlGill की सदस्यता लें:

<form #myForm="ngForm" (ngSubmit)="onSubmit()">
  ....
  <input type="text" ngControl="firstName" class="form-control" 
   required [(ngModel)]="model.first_name">
  ...
  <input type="text" ngControl="lastName" class="form-control" 
   required [(ngModel)]="model.last_name">

class MyForm {
  @ViewChild('myForm') form;
  ...
  ngAfterViewInit() {
    console.log(this.form)
    this.form.control.valueChanges
      .subscribe(values => this.doSomething(values));
  }
  doSomething(values) {
    console.log(values);
  }
}

plunker

विधि 2 के बारे में अधिक जानकारी के लिए, सावकीन का वीडियो देखें

यह भी देखें कि आप valueChangesअवलोकन के साथ क्या कर सकते हैं, इस पर अधिक जानकारी के लिए @ थिएरी का जवाब (जैसे कि प्रोसेसिंग में बदलाव से पहले थोड़ा सा इंतजार / इंतजार करना)।


61

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

वेधशालाएं न केवल subscribeविधि का उपयोग करने की अनुमति देती हैं ( thenकोणीय 1 में वादों की विधि के समान कुछ )। रूपों में अद्यतन डेटा के लिए कुछ प्रसंस्करण श्रृंखलाओं को लागू करने के लिए आवश्यक होने पर आप आगे जा सकते हैं।

मेरा मतलब है कि आप इस स्तर पर debounceTimeविधि के साथ बहस का समय निर्दिष्ट कर सकते हैं । यह आपको परिवर्तन को संभालने से पहले कई समय तक इंतजार करने और कई इनपुटों को सही ढंग से संभालने की अनुमति देता है:

this.form.valueChanges
    .debounceTime(500)
    .subscribe(data => console.log('form changes', data));

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

this.textValue.valueChanges
    .debounceTime(500)
    .switchMap(data => this.httpService.getListValues(data))
    .subscribe(data => console.log('new list values', data));

आप अपने घटक की संपत्ति में सीधे लौटे हुए अवलोकन को जोड़कर भी आगे बढ़ते हैं:

this.list = this.textValue.valueChanges
    .debounceTime(500)
    .switchMap(data => this.httpService.getListValues(data))
    .subscribe(data => console.log('new list values', data));

और asyncपाइप का उपयोग करके इसे प्रदर्शित करें :

<ul>
  <li *ngFor="#elt of (list | async)">{{elt.name}}</li>
</ul>

केवल यह कहने के लिए कि आपको Angular2 (बहुत अधिक शक्तिशाली तरीका ;-)) में रूपों को अलग तरीके से संभालने की आवश्यकता है।

आशा है कि यह आपकी मदद करता है, थियरी


प्रॉपर्टी 'valueChanges' टाइप 'स्ट्रिंग' पर मौजूद नहीं है
टूलकिट

मैं टीएस फ़ाइल में अटक गया हूं, जहां चेक फॉर्म परिवर्तन विधि रखी जानी चाहिए? यदि हम इसे ngAfterViewInit () {} में संग्रहीत करते हैं, तो ऐसा लगता है कि यह .form.valueChanges हमेशा कॉल करता है यदि हमें प्रपत्रों में अपडेट किए गए डेटा के लिए कुछ प्रसंस्करण श्रृंखलाओं को लागू करने की आवश्यकता है।
ताई गुयेन

1

मार्क के सुझावों पर विस्तार ...

विधि 3

मॉडल पर "गहरी" परिवर्तन का पता लगाने को लागू करें। फायदे मुख्य रूप से घटक में उपयोगकर्ता इंटरफ़ेस पहलुओं को शामिल करने से बचते हैं; यह मॉडल में किए गए प्रोग्राम परिवर्तन को भी पकड़ता है। उस ने कहा, थिएरी द्वारा सुझाई गई बहस के रूप में ऐसी चीजों को लागू करने के लिए अतिरिक्त काम की आवश्यकता होगी, और यह आपके स्वयं के प्रोग्राम परिवर्तन को भी पकड़ लेगा , इसलिए सावधानी के साथ उपयोग करें।

export class App implements DoCheck {
  person = { first: "Sally", last: "Jones" };
  oldPerson = { ...this.person }; // ES6 shallow clone. Use lodash or something for deep cloning

  ngDoCheck() {
    // Simple shallow property comparison - use fancy recursive deep comparison for more complex needs
    for (let prop in this.person) {
      if (this.oldPerson[prop] !==  this.person[prop]) {
        console.log(`person.${prop} changed: ${this.person[prop]}`);
        this.oldPerson[prop] = this.person[prop];
      }
    }
  }

प्लंकर में प्रयास करें


1

कोणीय 5+संस्करण के लिए। संस्करण डालने से कोणीय में बहुत बदलाव आता है।

ngOnInit() {

 this.myForm = formBuilder.group({
      firstName: 'Thomas',
      lastName: 'Mann'
    })
this.formControlValueChanged() // Note if you are doing an edit/fetching data from an observer this must be called only after your form is properly initialized otherwise you will get error.
}

formControlValueChanged(): void {       
        this.myForm.valueChanges.subscribe(value => {
            console.log('value changed', value)
        })
}

0

मैंने (ngModelChange) पद्धति का उपयोग करने के बारे में सोचा, फिर फॉर्मब्यूलर विधि के बारे में सोचा, और अंत में विधि 3 के बदलाव पर समझौता किया। यह टेम्पलेट को अतिरिक्त विशेषताओं के साथ सजाने से बचाता है और स्वचालित रूप से मॉडल में बदलाव करता है - कुछ भूलने की संभावना को कम करता है। विधि 1 या 2 के साथ।

सरल विधि 3 थोड़ा सा ...

oldPerson = JSON.parse(JSON.stringify(this.person));

ngDoCheck(): void {
    if (JSON.stringify(this.person) !== JSON.stringify(this.oldPerson)) {
        this.doSomething();
        this.oldPerson = JSON.parse(JSON.stringify(this.person));
    }
}

आप बहस को अनुकरण करने के लिए मिलीसेकंड की एक्स संख्या के बाद केवल कॉल करने के लिए एक टाइमआउट जोड़ सकते हैं।

oldPerson = JSON.parse(JSON.stringify(this.person));

ngDoCheck(): void {
    if (JSON.stringify(this.person) !== JSON.stringify(this.oldPerson)) {
        if (timeOut) clearTimeout(timeOut);
        let timeOut = setTimeout(this.doSomething(), 2000);
        this.oldPerson = JSON.parse(JSON.stringify(this.person));
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.