2017-04-20 27 views
8

मेरे कोणीय (4 + टाइपस्क्रिप्ट) प्रोजेक्ट के अंदर मैंने पहले ही तैयार घटक का उपयोग किया था (यह वास्तव में कोई फर्क नहीं पड़ता कि नियंत्रणवैल्यूएक्सर को विस्तारित करने के तरीके के बाद से यह वास्तव में कोई फर्क नहीं पड़ता है, लेकिन यदि यह मायने रखता है ng2-select) जो मैं बेहतर यूएक्स और अच्छे दिखने के कारण चाहता था। उस पर, मेरे प्रपत्र घटक है जो प्रतिक्रियाशील रूपों मैंने देखा उपयोग कर रहा है के लिए यह सहित के बाद प्रस्तुत मैं वापस (प्रपत्र नियंत्रण के लिए) वस्तु वर्ग SelectItem जो चयनित आइटम (रों) का प्रबंधन करने के लिए तैयार घटक के अंदर प्रयोग किया जाता है, के आधार पर मिलता है - इस तरह:एंगुलर 4 कंट्रोल वैल्यूएक्फरर मूल्य सबमिट और वैल्यू चेंज इवेंट्स

// console.log(this.myForm.values) 
Object { 
    txtInput: 'value', 
    // ... 
    preparedComponent: SelectItem { // <-- 
     id: '1', 
     text: 'Chosen item' 
    } 
} 

के बाद से घटक मूल रूप से सिर्फ मानक का चयन करें नियंत्रण, मैं उम्मीद कर रहा था कि मैं वापस स्ट्रिंग के रूप में गठन चुने गए आइटम का एक आईडी मिल जाएगा के लिए एक स्थानापन्न है - इस तरह:

// console.log(this.myForm.values) 
Object { 
    txtInput: 'value', 
    // ... 
    preparedComponent: '1' // <-- 
} 

मैं के बाद सीखा क्या वास्तव में ControlValueAccessor है और यह कैसे काम करता है, मैं आइटम परिवर्तन पर कहने के लिए क्या पीठ पर प्रस्तुत आता है (या बेहतर का तरीका ही बदल - +०१२३२५५६६५५) किसी आइटम की आईडी पर। कुछ समय तक समस्या हल हो गई जब तक कि मैंने रिक्त मानों (उदाहरण जोड़ने पर) के बजाय नियंत्रण बनाने के लिए पूर्वनिर्धारित मान (संपादन उदाहरण पर) सेट करना प्रारंभ किया। मैं पता लगा है कि इस बार writeValue मान निर्दिष्ट है यह पूर्वनिर्धारित मूल्य के रूप में यह करने के लिए भेज दिया जाता है, उसके आधार पर नियंत्रण के रूप में। मामले कि मैं के रूप में पूर्वनिर्धारित मूल्य भेजा में तो ...

Object { 
    id: '1', 
    text: 'Chosen item' 
} 

... यह भी था बस ऊपर पहले कोड उदाहरण के रूप में प्रस्तुत पर वस्तु में मूल्य। मैं writeValue कहा जाता है के बाद onChange अधिकार के साथ नियंत्रित करने के लिए सही मान देना इस बात के लिए एक समाधान बनाया है। यह बात करने का वास्तव में अनुचित तरीका था, लेकिन मुझे लगता है कि के अलावा और कुछ पता लगा नहीं कर सकता:

public writeValue(val: any): void { 
    this.selectedItems = val; // val is for example Object { id: '1', text: 'Chosen item' } 

    setTimeout(() => { 
     this.onChange(val.id); // just an example of emitted value, there should be some checks val is object and id exists in real code 
    }, 0); 
} 

और वह भी जहाँ तक काम किया, जैसा कि मैंने नियंत्रण के valueChanges फार्म की सदस्यता के साथ शुरू नहीं किया। समस्या तैयार घटक करने के लिए पूर्वनिर्धारित मूल्य के प्रत्येक बताए साथ, वहाँ भी बाद इस्तेमाल सबमिट करते हैं, वापस ग्राहकों के लिए भी जब { emitEvent: false } का उपयोग कर मूल्य का एक फेंकना है।

