Knockout二维ObservableArray编辑后数据未更新问题求助
Knockout.js 双向绑定不更新问题排查
嘿,我来帮你搞定这个问题!你遇到的是Knockout.js中嵌套ObservableArray编辑后数据看似没更新的情况,咱们一步步拆解原因和解决方案。
你的问题场景
首先先还原你的代码和问题:
原始JSON数据
{ "visualAttributes": { "stemAppearance": ["a", "b", "c", "k", "l"], "foamAppearance": ["yellow", "red", "green", "blue", "grey"], "adhesionAppearance": ["y", "y", "i", "o", "o"], "stemAngle": ["z", "x", "c", "r", "v"] } }
ViewModel 代码
self.visualAttributes = ko.observableArray([]); self.setVisualAttributes = function(visualAttributes) { for(attribute in visualAttributes) { var attr = ko.observableArray(); for(var i=0; i<visualAttributes[attribute].length; i++) { cell = ko.observable(visualAttributes[attribute][i]); attr.push(cell); } self.visualAttributes.push(attr); } }
HTML 渲染代码
<tbody data-bind="foreach : $root.visualAttributes"> <tr> <!-- ko foreach: $data --> <td><input type="text" class="form-control" data-bind="value: $data"></input></td> <!-- /ko --> </tr> </tbody>
遇到的问题
表格能正常渲染初始数值,但编辑单元格后,查看self.visualAttributes()时发现数据没有更新。
问题原因分析
这里有两个关键问题,其中一个是代码小疏漏,另一个是对Knockout Observable结构的误解:
1. 变量作用域的隐性问题
你在循环中定义cell时没有加var关键字:
cell = ko.observable(visualAttributes[attribute][i]); // 缺少var
这会导致cell成为全局变量,虽然当前可能没影响显示效果,但后续很容易引发变量污染、值被意外覆盖的问题,是需要修正的不良实践。
2. Observable结构的误解(核心问题)
你看到self.visualAttributes()里的数据没更新,其实是误解了它的存储结构:
self.visualAttributes是一个observableArray,里面的每一项又是一个observableArray- 每个内层
observableArray里的元素是单个的ko.observable()对象
当你编辑单元格时,Knockout已经把新值写回了对应的observable()对象里,但你直接打印self.visualAttributes()看到的是这些Observable对象本身,不是它们的当前值——所以才会误以为数据没更新。
解决方案
第一步:修复变量作用域问题
给cell加上var,把它变成循环内的局部变量:
self.setVisualAttributes = function(visualAttributes) { for(attribute in visualAttributes) { var attr = ko.observableArray(); for(var i=0; i<visualAttributes[attribute].length; i++) { var cell = ko.observable(visualAttributes[attribute][i]); // 添加var attr.push(cell); } self.visualAttributes.push(attr); } }
第二步:正确获取更新后的数据
如果你想拿到编辑后的普通二维数组,需要手动解包嵌套的Observable结构:
// 获取编辑后的普通数据数组 var updatedPlainData = self.visualAttributes().map(function(innerObsArray) { // 先解包内层的observableArray return innerObsArray().map(function(cellObservable) { // 再解包每个单元格的observable return cellObservable(); }); }); console.log(updatedPlainData); // 这里会输出编辑后的普通二维数组
额外优化:同步回原始JSON结构
如果你希望编辑后的数据能还原成和原始JSON一样的键值对结构,可以在ViewModel里维护一个结构化的Observable:
// 新增一个存储结构化数据的observable self.structuredVisualAttrs = ko.observable({}); self.setVisualAttributes = function(visualAttributes) { var structuredData = {}; var arrayData = []; for(var key in visualAttributes) { // 把每个数组项转成observable,再包装成observableArray var obsArray = ko.observableArray( visualAttributes[key].map(function(val) { return ko.observable(val); }) ); arrayData.push(obsArray); structuredData[key] = obsArray; } self.visualAttributes(arrayData); self.structuredVisualAttrs(structuredData); }; // 获取更新后的结构化数据 self.getUpdatedStructuredData = function() { var rawData = self.structuredVisualAttrs(); var result = {}; for(var key in rawData) { result[key] = rawData[key]().map(function(cellObs) { return cellObs(); }); } return result; };
调用self.getUpdatedStructuredData()就能得到和原始JSON结构一致的更新后数据了。
内容的提问来源于stack exchange,提问作者UIC
相关产品推荐
相关产品推荐

