Knockout.js में अवलोकन योग्य बाइंडिंग को कैसे साफ़ करें / निकालें?


113

मैं एक वेबपेज पर कार्यक्षमता का निर्माण कर रहा हूं जिसे उपयोगकर्ता कई बार कर सकता है। उपयोगकर्ता की कार्रवाई के माध्यम से, एक वस्तु / मॉडल बनाया जाता है और ko.applyBindings () का उपयोग करके HTML पर लागू किया जाता है।

डेटा-बाउंड HTML को jQuery टेम्प्लेट के माध्यम से बनाया गया है।

अब तक सब ठीक है।

जब मैं दूसरी वस्तु / मॉडल बनाकर इस कदम को दोहराता हूं और ko.applyBindings () मैं दो समस्याओं का सामना करता हूं:

  1. मार्कअप पिछली वस्तु / मॉडल के साथ-साथ नई वस्तु / मॉडल को दर्शाता है।
  2. एक जावास्क्रिप्ट त्रुटि ऑब्जेक्ट / मॉडल में किसी एक गुण से संबंधित होती है, हालांकि यह अभी भी मार्कअप में प्रदान की जाती है।

इस समस्या को हल करने के लिए, पहले पास के बाद मैं jQuery के .empty () को अस्थायी HTML को हटाने के लिए कहता हूं जिसमें सभी डेटा-बाइंड विशेषताएँ शामिल हैं, ताकि यह DOM में अब न हो। जब उपयोगकर्ता दूसरी पास के लिए प्रक्रिया शुरू करता है तो डेटा-बाउंड HTML को DOM में दोबारा जोड़ा जाता है।

लेकिन जैसा मैंने कहा, जब HTML को DOM में दोबारा जोड़ा जाता है और नए ऑब्जेक्ट / मॉडल में फिर से बाउंड किया जाता है, तब भी इसमें पहले ऑब्जेक्ट / मॉडल का डेटा शामिल होता है, और मुझे अभी भी JS त्रुटि मिलती है जो नहीं होती है पहली पास के दौरान।

निष्कर्ष यह प्रतीत होता है कि नॉकआउट इन बाध्य गुणों को पकड़ रहा है, भले ही मार्क से डोम को हटा दिया गया हो।

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

संपादित करें

मूल प्रक्रिया यह है कि उपयोगकर्ता एक फ़ाइल अपलोड करता है; सर्वर तब JSON ऑब्जेक्ट के साथ प्रतिक्रिया करता है, डेटा-बाउंड HTML को DOM में जोड़ा जाता है, फिर JSON ऑब्जेक्ट मॉडल इस HTML का उपयोग करने के लिए बाध्य होता है

mn.AccountCreationModel = new AccountViewModel(jsonData.Account);
ko.applyBindings(mn.AccountCreationModel);

उपयोगकर्ता द्वारा मॉडल पर कुछ चयन किए जाने के बाद, उसी ऑब्जेक्ट को सर्वर पर वापस पोस्ट किया जाता है, डेटा-बाउंड HTML को तब DOM से हटा दिया जाता है, और मेरे पास तब निम्न JS है

mn.AccountCreationModel = null;

जब उपयोगकर्ता इसे एक बार फिर से करना चाहता है, तो इन सभी चरणों को दोहराया जाता है।

मुझे डर है कि jsFiddle डेमो करने के लिए कोड बहुत 'शामिल' है।


विशेष रूप से एक ही तत्व तत्व पर कई बार ko.applyBindings को कॉल करने की अनुशंसा नहीं की जाती है। आप जो चाहते हैं उसे प्राप्त करने का एक और तरीका हो सकता है। आपको हालांकि अधिक कोड प्रदान करने की आवश्यकता होगी। यदि संभव हो तो एक jsfiddle शामिल करें।
madcapnmckay

एक initफ़ंक्शन को उजागर क्यों नहीं किया जाता है जिसमें आप डेटा को लागू करने के लिए पास करते हैं?
क्योरकोड

जवाबों:


169

क्या आपने मेमोरी बाउंड ऑब्जेक्ट में डिस्पोज करने के लिए अपने DOM तत्व पर नॉकआउट की क्लीन नोड विधि को कॉल करने की कोशिश की है?

