चलाने के लिए एक कम्प्यूटेड संपत्ति फ़ंक्शन को बाध्य करें


80

एक गणना की गई संपत्ति को देखते हुए

vm.checkedValueCount = ko.computed(function(){
  var observables = getCurrentValues();  //an array of ko.observable[]
  return _.filter(observables, function(v) { return v() }).length;
});

मान लीजिए कि getCurrentValues ​​() वेधशालाओं के विभिन्न सेटों को वापस कर सकते हैं जो कोड में कहीं और संशोधित किए गए हैं (और एक अवलोकन योग्य से अधिक जटिल संरचना से आता है)।

मुझे checkedValueCountजब भी अपडेट करना होगा

  • इसकी एक निर्भरता बदल जाती है
  • getCurrentValues ​​() वेधशालाओं का एक अलग सेट लौटाता है।

समस्या यह है कि ko.computedअंतिम रिटर्न मान को याद करने के लिए लगता है और केवल जब एक निर्भरता अद्यतन अद्यतन करता है। यह पहला मामला संभालता है लेकिन बाद वाला नहीं।

मैं जो खोज रहा हूं वह चेकवैल्यू को फिर से चलाने के लिए मजबूर करने का एक तरीका है। कुछ जो मैं उपयोग कर सकता हूं:

changeCurrentValues();
vm.checkeValueCount.recalculate();

सबसे सरल शब्दों में कहें, तो यह मेरे पास है

a = ko.computed(function() { return Math.random() })

मैं a()विभिन्न मूल्यों को वापस करने के लिए दो बार कैसे मजबूर कर सकता हूं ।


मेरा अद्यतन "पुनर्लेखन" उत्तर देखें।
जोश

जवाबों:


116

मुझे एहसास हुआ कि मेरा पहला जवाब आपकी बात से चूक गया, और आपकी समस्या का समाधान नहीं होगा।

समस्या यह है कि एक गणना केवल पुनर्मूल्यांकन होगी यदि कुछ अवलोकन योग्य है जो इसे फिर से मूल्यांकन करने के लिए मजबूर करता है। गणना के लिए फिर से मूल्यांकन करने के लिए मजबूर करने का कोई मूल तरीका नहीं है।

हालाँकि, आप इसे डमी ऑब्जर्वेबल मान बनाकर कुछ हैकरी के साथ प्राप्त कर सकते हैं और फिर अपने ग्राहकों को बता सकते हैं कि यह बदल गया है।

(function() {

    var vm = function() {
        var $this = this;

        $this.dummy = ko.observable();

        $this.curDate = ko.computed(function() {
            $this.dummy();
            return new Date();
        });

        $this.recalcCurDate = function() {
            $this.dummy.notifySubscribers();
        };        
    };

    ko.applyBindings(new vm());

}());​

यहाँ एक फिडेल है जो इस दृष्टिकोण को दिखा रहा है


