NgFor Angular2 में पाइप के साथ डेटा अपडेट नहीं करता है


113

इस परिदृश्य में, मैं छात्रों की सूची (सरणी) को इस दृश्य के साथ प्रदर्शित कर रहा हूं ngFor:

<li *ngFor="#student of students">{{student.name}}</li>

जब भी मैं सूची में अन्य छात्र को जोड़ता हूं तो यह अद्भुत है।

हालांकि, जब मैं इसे एक देने pipeके लिए filterछात्र के नाम से,

<li *ngFor="#student of students | sortByName:queryElem.value ">{{student.name}}</li>

यह सूची को तब तक अपडेट नहीं करता है जब तक कि मैं फ़िल्टरिंग छात्र के नाम फ़ील्ड में कुछ टाइप नहीं करता।

यहाँ plnkr का लिंक दिया गया है

Hello_world.html

<h1>Students:</h1>
<label for="newStudentName"></label>
<input type="text" name="newStudentName" placeholder="newStudentName" #newStudentElem>
<button (click)="addNewStudent(newStudentElem.value)">Add New Student</button>
<br>
<input type="text" placeholder="Search" #queryElem (keyup)="0">
<ul>
    <li *ngFor="#student of students | sortByName:queryElem.value ">{{student.name}}</li>
</ul>

sort_by_name_pipe.ts

import {Pipe} from 'angular2/core';

@Pipe({
    name: 'sortByName'
})
export class SortByNamePipe {

    transform(value, [queryString]) {
        // console.log(value, queryString);
        return value.filter((student) => new RegExp(queryString).test(student.name))
        // return value;
    }
}


14
pure:falseअपने पाइप में, और changeDetection: ChangeDetectionStrategy.OnPushअपने घटक में जोड़ें ।
एरिक मार्टिनेज

2
धन्यवाद @EricMartinez यह काम करता हैं। लेकिन क्या आप थोड़ा समझा सकते हैं?
चू बेटा

2
इसके अलावा, मैं .test()आपके फ़िल्टर फ़ंक्शन का उपयोग नहीं करने का सुझाव दूंगा । इसका कारण यह है, अगर उपयोगकर्ता एक स्ट्रिंग देता है जिसमें विशेष अर्थ अक्षर शामिल होते हैं जैसे: *या +आदि आपका कोड टूट जाएगा। मुझे लगता है कि आपको .includes()कस्टम फ़ंक्शन के साथ क्वेरी स्ट्रिंग का उपयोग या बचना चाहिए ।
इग्गी डिस

6
pure:falseअपने पाइप को स्टेटफुल जोड़ना और बनाना समस्या को ठीक करेगा। ChangeDetectionStrategy को संशोधित करना आवश्यक नहीं है।
पिक्सेलबिट्स

2
इसे पढ़ने वाले किसी भी व्यक्ति के लिए, कोणीय पाइप के लिए प्रलेखन बहुत बेहतर हो गया है और यहां चर्चा की गई कई चीजों पर चला जाता है। इसकी जांच - पड़ताल करें।
0xcaff

जवाबों:


153

समस्या और संभावित समाधानों को पूरी तरह से समझने के लिए, हमें कोणीय परिवर्तन का पता लगाने की आवश्यकता है - पाइप और घटकों के लिए।

पाइप परिवर्तन का पता लगाने

स्टेटलेस / प्योर पाइप्स

डिफ़ॉल्ट रूप से, पाइप स्टेटलेस / प्योर हैं। स्टेटलेस / प्योर पाइप केवल इनपुट डेटा को आउटपुट डेटा में बदलते हैं। उन्हें कुछ भी याद नहीं है, इसलिए उनके पास कोई गुण नहीं है - बस एक transform()विधि। इसलिए कोणीय, स्टेटलेस / शुद्ध पाइप के उपचार का अनुकूलन कर सकता है: यदि उनके इनपुट नहीं बदलते हैं, तो पाइप को परिवर्तन का पता लगाने के चक्र के दौरान निष्पादित करने की आवश्यकता नहीं है। जैसे पाइप के लिए {{power | exponentialStrength: factor}}, powerऔर factorइनपुट हैं।