var element = $('#elementId')[0]; 
ko.cleanNode(element);

फिर अपने नए दृश्य मॉडल के साथ उस तत्व पर नॉकआउट बाइंडिंग को फिर से लागू करने से आपका दृश्य बाध्यकारी हो जाएगा।


33
यह काम करता है - धन्यवाद। मैं इस पद्धति पर कोई भी दस्तावेज़ खोजने में असमर्थ हूँ, हालाँकि।
07

मैं भी इस नॉकआउट उपयोगिता समारोह पर प्रलेखन के लिए खोज की है। पास के रूप में मैं स्रोत कोड से बता सकता हूं, यह deleteखुद को प्रमुख तत्वों पर कुछ चाबियों से बुला रहा है , जो स्पष्ट रूप से है जहां सभी नॉकआउट जादू संग्रहीत है। अगर किसी के पास दस्तावेज़ीकरण का स्रोत है, तो मैं बहुत मजबूर होऊंगा।
पैट्रिक एम

2
तुम इसे नहीं पाओगे। मैंने ko उपयोगिता फ़ंक्शंस पर डॉक्स के लिए उच्च और निम्न खोज की है, लेकिन कोई भी मौजूद नहीं है। यह ब्लॉग पोस्ट सबसे निकटतम चीज़ है जो आप पाएंगे, लेकिन यह केवल ko.utils के सदस्यों को शामिल करती है: knockmeout.net/2011/04/utility-functions-in-knockoutjs.html
निक डेनियल्स

1
आप नीचे दिए गए मेरे उत्तर में दिखाई गई घटनाओं को मैन्युअल रूप से हटाना चाहते हैं।
माइकल बर्कोम्पास

1
@KodeKreachor मैंने पहले ही नीचे काम करने के उदाहरण को पोस्ट कर दिया था। मेरा कहना था कि इसके बजाय ViewModel के भीतर डेटा जारी करते समय बाइंडिंग को बरकरार रखना बेहतर हो सकता है। इस तरह से आपको कभी भी संयुक्त राष्ट्र के साथ समझौता नहीं करना पड़ेगा। यह मैन्युअल रूप से DOM से सीधे unbind करने के लिए undocumented तरीकों का उपयोग करने से क्लीनर लगता है। इसके अलावा, CleanNode समस्याग्रस्त है क्योंकि यह किसी भी घटना संचालकों को जारी नहीं करता है (अधिक विस्तार के लिए यहां उत्तर देखें: stackoverflow.com/questions/15063794/… )
Zac

31

मैं जिस प्रोजेक्ट पर काम कर रहा हूं, उसके लिए मैंने एक साधारण ko.unapplyBindingsफ़ंक्शन लिखा था जो एक jQuery नोड और रिमूव बूलियन को स्वीकार करता है। यह पहले सभी jQuery इवेंट्स को अनबाइंड ko.cleanNodeकरता है क्योंकि विधि इसका ध्यान नहीं रखती है। मैंने मेमोरी लीक के लिए परीक्षण किया है, और यह ठीक काम करने के लिए प्रकट होता है।

ko.unapplyBindings = function ($node, remove) {
    // unbind events
    $node.find("*").each(function () {
        $(this).unbind();
    });

    // Remove KO subscriptions and references
    if (remove) {
        ko.removeNode($node[0]);
    } else {
        ko.cleanNode($node[0]);
    }
};

सिर्फ एक कैविएट, मैंने उस चीज़ को फिर से बाध्यकारी नहीं किया है ko.cleanNode()जिसे अभी-अभी बुलाया गया है और पूरे html को प्रतिस्थापित नहीं किया गया है।
माइकल बर्कम्पास 3

4
आपका समाधान अन्य सभी ईवेंट बाइंडिंग को भी रद्द नहीं करेगा? क्या केवल कोओ के घटना संचालकों को हटाने की संभावना है?
lordvlad


