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 按对象设置初始值的主要内容,如果未能解决你的问题,请参考以下文章
Select2 with ajax, multiple and knockout binding 不将对象保存到 selectedOptions
Select2 4.0 和 Knockout 3.1 选择不允许选择