इस प्रश्न के लिए "#student of students | sortByName:queryElem.value", studentsऔर queryElem.valueइनपुट हैं, और पाइप sortByNameस्टेटलेस / प्योर है। studentsएक सरणी (संदर्भ) है।

  • जब एक छात्र जोड़ा जाता है, तो सरणी संदर्भ नहीं बदलता है - studentsनहीं बदलता है - इसलिए स्टेटलेस / शुद्ध पाइप निष्पादित नहीं किया जाता है।
  • जब कुछ को फ़िल्टर इनपुट में टाइप किया जाता है, queryElem.valueतो परिवर्तन होता है, इसलिए स्टेटलेस / शुद्ध पाइप निष्पादित होता है।

सरणी समस्या को ठीक करने का एक तरीका यह है कि किसी छात्र के जुड़ने पर हर बार सरणी संदर्भ को परिवर्तित किया जाए - यानी, जब छात्र जोड़ा जाता है, तो हर बार एक नया सरणी बनाएं। हम इसके साथ कर सकते हैं concat():

this.students = this.students.concat([{name: studentName}]);

हालांकि यह काम करता है, हमारी addNewStudent()विधि को एक निश्चित तरीके से लागू नहीं किया जाना चाहिए क्योंकि हम एक पाइप का उपयोग कर रहे हैं। हम push()अपने ऐरे से जोड़ना चाहते हैं ।

स्टेटफुल पाइप्स

स्टेटफुल पाइप में स्थिति होती है - उनके पास सामान्य रूप से गुण होते हैं, न कि केवल एक transform()विधि। यदि उनके इनपुट नहीं बदले हैं तो भी उनका मूल्यांकन करने की आवश्यकता हो सकती है। जब हम यह निर्दिष्ट करते हैं कि एक पाइप स्टेटफुल / नॉन-प्योर है - pure: false- तब जब भी कोणीय की परिवर्तन पहचान प्रणाली परिवर्तनों के लिए एक घटक की जाँच करती है और वह घटक एक स्टेटफुल पाइप का उपयोग करता है, तो यह पाइप के आउटपुट की जाँच करेगा, कि उसका इनपुट बदला है या नहीं।

यह लगता है कि हम क्या चाहते हैं, भले ही यह कम कुशल है, क्योंकि हम चाहते हैं कि पाइप निष्पादित करें भले ही studentsसंदर्भ बदल नहीं गया हो। यदि हम बस पाइप को स्टेटफुल बनाते हैं, तो हमें एक त्रुटि मिलती है:

