gpt4 book ai didi

javascript - knockout 的交叉更新问题

转载 作者:行者123 更新时间:2023-12-03 11:03:51 24 4
gpt4 key购买 nike

我遇到了 knockout 的“交叉更新”问题。以下函数('self.applyTagsAllocation')会导致一些奇怪的效果。第 3 行:'scenetag.sceneID = scene.sceneID;'正在更新“tag.sceneID”以及本地场景标签变量。我真的无法理解为什么 sceneID 永远不是可观察的。

self.applyTagsAllocation = function (tag) {
var scenetag = tag;
var scene = self.selectedScene();
scenetag.sceneID = scene.sceneID;
scene.sceneTags.push(scenetag);
};

这是我的 View 模型的更完整列表:

var Tag = function (data) {
var self = this;
self.ID = data.ID || -1;
self.sceneID = data.sceneID;
self.text = ko.observable((data.text || 'new').trim());
self.tagType = ko.observable(data.tagType || -1 );
}

var Scene = function(data){
var self = this;
self.sceneID = data.sceneID;
self.sceneTags = ko.observableArray();

self.tags = ko.computed({
read: function () {
var tags = [];
tags.push.apply(tags, self.sceneTags());
return tags;
},
write: function (tag) {
this.sceneTags.push(tag);
},
owner: self
});
};

var ViewModel = function (model){
var self = this;

self.selectedScene = ko.observable();
self.sceneTags = ko.observableArray();

self.Scenes = ko.observableArray(
ko.utils.arrayMap(model, function (item) {
return new Scene(item);
}));

self.sceneTags = ko.computed(function () {
var tags = [];
ko.utils.arrayForEach(self.Scenes(), function (scene) {
tags.push.apply(tags, scene.tags());
});
return tags;
});


//Tag is first created with:
self.addSceneTag = function (name, type) {
if (!type) type = -1;
var newtag = new Tag({
ID: -1,
sceneID: self.selectedScene().sceneID,
text: name,
tagType: type
});

// already in use?
var abort = false;
ko.utils.arrayForEach(self.selectedScene().sceneTags(), function (tag) {
if (tag.text() === newtag.text()) abort = true;
});
if (!abort) self.selectedScene().sceneTags.push(newtag);
};

self.applyTagsAllocation = function (tag) {
var scenetag = tag;
var scene = self.selectedScene();
scenetag.sceneID = scene.sceneID;
scene.sceneTags.push(scenetag);
};
};

(你可能想知道为什么“Scene”同时具有 sceneTags 数组和标签数组。这是因为我在这个示例中进行了简化。在我的项目中,我有另一个标签类型,并且这两种类型被合并一起在 View 模型范围内。)

HTML

标签首先设置为:

<input class="taginput"  placeholder="&lt;add a tag&gt;" data-bind="textInput: tagname, event: {keyup: $root.inputTag}" />

然后,当标签存在时,我想将其添加到“foreach:标签”范围内的另一个“场景”中:

 <span data-bind="visible: sceneID  !== null &&  sceneID !== $root.selectedScene().sceneID, click: function(){$root.applyTagsAllocation($data)};">Add Tag</span>

这里实际的 foreach 是 knockout 排序中的一个循环(来自 Ryan Niemeyer):

<div class="tag-list" data-bind="sortable:{template:'tagsTmpl',data:$root.sceneTags"></div>

什么可能导致此情况?任何提示和线索都非常感谢!

提前致谢!

最佳答案

再看一下这个函数;在您看来,您将标签的 $data 绑定(bind)到 self.applyTagsAllocation 函数,这实际上就是执行此操作 =>

self.applyTagsAllocation = function (tag) {
var scenetag = tag; // scenetag == instance of Tag you passed ( $data )
var scene = self.selectedScene(); // scene == the selected instance of Tag
scenetag.sceneID = scene.sceneID; //!!!! This line says:
// 'Make sceneID of this instance = sceneID of the selected instance'
scene.sceneTags.push(scenetag); // will fail, you can't write to a simple computed
};

所以,是的,它更新了局部变量,但局部变量指向您的 Tag viewModel,因此它更新了对象。. 与您可能(似乎)认为的不同,分配一个对象到另一个变量不会克隆它;仅供引用。

不如这样做:

self.applyTagsAllocation = function (tag) {
var scenetag = {};
// clone an object, for whatever strange reason one could have:
for (var prop in tag) {
scenetag[prop] = tag[prop];
} // now you have a copy of the tag instance you passed [..] rest of function
};

或者,如果您想将标签设置为选定状态,我认为这更合乎逻辑:
函数中的 self.selectedScene(tag)

重要:您已经分配了 self.sceneTags 两次,第二次它是计算的可观察量。您无法写入计算的可观察量(在 applyTagsAllocation 中推送到它),那么您需要 pureCompulated..

关于javascript - knockout 的交叉更新问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27954419/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com