Javascript 为什么设置optionsValue会破坏淘汰更新?
我一直在看淘汰赛教程,当我在玩一个教程的时候,有些东西让我困惑。这是我的HTML:Javascript 为什么设置optionsValue会破坏淘汰更新?,javascript,html,mvvm,knockout.js,Javascript,Html,Mvvm,Knockout.js,我一直在看淘汰赛教程,当我在玩一个教程的时候,有些东西让我困惑。这是我的HTML: <h2>Your seat reservations</h2> <table> <thead><tr> <th>Passenger name</th><th>Meal</th><th>Surcharge</th> </tr></th
<h2>Your seat reservations</h2>
<table>
<thead><tr>
<th>Passenger name</th><th>Meal</th><th>Surcharge</th>
</tr></thead>
<tbody data-bind="foreach: seats">
<tr>
<td><input data-bind="value: name" /></td>
<td><select data-bind="options: $root.availableMeals, optionsValue: 'mealVal', optionsText: 'mealName', value: meal"></select></td>
<td data-bind="text: formattedPrice"></td>
</tr>
</tbody>
</table>
<button data-bind="click: addSeat">Reserve another seat</button>
当我运行此示例并从乘客下拉菜单中选择不同的“膳食”时,“附加费”值未更新。原因似乎是我将选项value:'mealVal'
添加到选择
的数据绑定
属性中,当我删除该属性时,“附加费”确实会在选择新的下拉选项时更新。但是为什么添加选项value
会破坏更新?所做的就是设置select
列表的选项value
属性,这对于表单提交非常有用-我不明白为什么它应该阻止Knockout自动更新
更新:进一步调查后,我发现仍在调用formattedPrice
fn,但self.fine()
现在解析为值字符串,如PRM
,而不是整个fine对象。但这是为什么呢?文档中说,optionsValue
设置HTML中的value
属性,但没有说明如何更改视图模型行为
我认为,当您指定
选项:$root.availableMeals
,但不指定选项值时,Knockout可以神奇地确定更改选择时在列表中所做的选择,并允许您从availableMeals
访问对象,而不仅仅是放入value
属性的字符串值。这似乎没有很好的文档记录。我认为您了解发生了什么以及为什么它会破坏您的代码,但仍在寻找关于何时实际需要使用选项value
,何时不需要的解释
何时使用选项value
绑定
比如说,您的饭菜可能已经售完,您想在availableMeals
中向服务器查询更新:
const availableMeals=ko.observearray([]);
const loadfines=()=>getfines()。然后(可用的菜单项);
const selectedMeal=ko.可观察(空);
加载膳食();
ko.applyBindings({loadfends,availableMeals,selectedMeal});
函数getfeeds(){
返回{
然后:函数(cb){
setTimeout(cb.bind(null,[{mealVal:“STD”,mealName:“Standard(sandwich)”,价格:0},{mealVal:“PRM”,mealName:“Premium(lobster)”,价格:34.95},{mealVal:“ULT”,mealName:“Ultimate(fullzebra)”,价格:290}),500);
}
}
}
刷新膳食
你已经选择了
没有选择
做一个选择,点击刷新,当新数据到达时,注意选择丢失。
好的,在查看淘汰代码后,我已经知道发生了什么-截至撰写本文时,这还没有记录
value
绑定在读取select
元素的值时,不仅仅查看元素的DOM值
现在,selectExtensions
所做的就是为select
(及其子object
)元素实现特殊的行为,这并不奇怪。这就是神奇发生的地方,因为正如代码中的注释所说:
// Normally, SELECT elements and their OPTIONs can only take value of type 'string' (because the values
// are stored on DOM attributes). ko.selectExtensions provides a way for SELECTs/OPTIONs to have values
// that are arbitrary objects. This is very convenient when implementing things like cascading dropdowns.
因此,当值绑定尝试读取select
元素时,会出现以下代码:
case 'select':
return element.selectedIndex >= 0 ? ko.selectExtensions.readValue(element.options[element.selectedIndex]) : undefined;
这基本上是说“好的,找到所选索引并再次使用此函数读取该索引处的选项
元素。然后它读取选项
元素并得出以下结论:
case 'option':
if (element[hasDomDataExpandoProperty] === true)
return ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey);
return ko.utils.ieVersion <= 7
? (element.getAttributeNode('value') && element.getAttributeNode('value').specified ? element.value : element.text)
: element.value;
是的,正如我所怀疑的,Knockout是在后台存储复杂的数据,但只有当您要求它存储复杂的JS对象时才这样做。这解释了为什么,当您不指定optionsValue:[someStringValue]
,您的计算函数接收到复杂的膳食对象,而当您指定它时,您只需要传入基本字符串-Knockout只是从选项的值属性中提供字符串
就我个人而言,我认为这应该被清楚地记录下来,因为这是一个有点意外和特殊的行为,可能会让人困惑,即使它很方便。我会要求他们将其添加到文档中。文档中有一个简短的段落解释选项value
。”通常,您只希望使用optionsValue作为一种方法,以确保在更新可用选项集时KO可以正确保留选择。“如果您自己的更新回答了您的问题,我建议将其作为答案发布。如果您还有任何问题,请告诉我/我们还有什么尚不清楚。这仍然不清楚,因为它没有解释为什么在设置optionsValue
时,formattedPrice
函数会从传递整个用餐对象变为只传递optionsValue
值。为什么它不能继续得到整个用餐对象?我看不出你在哪里用
绑定重写了?是的,添加代码片段确实会有帮助。很高兴看到您深入到源代码中,并找到了确切的行为!就个人而言,我希望看到选项值
被选项平等比较程序
绑定所取代:传递一个(a,b)->布尔值的函数
,该函数用于将值
与选项
的元素相匹配。
case 'option':
if (element[hasDomDataExpandoProperty] === true)
return ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey);
return ko.utils.ieVersion <= 7
? (element.getAttributeNode('value') && element.getAttributeNode('value').specified ? element.value : element.text)
: element.value;
switch (ko.utils.tagNameLower(element)) {
case 'option':
if (typeof value === "string") {
ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, undefined);
if (hasDomDataExpandoProperty in element) { // IE <= 8 throws errors if you delete non-existent properties from a DOM node
delete element[hasDomDataExpandoProperty];
}
element.value = value;
}
else {
// Store arbitrary object using DomData
ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, value);
element[hasDomDataExpandoProperty] = true;
// Special treatment of numbers is just for backward compatibility. KO 1.2.1 wrote numerical values to element.value.
element.value = typeof value === "number" ? value : "";
}
break;