EXCEPTION: Expression 'students | sortByName:queryElem.value  in HelloWorld@7:6' 
has changed after it was checked. Previous value: '[object Object],[object Object]'. 
Current value: '[object Object],[object Object]' in [students | sortByName:queryElem.value

@ ड्रूमोर के उत्तर के अनुसार , "यह त्रुटि केवल देव मोड में होती है (जो कि बीटा -० के रूप में डिफ़ॉल्ट रूप से सक्षम होती है)। यदि आप enableProdMode()ऐप को बूटस्ट्रैप करते समय कॉल करते हैं, तो त्रुटि नहीं मिलेगी।" के लिये दस्तावेजApplicationRef.tick() राज्य:

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

हमारे परिदृश्य में मेरा मानना ​​है कि त्रुटि फर्जी / भ्रामक है। हमारे पास एक स्टेटफुल पाइप है, और आउटपुट को हर बार इसे बदलने के लिए कहा जा सकता है - इसके दुष्प्रभाव हो सकते हैं और यह ठीक है। पाइप के बाद NgFor का मूल्यांकन किया जाता है, इसलिए इसे ठीक काम करना चाहिए।

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

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

घटक परिवर्तन का पता लगाने

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

यदि हम जानते हैं कि एक घटक केवल उसके इनपुट गुणों (और टेम्पलेट ईवेंट्स) पर निर्भर करता है, और यह कि इनपुट गुण अपरिवर्तनीय हैं, तो हम बहुत अधिक कुशल onPushपरिवर्तन का पता लगाने की रणनीति का उपयोग कर सकते हैं । इस रणनीति के साथ, हर ब्राउज़र घटना पर जाँच करने के बजाय, एक घटक की जाँच तभी की जाती है जब इनपुट बदलते हैं और जब टेम्पलेट इवेंट ट्रिगर होते हैं। और, जाहिर है, हम Expression ... has changed after it was checkedइस सेटिंग के साथ उस त्रुटि को प्राप्त नहीं करते हैं । ऐसा तब होता है क्योंकि एक onPushघटक को फिर से जांच नहीं किया जाता है जब तक कि इसे "चिह्नित" ( ChangeDetectorRef.markForCheck()) फिर से नहीं किया जाता है। इसलिए टेम्पलेट बाइंडिंग और स्टेटफुल पाइप आउटपुट केवल एक बार निष्पादित / मूल्यांकन किए जाते हैं। स्टेटलेस / प्योर पाइप अभी भी निष्पादित नहीं किए जाते हैं जब तक कि उनके इनपुट नहीं बदलते। इसलिए हमें अभी भी यहां एक स्टेटफुल पाइप की जरूरत है।

यह समाधान है @EricMartinez ने सुझाव दिया: onPushपरिवर्तन का पता लगाने के साथ स्टेटफुल पाइप । इस समाधान के लिए @ caffinatedmonkey का उत्तर देखें।

ध्यान दें कि इस समाधान के साथ transform()विधि को हर बार एक ही सरणी वापस करने की आवश्यकता नहीं है। मुझे लगता है कि थोड़ा अजीब है: कोई राज्य नहीं के साथ एक राज्य पाइप। इसके बारे में कुछ और सोचना ... स्टेटफुल पाइप को शायद हमेशा एक ही सरणी वापस करना चाहिए। अन्यथा इसका उपयोग केवल onPushदेव विधा में घटकों के साथ किया जा सकता है।


इतना सब होने के बाद, मुझे लगता है कि मुझे @ एरिक और @ पिक्सेलबिट्स के उत्तरों का संयोजन पसंद है: स्टेटफुल पाइप जो उसी सरणी संदर्भ को वापस करता है, onPushपरिवर्तन का पता लगाने के साथ अगर घटक इसे अनुमति देता है। चूंकि स्टेटफुल पाइप एक ही सरणी संदर्भ देता है, इसलिए पाइप को अभी भी उन घटकों के साथ उपयोग किया जा सकता है जो कि कॉन्फ़िगर नहीं हैं onPush

Plunker

यह संभवतः एक कोणीय 2 मुहावरा बन जाएगा: यदि एक सरणी एक पाइप खिला रही है, और सरणी बदल सकती है (सरणी में आइटम जो कि नहीं है, तो सरणी संदर्भ नहीं), हमें एक स्टेटफुल पाइप का उपयोग करने की आवश्यकता है।


समस्या की आपकी विस्तृत व्याख्या के लिए धन्यवाद। हालांकि यह अजीब है कि समानता की तुलना के बजाय सरणियों के परिवर्तन का पता लगाने को पहचान के रूप में लागू किया जाता है। क्या ऑब्जर्वबल के साथ इसे हल करना संभव होगा?
मार्टिन नाओक

@MartinNowak, यदि आप पूछ रहे हैं कि क्या सरणी एक अवलोकन योग्य थी, और पाइप स्टेटलेस थे ... मुझे नहीं पता, मैंने कोशिश नहीं की है।
मार्क राजकॉक

एक अन्य समाधान एक शुद्ध पाइप होगा जहां आउटपुट ऐरे इवेंट श्रोताओं के साथ इनपुट ऐरे में बदलाव पर नज़र रख रहा है।
१४:४० पर तुपरटुनट

मैंने अभी-अभी आपके प्लंकर को कांटा है, और यह मेरे लिए काम करता है बिना onPushपरिवर्तन का पता लगाए plnkr.co/edit/gRl0Pt9oBO6038kCXZPk?p=preview
Dan

27

के रूप में एरिक मार्टिनेज टिप्पणी में कहा, जोड़ने pure: falseअपने को Pipeडेकोरेटर और changeDetection: ChangeDetectionStrategy.OnPushअपने को Componentडेकोरेटर आपकी समस्या का समाधान होगा। यहाँ एक काम कर रहा है। बदलने के लिए ChangeDetectionStrategy.Always, भी काम करता है। यहाँ पर क्यों।

पाइपों पर कोणीय 2 गाइड के अनुसार :

डिफ़ॉल्ट रूप से पाइप स्टेटलेस होते हैं। हमें डेकोरेटर की pureसंपत्ति को निर्धारित करके एक पाइप को स्टेटफुल घोषित करना चाहिए । यह सेटिंग प्रत्येक चक्र में इस इनपुट के उत्पादन की जांच करने के लिए कोणीय के परिवर्तन का पता लगाने की प्रणाली को बताती है, चाहे उसका इनपुट बदल गया हो या नहीं।@Pipefalse

के रूप में ChangeDetectionStrategy, डिफ़ॉल्ट रूप से, सभी बाइंडिंग हर एक चक्र की जाँच की जाती है। जब एक pure: falseपाइप जोड़ा जाता है, मेरा मानना है कि परिवर्तन पहचान पद्धति से किए गए परिवर्तन CheckAlwaysके लिए CheckOnceप्रदर्शन के कारणों के लिए। साथ OnPush, घटक के लिए बाइंडिंग केवल जाँच कर रहे हैं जब एक इनपुट गुण परिवर्तन या एक घटना शुरू हो रहा है जब। परिवर्तन डिटेक्टरों के बारे में अधिक जानकारी के लिए, एक महत्वपूर्ण हिस्सा angular2, निम्नलिखित लिंक देखें:


"जब एक pure: falseपाइप जोड़ा जाता है, तो मेरा मानना ​​है कि चेक डिटेक्शंस से चेक डिटेक्शंस में बदलाव का पता लगाने का तरीका बदल जाता है" - जो डॉक्स से आपके द्वारा उद्धृत किए जाने से सहमत नहीं है। मेरी समझ इस प्रकार है: एक सांख्यिकीय पाइप के इनपुट को हर चक्र में डिफ़ॉल्ट रूप से जांचा जाता है। यदि कोई परिवर्तन होता है, तो पाइप की transform()विधि को आउटपुट (पुनः) कहा जाता है। एक स्टेटफुल पाइप की transform()विधि को हर चक्र कहा जाता है, और इसके आउटपुट को परिवर्तनों के लिए जांचा जाता है। यह भी देखें stackoverflow.com/a/34477111/215945
मार्क राजकोक

@MarkRajcok, उफ़, आप सही कह रहे हैं, लेकिन अगर ऐसा है, तो परिवर्तन का पता लगाने की रणनीति काम क्यों कर रही है?
0xcaff 18

1
बड़ा सवाल है। ऐसा लगता है कि जब परिवर्तन का पता लगाने की रणनीति को बदल दिया जाता है OnPush(यानी, घटक को "अपरिवर्तनीय" के रूप में चिह्नित किया जाता है), तो स्टेटफुल पाइप आउटपुट को "स्थिर" नहीं करना पड़ता है - अर्थात, ऐसा लगता है कि transform()विधि केवल एक बार (शायद सभी के लिए) चलाई गई है घटक के लिए परिवर्तन का पता लगाना केवल एक बार चलाया जाता है)। इसके विपरीत, @ पिक्सेलबिट्स के उत्तर में, जहां transform()विधि को कई बार कहा जाता है, और इसे स्थिर करना होगा (पिक्सेलबिट्स के अन्य उत्तर के अनुसार ), इसलिए उसी सरणी संदर्भ का उपयोग करने की आवश्यकता है।
मार्क राजकॉक

