因此,请考虑以下几点:

(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

看到的问题是我有一个select元素:

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


如您从我发布的初始视图中所看到的,此select元素位于循环self.desigItems的循环内

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

您会认为,好吧,也许此时尚未获取数据,请接受它,因为有7个项目已呈现到屏幕上。

我想做的就是说,好吧:将此frequencies列表添加到每个desigItems

那么为什么当我console.log(viewModel.desigItems)返回一个空数组却为什么视图遍历desigItems却又返回了七个东西呢?

最佳答案

observableArray不是数组。它是一个包装数组的函数(!)(就像observable不是值,而是包装一个值的函数)。要检索实际值,必须调用一个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请求都完成,然后才能合并结果。


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



附注:您确实可以简化这个问题,实际上您发布的代码都与手头的问题无关。

09-27 03:45