आह, मैंने यह कोशिश की, लेकिन मैंने इसे गलत रूप दिया होगा। यह हैकरी लगता है, लेकिन अच्छा (और काफी अच्छा है कि मैं इसे काम करने की अनुमति देने के लिए ko.computed का विस्तार कर सकता हूं
जॉर्ज माउर

हमेशा की तरह सरल सबसे अच्छा है।
हेनरी रोड्रिगेज

1
यह सहायक जब आप डेटा के बड़े सरणी को बदलते हैं जो देखने योग्य नहीं है और परिवर्तन के बाद डेटा के कुछ हिस्से को प्रदर्शित किया जाना चाहिए।
मारेक बार

1
नोटिस्फ़ेब्रिकर्स () का आपका उपयोग एक अच्छा है। की तुलना में बेहतर है कि मैं क्या एक यादृच्छिक संख्या के निर्माण और () डमी के मूल्य के स्थापित करने के कर रहा था
efreed

9

नहीं है एक विधि तुम्हारा के आधार पर सभी observables के बल पुनर्गणना के लिए:

getCurrentValues.valueHasMutated()

9
कंप्यूटर्स में यह विधि नहीं है
जॉर्ज माउर

getCurrentValues(); //an array of ko.observable[]
रुस्तम

ओह मैं समझा। आप कह रहे हैं कि एक अवलोकन योग्य है जो गणना की निर्भरता है और इसे valueHasMutatedविधि कहते हैं। यह वास्तव में मौलिक रूप से जोश के उत्तर से अलग नहीं है, क्या यह है? वास्तव में यह आपको यह जानने के लिए मजबूर करता है कि संदर्भित क्या है और यह जानने के लिए कि वे संदर्भ अवलोकनीय हैं (और गणना नहीं)।
जॉर्ज मौएर

2
इस फ़ंक्शन का उल्लेख करना अच्छा है, हालांकि यह पाठकों के लिए एक विकल्प बना हुआ है, हालाँकि शायद कोई नोट मामलों के स्वीकृत उत्तर को अपडेट कर सकता है, जहाँ इस फ़ंक्शन को InformSubscribers () के साथ इंटरचेंज किया जा सकता है, और यदि कोई जुर्माना या फायदा हो तो।
शॉन विल्सन 19

4

यह उत्तर वैचारिक रूप से वैसा ही है जैसा कि एक @ जोश ने दिया था, लेकिन एक अधिक सामान्य आवरण के रूप में प्रस्तुत किया। नोट: यह संस्करण एक 'लिखने योग्य' गणना के लिए है।

मैं टाइपस्क्रिप्ट का उपयोग कर रहा हूं इसलिए मैंने पहले tdd परिभाषा को शामिल किया है। इसलिए इस पहले भाग को नजरअंदाज करें यदि आप के लिए प्रासंगिक नहीं है।

interface KnockoutStatic
{
    notifyingWritableComputed<T>(options: KnockoutComputedDefine<T>, context ?: any): KnockoutComputed<T>;
}

सूचना-लेखन-संगणित

एक लिखने योग्य के लिए एक आवरण observableजो हमेशा ग्राहकों को सूचित करता है - भले ही कोई वेधशाला writeकॉल के परिणामस्वरूप अपडेट नहीं की गई हो

यदि आप टाइपस्क्रिप्ट का उपयोग नहीं करते हैं तो बस इसके function<T> (options: KnockoutComputedDefine<T>, context)साथ बदलें function(options, context)

ko.notifyingWritableComputed = function<T> (options: KnockoutComputedDefine<T>, context)
{
    var _notifyTrigger = ko.observable(0);
    var originalRead = options.read;
    var originalWrite = options.write;

    // intercept 'read' function provided in options
    options.read = () =>
    {
        // read the dummy observable, which if updated will 
        // force subscribers to receive the new value
        _notifyTrigger();   
        return originalRead();
    };

    // intercept 'write' function
    options.write = (v) =>
    {
        // run logic provided by user
        originalWrite(v);

        // force reevaluation of the notifyingWritableComputed
        // after we have called the original write logic
        _notifyTrigger(_notifyTrigger() + 1);
    };

    // just create computed as normal with all the standard parameters
    return ko.computed(options, context);
}

इसके लिए मुख्य उपयोग मामला तब है जब आप कुछ ऐसा अपडेट कर रहे हैं जो अन्यथा readफ़ंक्शन द्वारा 'अवलोकन' किए गए अवलोकन में परिवर्तन को ट्रिगर नहीं करेगा ।

उदाहरण के लिए मैं कुछ मान सेट करने के लिए लोकलस्टोरेज का उपयोग कर रहा हूं, लेकिन पुनर्मूल्यांकन को ट्रिगर करने के लिए किसी भी अवलोकन के लिए कोई परिवर्तन नहीं है।

hasUserClickedFooButton = ko.notifyingWritableComputed(
{
    read: () => 
    {
        return LocalStorageHelper.getBoolValue('hasUserClickedFooButton');
    },
    write: (v) => 
    {
        LocalStorageHelper.setBoolValue('hasUserClickedFooButton', v);        
    }
});

ध्यान दें कि सभी मैं परिवर्तन करने की जरूरत थी ko.computedकरने के लिए ko.notifyingWritableComputedऔर उसके बाद सब कुछ खुद का ख्याल रखता है।

जब मैं फोन करता हूं hasUserClickedFooButton(true)तो 'डमी' देखने योग्य किसी भी सब्सक्राइबर्स (और उनके सब्सक्राइबर) को नए मूल्य प्राप्त करने के लिए मजबूर किया जाता है, जब लोकलस्टोरेज में वैल्यू अपडेट होती है।

(नोट: आप सोच सकते हैं कि notify: 'always'एक्सटेंडर यहां एक विकल्प है - लेकिन यह कुछ अलग है)।


एक गणना योग्य अवलोकन के लिए एक अतिरिक्त समाधान है जो केवल पठनीय है:

ko.forcibleComputed = function(readFunc, context, options) {
    var trigger = ko.observable().extend({notify:'always'}),
        target = ko.computed(function() {
            trigger();
            return readFunc.call(context);
        }, null, options);
    target.evaluateImmediate = function() {
        trigger.valueHasMutated();
    };
    return target;
};


myValue.evaluateImmediate();

@Mbest टिप्पणी से https://github.com/knockout/knockout/issues/1019


आपका क्या मतलब है कि कोई मूल्य नहीं है? क्या यह स्विच करने से पहले काम करता था। क्या आप आस्थगित अपडेट (वैश्विक सेटिंग) का उपयोग कर रहे हैं। बस एहसास हुआ कि यदि आप अवलोकन को अद्यतन करने में सक्षम होने और फिर तुरंत मूल्य का उपयोग करने में सक्षम होने की उम्मीद करते हैं तो संघर्ष हो सकता है। यदि ऐसा है तो ko.tasks.runEarly () को मेरी विधि में जोड़ने का प्रयास करें।
सिमोन_विवर

1

मान लीजिए कि getCurrentValues ​​() वेधशाला के विभिन्न सेट लौटा सकते हैं जो कोड में कहीं और संशोधित किए गए हैं

मुझे लगता है getCurrentValues ​​() एक फ़ंक्शन है। यदि आप इसे एक संगणक बना सकते हैं, तो आपका CheckValueCount बस जादुई रूप से काम करना शुरू कर देगा।

आप कर सकते हैं getCurrentValues ​​एक समारोह के बजाय एक गणना की जा सकती है?


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

अगर यह "स्लाइसिंग और डाइशिंग" वेधशालाओं पर आधारित होता, तो इससे फर्क पड़ता। उदाहरण के लिए, मान लें कि आपका स्लाइसिंग और डायनिंग नोड्स है। .schecked () == सही है। फिर आपके पास एक गणना .currentValues ​​() होगी जो सभी नोड्स का मूल्यांकन करेगी और उन्हें .Ichecked () में लौटा देगी। क्या अवलोकन योग्य गुणों पर स्लाइसिंग और डिशिंग किया जा सकता है?
जुडाह गेब्रियल हिमांगो 19

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

-1

चूँकि किसी गणना को अद्यतन करने के लिए मजबूर करने का कोई सीधा आगे का तरीका नहीं है, इसलिए मैंने toForceComputedUpdate नाम का एक ऑब्जर्वेबल बनाया है, और मैंने इसे गणना की गई फ़ंक्शन के भीतर बुलाया है, इसलिए कंप्यूटर्स इसके अपडेट को सुनेगा, फिर अपडेट को बाध्य करने के लिए इसे इस तरह से toForceComputedUpdate (Math) )

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