@MarkRajcok अगर आप जो कहते हैं, वह दक्षता के लिहाज से सही है, तो यह शायद बेहतर तरीका है, इस विशेष उपयोग के मामले में क्योंकि transformकेवल तब ही कहा जाता है जब आउटपुट को स्थिर करने तक कई बार नए डेटा को कई बार धक्का दिया जाता है, है ना?
0xcaff

1
शायद, मेरा लंबा-चौड़ा जवाब देखिए। मेरी इच्छा है कि कोणीय 2 में परिवर्तन का पता लगाने के बारे में और अधिक दस्तावेज थे
मार्क राजकॉक

22

डेमो प्लंकर

आपको ChangeDetectionStrategy को बदलने की आवश्यकता नहीं है। एक स्टेटफुल पाइप को लागू करना सब कुछ काम करने के लिए पर्याप्त है।

यह एक स्टेटफुल पाइप है (कोई अन्य परिवर्तन नहीं किए गए थे):

@Pipe({
  name: 'sortByName',
  pure: false
})
export class SortByNamePipe {
  tmp = [];
  transform (value, [queryString]) {
    this.tmp.length = 0;
    // console.log(value, queryString);
    var arr = value.filter((student)=>new RegExp(queryString).test(student.name));
    for (var i =0; i < arr.length; ++i) {
        this.tmp.push(arr[i]);
     }

    return this.tmp;
  }
}