1
यह सच है, हालांकि यह संभव नहीं है जहाँ तक मैं एक कोर बदलाव के बिना बता सकता हूँ। इस मुद्दे को मैं यहाँ लाया: github.com/SteveSanderson/knockout/issues/724
माइकल बर्कोम्पास

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

12

आप बाध्यकारी प्रस्ताव के साथ प्रयोग करने का प्रयास कर सकते हैं: http://knockoutjs.com/documentation/with-binding.html यह विचार एक बार बाइंडिंग लागू करने का है, और जब भी आपका डेटा बदलता है, बस अपने मॉडल को अपडेट करें।

मान लें कि आपके पास एक शीर्ष स्तर का दृश्य मॉडल स्टोर व्यूमॉडल है, आपका कार्ट कार्ट व्यूमॉडल द्वारा दर्शाया गया है, और उस कार्ट में आइटमों की एक सूची है - कार्ट इटम्स व्यूवॉडल का कहना है।

आप शीर्ष स्तर के मॉडल - storeViewModel को पूरे पृष्ठ पर बाँध देंगे। फिर, आप अपने पृष्ठ के उन हिस्सों को अलग कर सकते हैं जो कार्ट या कार्ट आइटम के लिए ज़िम्मेदार हैं।

मान लें कि CartItemsViewModel में निम्नलिखित संरचना है:

var actualCartItemsModel = { CartItems: [
  { ItemName: "FirstItem", Price: 12 }, 
  { ItemName: "SecondItem", Price: 10 }
] }

CartItemsViewModel शुरुआत में खाली हो सकता है।

कदम इस तरह दिखेंगे:

  1. HTML में बाइंडिंग को परिभाषित करें। कार्ट को अलग करें। ViewModel बाइंडिंग।

      
        <div data-bind="with: cartItemsViewModel">
          <div data-bind="foreach: CartItems">
            <span data-bind="text: ItemName"></span>
            <span data-bind="text: Price"></span>
          </div>
        </div>
      
    
  2. स्टोर मॉडल आपके सर्वर से आता है (या किसी अन्य तरीके से बनाया गया है)।

    var storeViewModel = ko.mapping.fromJS(modelFromServer)

  3. अपने शीर्ष स्तर के दृश्य मॉडल पर खाली मॉडल परिभाषित करें। फिर वास्तविक डेटा के साथ उस मॉडल की संरचना को अपडेट किया जा सकता है।

      
        storeViewModel.cartItemsViewModel = ko.observable();
        storeViewModel.cartViewModel = ko.observable();
     
    
  4. शीर्ष स्तर के दृश्य मॉडल को बांधें।

    ko.applyBindings(storeViewModel);

  5. जब CartItemsViewModel ऑब्जेक्ट उपलब्ध हो, तो उसे पहले निर्धारित प्लेसहोल्डर को असाइन करें।

    storeViewModel.cartItemsViewModel(actualCartItemsModel);

यदि आप कार्ट आइटम साफ़ करना चाहते हैं: storeViewModel.cartItemsViewModel(null);

नॉकआउट html का ध्यान रखेगा - अर्थात यह तब दिखाई देगा जब मॉडल खाली नहीं होगा और div की सामग्री ("बाइंडिंग के साथ") गायब हो जाएगी।


9

मुझे ko.applyBinding हर बार खोज बटन क्लिक पर कॉल करना होगा, और फ़िल्टर किया गया डेटा सर्वर से वापस आ जाएगा, और इस मामले में ko.cleanNode का उपयोग किए बिना मेरे लिए काम का पालन करना।

मैंने अनुभव किया, यदि हम फॉर्चे को टेम्प्लेट से बदलते हैं तो संग्रह / अवलोकन योग्य के मामले में ठीक काम करना चाहिए।

आपको यह परिदृश्य उपयोगी लग सकता है।

<ul data-bind="template: { name: 'template', foreach: Events }"></ul>

<script id="template" type="text/html">
    <li><span data-bind="text: Name"></span></li>
</script>

1
मैंने कम से कम 4 घंटे इसी तरह के मुद्दे को सुलझाने की कोशिश की है और केवल आमिर का समाधान मेरे लिए काम करता है।
एंटोनिन जेलिनक

