[英]Knockoutjs valueHasMutated not working correctly
希望这对于淘汰赛大师来说是个快速的选择。
我正在编写几个自定义绑定,以帮助我在正在处理的项目中使用自定义翻译引擎来翻译UI。
一种是翻译文本,另一种是翻译HTML5输入元素上的“占位符”属性。
除最后一条语句外,这两个绑定是相同的,在最后一条语句中,一个绑定更新元素中的文本,另一个绑定更新属性值。
文本一个完美地工作,但是占位符一个不工作,我被迫寻求一个答案。
绑定代码如下:
翻译文字绑定
ko.bindingHandlers.translatedText = {
init: (element: HTMLElement, valueAccessor: Function, allBindings: KnockoutAllBindingsAccessor, viewModel: any, bindingContext: KnockoutBindingContext) => {
// Get our custom binding values
var value = valueAccessor();
var associatedObservable = value.observable;
var translationToken = value.translationToken;
// Set up an event handler that will respond to events telling it when our translations have finished loading
// the custom binding will instantly update when a key matching it's translation ID is loaded into the
// local session store
window.addEventListener("TranslationsLoaded", (e) => {
//associatedObservable(" "); // Force an update on our observable, so that the update routine below is triggered
associatedObservable.valueHasMutated();
}, false);
},
update: (element: HTMLElement, valueAccessor: Function, allBindings: KnockoutAllBindingsAccessor, viewModel: any, bindingContext: KnockoutBindingContext) => {
// Get our custom binding values
var value = valueAccessor();
var associatedObservable = value.observable;
var translationToken = value.translationToken;
// Ask local storage if we have a token by that name
var translatedText = utilityLib.getTranslatedString(translationToken);
// Check if our translated text is defined, if it's not then substitute it for a fixed string that will
// be seen in the UI (Whatever you put into the 'associatedObservable' at this point WILL appear in the element
if (undefined === translatedText || translatedText === "" || translatedText === null) {
if (sessionStorage["translations"] === undefined) {
// No translations have loaded yet, so we blank the text
translatedText = "";
} else {
// Translations have loaded, and the token is still not found
translatedText = "No Translation ID";
}
}
associatedObservable(translatedText);
ko.utils.setTextContent(element, associatedObservable());
}
} // End of translatedText binding
翻译的占位符绑定
ko.bindingHandlers.translatedPlaceholder = {
// This one works pretty much the same way as the translated text binding, except for the final part where
// the translated text is inserted into the element.
init: (element: HTMLElement, valueAccessor: Function, allBindings: KnockoutAllBindingsAccessor, viewModel: any, bindingContext: KnockoutBindingContext) => {
var value = valueAccessor();
var associatedObservable = value.observable;
var translationToken = value.translationToken;
window.addEventListener("TranslationsLoaded", (e) => {
debugger;
associatedObservable.valueHasMutated();
}, false);
},
update: (element: HTMLElement, valueAccessor: Function, allBindings: KnockoutAllBindingsAccessor, viewModel: any, bindingContext: KnockoutBindingContext) => {
var value = valueAccessor();
var associatedObservable = value.observable;
var translationToken = value.translationToken;
var translatedText = utilityLib.getTranslatedString(translationToken);
debugger;
if (undefined === translatedText || translatedText === "" || translatedText === null) {
if (sessionStorage["translations"] === undefined) {
translatedText = "";
} else {
translatedText = "No Translation ID";
}
}
associatedObservable(translatedText);
element.setAttribute("placeholder", translatedText);
}
} // End of translatedPlaceholder binding
这个想法很简单,如果绑定运行并且转换已经存在于sessionStorage中,那么我们将选择转换后的字符串并将其插入与元素关联的observable中。
如果已加载翻译,但未找到翻译,则将“无翻译ID”插入到元素的可观察范围内。
如果尚未加载翻译,则将一个空字符串插入可观察对象,然后等待事件“ TranslationsLoaded”触发。 引发此事件时,元素的可观察绑定发生突变,从而导致更新发生,更新又重新检查翻译,然后发现翻译已加载并因此采取相应措施。
然而.....
不管我多么努力,翻译后的占位符绑定都不会触发它的更新。
我可以在调试器中清楚地看到两个绑定都接收到该事件,并且调用了mutate函数。
在翻译的文本绑定上,我得到以下序列...
'init'->'update'->'event'->'mutate'->'update'
这正是我所期望的,它发生在该绑定的每个元素+可观察到的绑定上。
在翻译后的占位符上,我得到
'init'->'update'->'event'->'mutate'
但是最终更新永远不会发生。
结果,占位符的翻译后的字符串永远不会正确查找,具有相同代码的文本可以完美地工作!
对于那些会问的人,我正在使用这样的绑定:
<input type="text" class="form-control" data-bind="value: userName, translatedPlaceholder: { observable: namePlaceHolderText, translationToken: 'loginBoxNamePlaceholderText'}">
<span class="help-block" data-bind="translatedText: {observable: nameErrorText, translationToken: 'loginBoxUserNameEmptyValidationText'}"></span>
在视图模型内部,“ observable”参数只是保存字符串的普通ko.observable变量。
干杯
我相信您有事件冒泡的问题...在调用valueHasMutated之后,尝试将“ return true”设置为:
init: (element: HTMLElement, valueAccessor: Function, allBindings: KnockoutAllBindingsAccessor, viewModel: any, bindingContext: KnockoutBindingContext) => {
var value = valueAccessor();
var associatedObservable = value.observable;
var translationToken = value.translationToken;
window.addEventListener("TranslationsLoaded", (e) => {
associatedObservable.valueHasMutated();
return true; // allow event to bubble
}, false);
},
话虽这么说,我认为所有这些手动事件都与淘汰赛可以为您带来的好处相悖。 您应该观察数据,将其绑定,并让敲除为您完成所有内部事件……这就是它的作用。
以user3297291的小提琴为基础的示例:
ko.bindingHandlers.translatedPlaceholder = {
init: function(element, valueAccessor) {
var va = valueAccessor();
var obs = ko.utils.unwrapObservable(va.obs);
var placeholderStr = obs[va.key];
console.log(placeholderStr);
element.setAttribute("placeholder", placeholderStr);
},
update: function(element, valueAccessor) {
var va = valueAccessor();
var obs = ko.utils.unwrapObservable(va.obs);
var placeholderStr = obs[va.key];
console.log(placeholderStr);
element.setAttribute("placeholder", placeholderStr);
}
};
var vm = function() {
var self = this;
self.dictionary = ko.observable({
"placeholder": "Initial State"
});
self.switchTranslations = function() {
// Set the 'new' dictionary data:
self.dictionary({
"placeholder": "My Translated Placeholder"
});
};
}
ko.applyBindings(new vm());
从淘汰赛文档中 :
当绑定应用于元素时,Knockout会首先调用
update
回调,并跟踪您访问的所有依赖项(可观察对象/计算对象)。 当这些依赖项中的任何一个发生更改时,将再次调用update
回调。
关键是您必须访问update
函数中的observable才能获取更新。 在您的translatedText
绑定中,您可以这样做:
ko.utils.setTextContent(element, associatedObservable());
但是,在translatedPlaceholder
的update
函数中没有对associatedObservable
访问。 您需要像这样添加它:
associatedObservable(translatedText);
associatedObservable(); // get notified of updates to associatedObservable
element.setAttribute("placeholder", translatedText);
对于您的情况,确实不需要update
处理程序,因为您不需要基于对视图模型的更改来更新视图。 相反,您的更新仅来自事件,可以在init
处理程序中进行设置。
ko.bindingHandlers.translatedPlaceholder = {
init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
function loadTranslation() {
var translationToken = valueAccessor(),
translatedText = utilityLib.getTranslatedString(translationToken);
element.setAttribute("placeholder", translatedText || "No Translation ID");
window.removeEventListener("TranslationsLoaded", loadTranslation);
}
if (sessionStorage["translations"] === undefined)
window.addEventListener("TranslationsLoaded", loadTranslation, false);
} else {
loadTranslation();
}
}
}
用法:
data-bind="value: userName, translatedPlaceholder: 'loginBoxNamePlaceholderText'"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.