तो यह वही चीजें हैं जिन्हें मैं किसी भी तरह से तैयार घटक के साथ संभालना चाहता हूं, क्योंकि मैं सबमिट पर नियंत्रण से सही मूल्य प्राप्त करना चाहता हूं और मैं ग्राहकों को तब तक बदलना नहीं चाहता जब तक कि मूल्य वास्तव में नहीं बदला जाता, न केवल पूर्वनिर्धारित मान के रूप में प्रतिस्थापित किया गया। इस बात को संभालने का कोई विचार सराहना की जाएगी।

+0

मैं थोड़े इस सटीक प्रक्रिया के माध्यम से चला गया। मुझे बिल्कुल यकीन नहीं है कि मैं आपकी सटीक समस्या को समझता हूं। – Amit

+0

समस्या मुख्य रूप से 'writeValue' के अंदर 'ऑन चेंज' के साथ है। सबसे पहले, क्योंकि 'setTimeout' जो वास्तव में अंत में मैं एक समाधान के रूप करते हैं और होता है दूसरी बात, क्योंकि यह परिवर्तन घटना जब पूर्वनिर्धारित मूल्य के साथ प्रारंभ उत्सर्जन करता है। आदर्श रूप से इनपुट और आउटपुट मान अलग किए जाएंगे - इनपुट ऑब्जेक्ट स्वीकार करेगा और आउटपुट चयनित ऑब्जेक्ट की आईडी वापस करेगा। 'नियंत्रण से setValue' पर' या फार्म 'reset' कोणीय घटना उत्सर्जन नहीं: क्योंकि यह नहीं है एक (डिफ़ॉल्ट व्यवहार के रूप उम्मीद करेंगे क्या' {झूठी emitEvent} के मामले में इसलिए, परिवर्तन मूल्य init पर उत्सर्जन के लिए कोई जरूरत नहीं है जब मूल्य chaning)। – user1257255

+1

मैं बहुत विश्वास है इस एक मुद्दे के अधिक है क्योंकि आप कर रहे है कर रहा हूँ (और मैं भी है) "फाइटिंग" NG2 का चयन करें (जो मुश्किल से btw बनाए रखा है) – Amit

उत्तर

2

मुझे यकीन है कि मैं सही ढंग से इस समझा नहीं कर रहा हूँ, लेकिन मैं इसे एक शॉट देने के लिए करना चाहते हैं।

आप घटक के इनपुट निम्नलिखित प्रकार का होना चाहते हैं:

{ 
    id: string, 
    text: string 
} 

लेकिन आप घटक के उत्पादन चयनित आइटम का सिर्फ स्ट्रिंग आईडी होना चाहता हूँ।

मैं का तर्क था कि इस डाटा प्रवाह थोड़ा अजीब है। प्रारंभ के दौरान, preparedComponent एक object है, लेकिन जब एक आइटम का चयन किया गया है आप इसे एक string में बदलने के लिए चाहते हैं। प्रकार की सुरक्षा के मुद्दे के अलावा, यह केवल अनजान लगता है।

तुलना के लिए, ngModel और एक पाठ इनपुट के साथ ऐसा करने की कल्पना:

<input type="text" [(ngModel)]="preparedComponent" /> 

आप एक वस्तु में पारित करने के लिए उम्मीद करेंगे, और एक स्ट्रिंग जब उपयोगकर्ता वापस मिल सकता है? शायद ऩही।


लेकिन मान लें कि यह किसी कारण से इस तरह होना चाहिए करते हैं। आपने ng2-select के ControlValueAccessor के कार्यान्वयन को संशोधित करके या ControlValueAccessor लागू करने और ng2-select को लपेटकर अपना स्वयं का घटक बनाकर आगे बढ़ाया। (मैं यह नहीं बता सकता कि आप इनमें से कौन सा प्रश्न अपने प्रश्न में कर रहे थे)। अब जब कोई आइटम चुना जाता है तो आप this.onChange(val.id) पर कॉल करते हैं, जो स्ट्रिंग आईडी के साथ मूल घटक को अद्यतन करता है।

