optionsCaption如何影响淘汰赛中的数据绑定

时间:2014-09-19 12:31:54

标签: knockout.js

我有两组几乎相同的代码,两者之间唯一的区别是一个元素中有一个选项标题而另一个没有。没有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>

谢谢

3 个答案:

答案 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> ,直到选择了某些内容为止。您可以执行以下操作:

Demo Fiddle

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>

演示:

&#13;
&#13;
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;
&#13;
&#13;