@AntoninJelinek ने दूसरी चीज जो मैंने अपने परिदृश्य में अनुभव की थी, html को पूरी तरह से हटाने के लिए, और डायनेमिकली ने इसे फिर से पूरी तरह से सब कुछ हटाने के लिए जोड़ दिया। उदाहरण के लिए, मेरे पास नॉकआउट कोड कंटेनर div <div id = "knockoutContainerDiv"> </>> $ पर है। सफलता का परिणाम मैं हर बार सर्वर विधि $ ("# knoutContainerDiv") का पालन करते हुए करता हूं। बच्चे (); / / इसके बारे में / सामग्री निकालें नॉकआउट कोड $ के साथ गतिशील HTML संलग्न करने के लिए विधि कॉल ( "# knockoutContainerDiv") संलग्न ( "नॉकआउट बाध्यकारी कोड के साथ childelements") और फिर applyBinding बुला।
आमिर सज्जाद

1
अरे अम्मां, मेरे पास आपके जैसा ही परिदृश्य था। आपके द्वारा उल्लिखित सब कुछ इस तथ्य को छोड़कर महान काम करता है कि मुझे ko.cleanNode (तत्व) का उपयोग करना था; पहले हर फिर से बाध्यकारी।
रैडोस्लाव मिनचेव

@RadoslavMinchev क्या आपको लगता है कि मैं आपकी आगे मदद कर सकता हूं, यदि हाँ तो कैसे, मुझे विशेष प्रश्न के बारे में अपने विचार / अनुभव साझा करने में खुशी होगी।
आमिर सज्जाद

धन्यवाद। @aamirsajjad, बस यह उल्लेख करना चाहता था कि मेरे लिए जो काम किया गया था उसे काम करने के लिए क्लीननोड () फ़ंक्शन को कॉल करना था।
राडोस्लाव मिनचेव

6

KO के आंतरिक कार्यों का उपयोग करने और JQuery के कंबल इवेंट हैंडलर को हटाने के बजाय, एक बेहतर विचार का उपयोग withया templateबाइंडिंग है। जब आप ऐसा करते हैं, तो ko DOM के उस हिस्से को फिर से बनाता है और इसलिए यह अपने आप साफ़ हो जाता है। यह भी जिस तरह से सिफारिश की है, यहाँ देखें: https://stackoverflow.com/a/15069509/207661


4

मुझे लगता है कि पूरे समय बाध्यकारी रखना बेहतर हो सकता है, और बस इससे जुड़े डेटा को अपडेट करें। मैं इस मुद्दे पर भाग गया, और पाया कि .resetAll()जिस सरणी में मैं अपना डेटा रख रहा था, उस पद्धति का उपयोग करके केवल कॉल करना ऐसा करने का सबसे प्रभावी तरीका था।

मूल रूप से आप कुछ वैश्विक संस्करण के साथ शुरू कर सकते हैं जिसमें ViewModel के माध्यम से प्रस्तुत किए जाने वाले डेटा शामिल हैं:

var myLiveData = ko.observableArray();

यह महसूस करने में मुझे थोड़ा समय लगा कि मैं सिर्फ myLiveDataएक सामान्य सरणी नहीं बना सका - ko.oberservableArrayभाग महत्वपूर्ण था।

तब आप आगे बढ़ सकते हैं और जो भी आप करना चाहते हैं वह कर सकते हैं myLiveData। उदाहरण के लिए, एक $.getJSONकॉल करें:

$.getJSON("http://foo.bar/data.json?callback=?", function(data) {
    myLiveData.removeAll();
    /* parse the JSON data however you want, get it into myLiveData, as below */
    myLiveData.push(data[0].foo);
    myLiveData.push(data[4].bar);
});

एक बार ऐसा करने के बाद, आप आगे बढ़ सकते हैं और हमेशा की तरह अपने ViewModel का उपयोग करके बाइंडिंग लागू कर सकते हैं:

function MyViewModel() {
    var self = this;
    self.myData = myLiveData;
};
ko.applyBindings(new MyViewModel());

फिर HTML myDataमें आप सामान्य रूप से उपयोग करेंगे।