[: मैं onPush को फेरबदल changeDectection बिना यह त्रुटि आई plnkr.co/edit/j1VUdgJxYr6yx8WgzCId?p=preview](Plnkr) Expression 'students | sortByName:queryElem.value in HelloWorld@7:6' has changed after it was checked. Previous value: '[object Object],[object Object],[object Object]'. Current value: '[object Object],[object Object],[object Object]' in [students | sortByName:queryElem.value in HelloWorld@7:6]
चू बेटा

1
क्या आप उदाहरण दे सकते हैं कि आपको SortByNamePipe में एक स्थानीय चर के मानों को संग्रहीत करने की आवश्यकता क्यों है और फिर इसे फ़ंक्शन @pixbitbits में परिवर्तित करें? मैंने यह भी देखा कि परिवर्तन के माध्यम से दो बार परिवर्तन समारोह के माध्यम से कोणीय चक्र। इसके अलावा 4 बार और इसके बिना
चू बेटा

@ChuSon, आप शायद पिछले संस्करण के लॉग देख रहे हैं। मानों की एक सरणी वापस करने के बजाय, हम मानों की एक सरणी के लिए एक संदर्भ लौटा रहे हैं , जिसे बदला जा सकता है, मुझे विश्वास है। Pixelbits, आपका जवाब अधिक समझ में आता है।
0xcaff

अन्य पाठकों के लाभ के लिए, चिउन्स ने त्रुटियों के बारे में टिप्पणी में ऊपर उल्लेख किया है, और एक स्थानीय चर का उपयोग करने की आवश्यकता है, एक और प्रश्न बनाया गया था , और पिक्सेलबिट्स द्वारा उत्तर दिया गया था।
मार्क राजकोक

19

से कोणीय प्रलेखन

शुद्ध और अशुद्ध पाइप

पाइप की दो श्रेणियां हैं: शुद्ध और अशुद्ध। डिफ़ॉल्ट रूप से पाइप शुद्ध हैं। आपके द्वारा अब तक देखा गया हर पाइप शुद्ध रहा है। आप अपने शुद्ध ध्वज को असत्य पर स्थापित करके एक पाइप अशुद्ध बनाते हैं। आप इस तरह से FlyHeroesPipe अशुद्ध बना सकते हैं:

@Pipe({ name: 'flyingHeroesImpure', pure: false })

ऐसा करने से पहले, शुद्ध और अशुद्ध के बीच के अंतर को समझें, जो एक शुद्ध पाइप से शुरू होता है।

