Knockout Select2 按对象设置初始值

Posted

技术标签:

【中文标题】Knockout Select2 按对象设置初始值【英文标题】:Knockout Select2 set initial value by object 【发布时间】:2019-02-22 00:31:02 【问题描述】:

我有一个 Knockout.js Web 应用程序,其中有一个 select2 下拉菜单。我想将 id 和 text 值都绑定到一个变量,而不仅仅是 id。这是我的数据:

var cars = [id: 1, name: 'Honda', id: 2, name: 'Toyota', id: 3, name: 'Dodge'];
var selectedCar = ko.observable();

这是我的html

<select data-bind="value: selectedCar, optionsCaption: 'Select', optionsText: 'name', options: cars"></select>

所以现在,每当我在下拉列表中选择某些内容时,我的变量都会包含整个对象,如下所示:

selectedCar = id: 1, name: 'Honda';

当您加载页面并希望将下拉菜单设置为特定值时,会出现唯一问题。即使在呈现 html 之前,selectedCar 变量设置为 id: 1, name: 'Honda',当页面呈现时下拉菜单没有设置为任何内容,它只是设置为占位符“选择”。

我做错了什么?

【问题讨论】:

很好的问题,通过回答这个问题学到了一些新东西 嗨..对答案有什么想法吗? 【参考方案1】:

如果要将 id 和 text 值都绑定到变量,则需要使用 optionsValue 绑定并将整个上下文绑定到它($data);

<select data-bind="value: selectedCar, 
                   optionsCaption: 'Select', 
                   optionsText: 'name', 
                   options: cars, 
                   optionsValue: $data"></select>

通常我们会指定 id 或其他任何内容来选择初始值。因此,如果湿设置optionsValue: $data 而不是$optionsValue: 'id',则在您的问题中将整个对象id: 1, name: 'Honda' 作为初始值提供给selectedCar 是有意义的。

(IMPORTANT) 但事实证明这不起作用,因为我们正在创建一个新对象,因此当 Knockout 将 cars 的对象与内部对象进行比较时,它的相等性测试将失败selectedCar。设置初始值的正确方法是cars[0]


我确定这是一个错字,但无论如何我会指定:当您创建任何需要由 HTML 访问的变量时,您需要将其绑定到 this,这将是对 viewModel 的引用.

this.cars = [id: 1, name: 'Honda', id: 2, name: 'Toyota', id: 3, name: 'Dodge'];
this.selectedCar = ko.observable();

让我们用小提琴来测试一下:

var viewModel = function()
  var self = this;
  self.cars = [id: 1, name: 'Honda', id: 2, name: 'Toyota', id: 3, name: 'Dodge'];
  self.selectedCar = ko.observable(self.cars[0]);
  

;

ko.applyBindings(new viewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<select data-bind="value: selectedCar, optionsCaption: 'Select', optionsText: 'name', optionsValue:$data, options: cars"></select>

<!-- to verify that we are getting the entire object -->
<p data-bind="text: ko.toJSON(selectedCar)"></p>

【讨论】:

没有必要这样设置optionsValue,选择的项目是隐含的值。 是的,但是您将如何设置初始值并满足 OP 将 id 和 text 绑定到“selectedCar”的要求?我认为此时 optionsValue 变得很有必要。 设置optionsValue: $data 不会按照您的想法进行。 $data 在该上下文中实际上是视图模型,它不是该属性的有效值。所以实际上,它使用默认行为(选定的项目设置为值)。但是您已经正确指出,selectedCar 的初始值是通过访问数组中的实际实例正确设置的。【参考方案2】:

选择框的value 将成为与所选项目或optionsValue 参数中设置的属性相对应的对象。所以在对象的情况下,您设置的选定值必须与数组中存在的实例相同。拥有一个不同的对象实例恰好在结构上是等效的是不够的。

对于这种情况,我发现将选择框的值绑定到对象的唯一 id 会更容易。然后,您可以通过计算值将该 id 映射到您想要的实际实例。

function ViewModel(data) 
    this.cars = data.cars;
    this.selectedCarId = ko.observable(data.selectedCarId);
    this.selectedCar = ko.computed(() => 
        let selectedCarId = this.selectedCarId();
        return this.cars.find(c => c.id === selectedCarId);
    );


let model = 
    cars: [
         id: 1, name: 'Honda' ,
         id: 2, name: 'Toyota' ,
         id: 3, name: 'Dodge' 
    ],
    selectedCarId: 2
;
ko.applyBindings(new ViewModel(model), document.getElementById('content'));
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.5/js/select2.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.5/css/select2.min.css">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<div id="content">
  <select data-bind="value: selectedCarId,
                     optionsCaption: 'Select',
                     optionsText: 'name',
                     optionsValue: 'id',
                     options: cars">
  </select>
  <p>selectedCarId: <span data-bind="text: selectedCarId"></span></p>
  <p>selectedCar: <span data-bind="text: ko.toJSON(selectedCar)"></span></p>
  
  <pre data-bind="text: ko.toJSON($root, null, 2)"></pre>
</div>

如果您不想使用单独的计算属性,您仍然需要传入一个索引,但您设置的值必须从数组中获取。

function ViewModel(data) 
    this.cars = data.cars;
    this.selectedCar = ko.observable(
        data.cars.find(c => c.id === data.selectedCarId)
    );

【讨论】:

以上是关于Knockout Select2 按对象设置初始值的主要内容,如果未能解决你的问题,请参考以下文章

Knockout + Select2 - 设置默认值?

Select2 Knockout 多选设置值问题

Select2 with ajax, multiple and knockout binding 不将对象保存到 selectedOptions

Select2 4.0 和 Knockout 3.1 选择不允许选择

Knockout.js Select2 绑定。将 Select2 升级到 v4 后损坏

使用 knockout.js 和 select2 级联下拉菜单