Not understanding ko.obseravables

Not understanding ko.obseravables

本文关键字:obseravables ko understanding Not      更新时间:2023-09-26

因此,请考虑以下内容:

(function($, ko){
    var ViewModel = function() {
        var self           = this;
        self.errorMessages = ko.observableArray([]);
        self.desigItems    = ko.observableArray([]);
        self.frequencies   = ko.observableArray([]);
    }
    var viewModel = new ViewModel();
    var loadData = function() {
        $.ddcApiGet('/widget/desigs.json', [], function(data) {
            _processLoadedData(data);
        }, viewModel.errorMessages);
    }
    var loadFrequencies = function() {
        $.ddcApiGet('/widget/freqs.json', [], function(data) {
            _processFrequenciesData(data);
        }, viewModel.errorMessages);
    }
    var _processLoadedData = function(data) {
        for (var i = 0; i < data.desig_options.length; i++) {
            viewModel.desigItems.push(data.desig_options[i]);
        }
    }
    var _processFrequenciesData = function(data) {
        var frequencies = [];
        // Get the list of frequencies.
        for (var i = 0; i < data.frequency.length; i++) {
            frequencies.push(data.frequency[i]);
        }
        // Push frequencies on to each of the design items in the list.
        for (var i = 0; i < viewModel.desigItems.length; i++) {
            viewModel.desigItems[i]['frequencies'] = frequencies
        }
        console.log(viewModel.desigItems());
    }
    var preBind = function() {
        loadData();
        loadFrequencies();
    }
    preBind();
    ko.applyBindings(viewModel, $('#designnation-list-container')[0]);
})(jQuery, ko);

然后与以下视图关联:

<h1>Hello World</h1>
<div id="designnation-list-container" data-bind="foreach: desigItems">
<div class="donor-js-wid-desig-opt donor-style-box donor-style-2col">
        <h2 class="donor-js-desig-desc" data-bind="text: desc"> </h2>
        <img class="donor-js-desig-logo donor-style-donation-image" alt="Web Desc 10000 - adding this" src="https://d36vh9gkg2fzwi.cloudfront.net/imageserver/be1b7b8e195587ff422c40750a6caa9f/10000_IPHONE_v1.JPG">
        <form method="post" enctype="multipart/form-data" action="javascript:">
            <input class="donor-js-wid-desig" type="hidden" name="gift_desig" value="10000">
            <p class="donor-js-desig-shorttext" data-bind="html: shortdesc"> </p>
                <p id="donor-js-donation-amount-label">
                    <label class="donor-style-label">Donation Amount</label>
                </p>
            <p>
            <div data-bind="foreach: amount_options">
                <label class="donor-js-amount-choice">
                    <input type="radio" class="donor-js-webware" name="gift_amt" data-bind="attr: {value: desc}, checked: selected"><span class="donor-js-currency-symbol">$</span>&nbsp;<span class="donor-js-amount" data-bind="text: desc"></span>&nbsp;<span class="donor-js-input-currency"></span><br>
                </label>
            </div>
            <label>
                <input type="radio" class="donor-js-other-amount-opt" name="gift_amt" value="other">
                <span id="donor-js-other-label">Amount:</span>
                <span class="donor-js-currency-symbol">$</span></label>
                <input class="donor-js-other-amount-input" type="text" name="other_amt" onclick="$(this).closest('form').find('input[class=donor-js-other-amount-opt]').attr('checked', true);">&nbsp;<span class="donor-js-input-currency"></span>
            </p>
            <p>
                <select class="donor-js-wid-frequency" name="gift_freq" data-bind="options: frequencies, optionsText: desc, value: desc"></select>
            </p>
            <p id="donor-js-gift-notes" style="display:none">
                <label class="donor-js-gift-note-label">Gift Notes
                    <textarea name="gift_note" class="donor-style-select" rows="2" cols="40"></textarea>
                </label>
            </p>
            <p><input type="submit" class="donor-js-dona-submit button" value="Add to Cart"><input type="button" class="donor-js-desig-info donor-style-buttonlink" value="show more details">
            </p></form>
        <div class="donor-style-clearb"></div>
    </div>
</div>

我知道有很多东西要接受,但我有一个特定的功能有问题:_processFrequenciesData

看到的问题是,我有一个选择元素:

        <p>
            <select class="donor-js-wid-frequency" name="gift_freq" data-bind="options: frequencies, optionsText: desc, value: desc"></select>
        </p>

正如您可能从我发布的初始视图中看到的,这个select元素位于self.desigItems 上循环的循环中

此函数(_processFrequenciesData)中有一个console.log,但它返回:[]

你会认为,好吧,也许数据没有被提取,接受它在这一点上,因为7个项目被渲染到屏幕上。

我想做的是说,好吧:把这个frequencies列表添加到每个desigItems

那么,为什么当我console.log(viewModel.desigItems)时,我得到了一个空数组,而当视图遍历desigItems时,我又得到了七个东西呢?

observableArray不是数组。它是包装数组的函数(!)(就像observable不是值,而是包装值的函数一样)。要检索实际值,必须调用一个可观测值:

// Push frequencies on to each of the design items in the list.
var desigItems = viewModel.desigItems(); // access the underlying array
for (var i = 0; i < desigItems.length; i++) {
    desigItems[i].frequency = frequencies[i];
}
viewModel.desigItems.notifySubscribers();
console.log(viewModel.desigItems());

您所做的是向可观察对象本身添加属性,但这不会影响可观察对象包含的值。

现在,由于我们已经改变了viewModel.desigItems的基本值,而没有给敲除一个注意的机会,我们必须调用notifySubscribers()来通知每个人可观察到的值已经改变。


话虽如此,我会这样重写你的整个代码:

(function($, ko){
    function ViewModel() {
        var self = this;
        self.errorMessages = ko.observableArray();
        self.desigItems    = ko.observableArray();
        self.frequencies   = ko.observableArray();
    }
    var viewModel = new ViewModel();
    $(function () {
        ko.applyBindings(viewModel, $('#designnation-list-container')[0]);
    });
    var desigsReq = $.ddcApiGet('/widget/desigs.json').done(viewModel.desigItems);
    var freqsReq = $.ddcApiGet('/widget/freqs.json').done(viewModel.frequencies);
    $.when(desigsReq, freqsReq).done(function (desigs, freqs) {
        desigs.forEach(function (desig, i) {
            desig.frequency = freqs[i];
        });
    }).fail(viewModel.errorMessages);
})(jQuery, ko);

这修复了代码中的两个定时问题:

  • 在文档准备就绪之前,不能绑定视图模型
  • 您必须等待两个Ajax请求都完成,然后才能组合结果

以这种方式组合两个数组是否真的有用是另一回事。我认为这不是一个很干净的解决方案。


附言:你真的可以把这个问题缩短,实际上你发布的代码都与手头的问题无关。

那么,为什么当我console.log(viewModel.desigItems())时,我得到了一个空数组,而当视图遍历desigItems时,我又得到了七个东西呢?

_processFrequenciesData回调函数中有console.log(viewModel.desigItems)调用。

但是,您不会在那里填充viewModel.desigItems,而是在_processLoadedData回调函数中填充。

这可能是一个简单的错误。您可能只想将console.log(...)移到另一个回调中。

按照现在的方式,当loadFrequencies的响应在loadData的响应之前处理时,您将有一个空的控制台输出(正如您所看到的)。