[英]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.