फिर आपने एक अलग मुद्दा देखा, जो कि ng2-select प्रारंभिक समय के दौरान एक परिवर्तन घटना को सक्रिय करता है यदि आप किसी चयनित मान को पूर्वनिर्धारित करते हैं। यह अजीब है क्योंकि उपयोगकर्ता ने अभी तक चयन नियंत्रण से बातचीत नहीं की है। इसलिए आपने को पर पर emitEvent: false के साथ कॉल करके को प्रारंभ करने का प्रयास किया, लेकिन मुझे लगता है कि यह काम नहीं करता है क्योंकि जब आपने अपना डेटा प्रारंभ किया था, तो ng2-select ने आपके डेटा में दूसरा परिवर्तन किया था, हाथोंहाथ।

बजाय, आप जब तक ng2-select से पहले अद्यतन अद्यतन करता है एक नई वस्तु को माता-पिता घटक इंतजार कर रहे हैं, और फिर (setTimeout उपयोग करते हुए) आप स्ट्रिंग आईडी आप वास्तव में चाहते हैं के साथ इसे अधिलेखित द्वारा इस के आसपास काम किया। यह स्ट्रिंग के साथ अद्यतित preparedComponent रखता है, लेकिन जब उपयोगकर्ता नियंत्रण से बातचीत नहीं करता तब भी बदलाव ईवेंट फ़ायरिंग के मुद्दे को हल नहीं करता है। (वैसे, अगर आप फिर अपने घटक के साथ ng2-select लपेटकर कर रहे हैं मुझे नहीं यकीन है कि तुम क्यों इस setTimeout भाग कर दिया था, हूं, क्योंकि आप पहले से ही एक और समारोह जो this.onChange(val.id) कॉल ng2-select एक नया की आपको सूचित करता है नहीं होगा चयनित आइटम, जैसा कि मैंने पिछले पैराग्राफ में वर्णित)


के बाद से मैं नहीं बता सकता कि क्या आप ng2-select प्रत्यक्ष रूप से बदलाव कर रहे हैं, या अपने खुद के घटक के साथ यह लपेटकर:

आप ng2-select को संशोधित कर रहे हैं, तो क्यों न केवल writeValue विधि ढूंढें और उस ईवेंट को हटा दें जो किसी ईवेंट को उत्सर्जित करता है ? इस तरह जब आप किसी मान को पूर्वनिर्धारित करते हैं तो यह DOM को अपडेट करता है, लेकिन फिर आपके मान को ओवरराइट नहीं करता है।

आप अपने खुद के घटक के साथ ng2-select लपेटकर रहे हैं, तो क्यों नहीं बस अपने writeValue विधि एक झंडा स्टोर करने के लिए करता है, तो ng2-select एक ईवेंट सक्रिय करने के बारे में है, संशोधित करने, तो आप इसे अनदेखा कर सकते हैं:

private: ignoreSelectedEvent = false; 

public writeValue(val: any): void { 
    this.ignoreSelectedEvent = true; 

    // Update ng2-select, which will cause an event to fire 
} 

और फिर में अपने कार्य है कि एक नए चयनित आइटम के प्रति प्रतिक्रिया:

if (this.ignoreSelectedEvent) { 
    this.ignoreSelectedEvent = false; 

    return; 
} 

// Update the model with the string ID 

this.onChange(val.id); 
0

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

तो समाधान के लिए प्रारंभिक मूल्य निर्धारित करने के लिए है कि क्या होगा आईडी की आईडी/सरणी के लिए कुछ वस्तु परिवर्तित करने के बाद onChange में नियंत्रण घटक वापसी। घटक को केवल उन सभी आईडी/आईडी के आधार पर सभी उपलब्ध वस्तुओं से उचित वस्तु का चयन करना होगा जो इसमें भेजे जाते हैं।

संबंधित मुद्दे