शुद्ध पाइप्स कोणीय एक शुद्ध पाइप को केवल तब निष्पादित करता है जब यह इनपुट मूल्य में शुद्ध परिवर्तन का पता लगाता है। एक शुद्ध परिवर्तन या तो एक आदिम इनपुट मूल्य (स्ट्रिंग, संख्या, बूलियन, प्रतीक) या परिवर्तित वस्तु संदर्भ (दिनांक, सरणी, कार्य, वस्तु) के लिए एक परिवर्तन है।

कोणीय (समग्र) वस्तुओं के भीतर परिवर्तन की अनदेखी करता है। यदि आप इनपुट महीना बदलते हैं, तो इनपुट सरणी में जोड़ें, या इनपुट ऑब्जेक्ट प्रॉपर्टी को अपडेट करें तो यह शुद्ध पाइप नहीं कहलाएगा।

यह प्रतिबंधात्मक लग सकता है लेकिन यह भी तेज है। ऑब्जेक्ट रेफरेंस चेक तेज़ है-मतभेदों के लिए एक गहरी जाँच की तुलना में बहुत तेज़ है - इसलिए कोणीय जल्दी से यह निर्धारित कर सकता है कि यह पाइप निष्पादन और व्यू अपडेट दोनों को छोड़ सकता है या नहीं।

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


उत्तर सही है, लेकिन इसे पोस्ट करते समय थोड़ा और प्रयास अच्छा होगा
स्टीफन

2

शुद्ध करने के बजाय: असत्य। आप इस घटक में मूल्य को गहराई से कॉपी और प्रतिस्थापित कर सकते हैं। सामग्री = Object.assign ([], NEW_ARRAY); जहाँ NEW_ARRAY संशोधित सरणी है।

यह कोणीय 6 के लिए काम करता है और अन्य कोणीय संस्करणों के लिए भी काम करना चाहिए।


0

एक वर्कअराउंड: इस पाइप का उपयोग करके कंस्ट्रक्टर और कॉल ट्रांसफ़ॉर्म विधि में मैन्युअल रूप से आयात करें

constructor(
private searchFilter : TableFilterPipe) { }

onChange() {
   this.data = this.searchFilter.transform(this.sourceData, this.searchText)}

वास्तव में आपको एक पाइप की भी आवश्यकता नहीं है


0

अतिरिक्त पैरामीटर को पाइप में जोड़ें, और सरणी परिवर्तन के ठीक बाद इसे बदलें, और यहां तक ​​कि शुद्ध पाइप के साथ, सूची ताज़ा हो जाएगी

आइये जाने आइटम के आइटम | पाइप: param


0

इस उपयोग के मामले में मैंने डेटा फ़िल्टरिंग के लिए ts फ़ाइल में अपने पाइप का उपयोग किया। शुद्ध पाइप का उपयोग करने की तुलना में यह प्रदर्शन के लिए बहुत बेहतर है। इस तरह से ts में उपयोग करें:

import { YourPipeComponentName } from 'YourPipeComponentPath';

class YourService {

  constructor(private pipe: YourPipeComponentName) {}

  YourFunction(value) {
    this.pipe.transform(value, 'pipeFilter');
  }
}

0

अशुद्ध पाइप बनाने के लिए प्रदर्शन पर महंगा है। इसलिए अशुद्ध पाइप न बनाएं, बल्कि डेटा में बदलाव के द्वारा डेटा वेरिएबल के संदर्भ को बदलें जब डेटा में बदलाव होता है और मूल डेटा वेरिएबल में कॉपी के संदर्भ को पुन: असाइन करता है।

            emp=[];
            empid:number;
            name:string;
            city:string;
            salary:number;
            gender:string;
            dob:string;
            experience:number;

            add(){
              const temp=[...this.emps];
              const e={empid:this.empid,name:this.name,gender:this.gender,city:this.city,salary:this.salary,dob:this.dob,experience:this.experience};
              temp.push(e); 
              this.emps =temp;
              //this.reset();
            } 
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.