इस तरह, आप जो भी फ़ंक्शन से myLiveData के साथ मेल कर सकते हैं। उदाहरण के लिए, यदि आप हर कुछ सेकंड में अपडेट करना चाहते हैं, तो बस उस $.getJSONलाइन को किसी फ़ंक्शन में लपेटें और उस setIntervalपर कॉल करें । जब तक आप myLiveData.removeAll();लाइन को याद रखना चाहते हैं, तब तक आपको बंधन को हटाने की आवश्यकता नहीं होगी ।

जब तक आपका डेटा वास्तव में बहुत बड़ा नहीं होता है, तब तक उपयोगकर्ता सरणी को रीसेट करने और फिर सबसे वर्तमान डेटा को जोड़ने के बीच समय को नोटिस करने में सक्षम नहीं होगा।


प्रश्न पोस्ट करने के बाद के समय में, मैं अब यही करता हूं। यह सिर्फ इतना है कि इनमें से कुछ नॉकआउट तरीके या तो अनिर्दिष्ट हैं या आपको वास्तव में चारों ओर देखने की जरूरत है (पहले से ही फ़ंक्शन का नाम जानने के लिए) यह क्या करता है।
13:22

मुझे इसे खोजने में बहुत मेहनत करनी पड़ी (जब डॉक्स के माध्यम से खुदाई करने में घंटों की संख्या कोड की पंक्तियों की परिणामी संख्या से अधिक हो जाती है ... वाह)। मैं खुश हूं कि आपका यह चलने लगा।
Zac

2

मुझे हाल ही में एक मेमोरी लीक की समस्या थी और ko.cleanNode(element);यह मेरे लिए नहीं करेगा - ko.removeNode(element);किया। जावास्क्रिप्ट + नॉकआउट.ज स्मृति रिसाव - कैसे सुनिश्चित करें कि वस्तु नष्ट हो रही है?


नॉकआउट 3.1 में, ko.removeNode वास्तव में ko.cleanNode कहता है। मुझे नहीं पता कि पहले के संस्करणों के लिए यही स्थिति थी, हालांकि।
कीपेरनी

1

क्या आपने इस बारे में सोचा है:

try {
    ko.applyBindings(PersonListViewModel);
}
catch (err) {
    console.log(err.message);
}

मैं इसके साथ आया क्योंकि नॉकआउट में, मुझे यह कोड मिला

    var alreadyBound = ko.utils.domData.get(node, boundElementDomDataKey);
    if (!sourceBindings) {
        if (alreadyBound) {
            throw Error("You cannot apply bindings multiple times to the same element.");
        }
        ko.utils.domData.set(node, boundElementDomDataKey, true);
    }

तो मेरे लिए यह वास्तव में एक मुद्दा नहीं है कि इसकी पहले से ही बाध्य है, यह है कि त्रुटि पकड़ा नहीं गया था और निपटा ...


0

मैंने पाया है कि यदि दृश्य मॉडल में कई div बाइंडिंग शामिल हैं, तो ko.applyBindings(new someModelView);उपयोग करने का सबसे अच्छा तरीका है : ko.cleanNode($("body")[0]);यह आपको ko.applyBindings(new someModelView2);पिछले दृश्य मॉडल की चिंता के बिना एक नए गतिशील रूप से कॉल करने की अनुमति देता है ।


4
कुछ ऐसे बिंदु हैं जिन्हें मैं जोड़ना चाहूंगा: (1) यह आपके वेबपेज से सभी बाइंडिंग को साफ कर देगा, जो आपके आवेदन के अनुरूप हो सकता है, लेकिन मुझे लगता है कि बहुत सारे अनुप्रयोग हैं जहां बाइंडिंग को पेज के कई हिस्सों में अलग-अलग जोड़ दिया गया है कारणों। यह कई उपयोगकर्ताओं के लिए एक एकल, व्यापक आदेश में सभी बाइंडिंग को साफ करने के लिए उपयोगी नहीं हो सकता है। (2) पुनर्प्राप्त करने $("body")[0]का एक तेज़, अधिक कुशल, देशी जावास्क्रिप्ट तरीका है document.body
जज
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.