首页 文章

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

提问于
浏览
2

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

  • 1

    如果使用 optionsCaption ,则需要防御 null 值,因为 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() observable是否已设置 .

  • 1

    浏览器控制台显示此错误:

    未捕获的TypeError:无法处理绑定“value:function(){return program() . Description}”消息:无法读取未定义的属性“描述”

    发生这种情况是因为在第一种情况下(当不起作用时),当敲除执行绑定时, programId 的值不会改变(因为指定了optionsCaption且未选择实际值) . 所以 program 保持未定义,因为你没有用任何值初始化它( self.program = ko.observable(); ) .

    在第二种情况下(工作时),在绑定过程中,knockout更新 programId (设置select的默认值),因此您的订阅会触发:

    self.programId.subscribe(function (newValue) {
        self.program(self.availablePrograms()[newValue - 1]);
    });
    

    因此更新 program 并正确填充值 .

    Edit:

    出现了另一个问题

    当我选择一个程序时究竟发生了什么?如果program()为null,那么第一个输入元素如何在选择程序后显示一个值,另一方面,如果program()不为null,那么其他两个元素如何不被绑定?

    当knockout绑定第一个值时,抛出异常(因为未定义)并且绑定进程停止 . 但是这个第一个绑定保持"alive",其余的只是没有约束 . 只是为了清楚 - 由于绑定只执行一次,即使 program 值发生变化,其他字段也不会受到限制 . 这就是它以如此奇怪的方式表现的原因 .

    注意:此讨论会从评论中复制并粘贴到同一问题的其他答案,以确保在删除答案或删除评论时不会丢失 .

  • 3

    问题是您的输入绑定正在尝试使用 program observable中找到的对象的属性 . 当您将 Headers 添加到选择 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'));
    
    #content div {
      border: thin black solid;
    }
    
    <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>
    

相关问题