我有两组几乎相同的代码,两者之间唯一的区别是一个元素中有一个选项标题而另一个没有。没有optionsCaption数据的代码看似正确绑定,另一个似乎在绑定第一个元素后停止数据绑定。有人可以向我解释我做错了什么以及数据绑定为什么会这样工作?
示例1 - 不起作用,为了查看,请选择其中一个选项 - http://jsfiddle.net/749sj7w5/2/
示例2 - 正确工作 - http://jsfiddle.net/749sj7w5/3/
脚本:
var Program = function (programId, description) {
this.ProgramId = programId;
this.Description = description;
};
var myViewModel = function () {
var self = this;
self.program = ko.observable();
self.programId = ko.observable(-1);
self.availablePrograms = ko.observableArray([
new Program(1, "Program One"),
new Program(2, "Program Two"),
new Program(3, "Program Three")]);
self.programId.subscribe(function (newValue) {
self.program(self.availablePrograms()[newValue - 1]);
});
};
非工作html:
<div>
<select data-bind="options: availablePrograms, optionsText: 'Description', optionsValue: 'ProgramId', value: programId, optionsCaption: 'Select a Program'"></select>
</div>
<div>
<input type="text" data-bind="value: program().Description" />
<input type="text" data-bind="value: program().Description" />
<input type="text" data-bind="value: program().ProgramId" />
</div>
使用html:
<div>
<select data-bind="options: availablePrograms, optionsText: 'Description', optionsValue: 'ProgramId', value: programId"></select>
</div>
<div>
<input type="text" data-bind="value: program().Description" />
<input type="text" data-bind="value: program().Description" />
<input type="text" data-bind="value: program().ProgramId" />
</div>
谢谢
答案 0 :(得分:3)
如果您使用null
,则需要防御optionsCaption
值,因为program()
将undefined
为<div>
<input type="text" data-bind="value: program() ? program().Description : 'none'" />
<input type="text" data-bind="value: program() ? program().Description : 'none'" />
<input type="text" data-bind="value: program() ? program().ProgramId : 'none' " />
</div>
,直到选择了某些内容为止。您可以执行以下操作:
program()
这只会评估{{1}} observable是否已设置。
答案 1 :(得分:1)
浏览器控制台显示此错误:
Uncaught TypeError:无法处理绑定“value:function(){return program()。Description}” 消息:无法读取未定义的属性“描述”
这是因为在第一种情况下(当不起作用时),当敲除执行绑定时,programId
的值不会改变(因为指定了optionsCaption且未选择实际值)。所以program
保持未定义,因为您没有使用任何值(self.program = ko.observable();
)初始化它。
在第二种情况下(工作时),在绑定过程中,淘汰更新programId
(设置选择的默认值),因此您的订阅会触发:
self.programId.subscribe(function (newValue) {
self.program(self.availablePrograms()[newValue - 1]);
});
因此更新program
并正确填充值。
修改强>
出现了另一个问题:
当我选择一个程序时究竟发生了什么?如果program()为null,那么第一个输入元素如何在选择程序后显示一个值,另一方面,如果program()不为null,那么其他两个元素如何不被绑定?
当knockout绑定第一个值时,抛出异常(因为未定义)并且绑定进程停止。但是这个第一个绑定保持“活着”,其余的只是没有约束。只是为了说清楚 - 由于绑定只执行一次,即使program
值发生变化,其他字段也不会受到约束。这就是为什么它表现得如此奇怪。
注意:此讨论会从评论中复制并粘贴到此同一问题的其他答案,以确保在删除答案或删除评论时不会丢失此内容。
答案 2 :(得分:1)
问题是您的输入绑定正在尝试使用program
observable中找到的对象的属性。当您将标题添加到选择options
绑定时,没有初始值,因此program
最终没有值(undefined
),因此所有内容都会崩溃。
其他人提供了一种解决问题的方法,但另一个问题仍然存在,你并没有充分利用这些绑定。
select
元素的选定值不需要是字符串或其他简单值,它可以是任何。而不是绑定到补充ID并查找相关程序,只需绑定到程序本身。
<select data-bind="options: availablePrograms,
optionsText: 'Description',
optionsCaption: 'Select a Program',
value: selectedProgram">
</select>
function ViewModel() {
this.selectedProgram = ko.observable();
this.availablePrograms = ko.observableArray(...);
}
然后,从那里,如果要访问所选程序的属性,请使用with
绑定将上下文更改为所选程序。
<div data-bind="with: selectedProgram">
<input type="text" data-bind="value: Description"/>
<input type="text" data-bind="value: Description"/>
<input type="text" data-bind="value: ProgramId"/>
</div>
请注意,如果没有选定的程序,则不会显示输入。如果要保持可见,请在没有选定程序的情况下使用虚拟对象。
<div data-bind="with: selectedProgram() || {}">...</div>
演示:
function Program(programId, description) {
this.ProgramId = programId;
this.Description = description;
}
function ViewModel() {
this.selectedProgram = ko.observable();
this.availablePrograms = ko.observableArray([
new Program(1, 'Program One'),
new Program(2, 'Program Two'),
new Program(3, 'Program Three')
]);
}
var viewModel = new ViewModel();
ko.applyBindings(viewModel, document.getElementById('content'));
&#13;
#content div {
border: thin black solid;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div id="content">
<div>
<select data-bind="options: availablePrograms,
optionsText: 'Description',
optionsCaption: 'Select a Program',
value: selectedProgram">
</select>
</div>
<div data-bind="with: selectedProgram() || {}">
<input type="text" data-bind="value: Description"/>
<input type="text" data-bind="value: Description"/>
<input type="text" data-bind="value: ProgramId"/>
</div>
</div>
&#13;