因此,请考虑以下几点:
(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> <span class="donor-js-amount" data-bind="text: desc"></span> <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);"> <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请求都完成,然后才能合并结果。
以这种方式组合两个数组是否真正有用是另一回事。我会说这并不是一个很干净的解决方案。
附注:您确实可以简化这个问题,实际上您发布的代码都与手头的问题无关。