javascript - Knockoutjs valueHasMutated 无法正常工作

标签 javascript mvvm knockout.js data-binding custom-binding

希望这对 knockout 大师来说是一个快速的过程......

我正在编写几个自定义绑定(bind)来帮助我在我正在处理的项目中使用自定义翻译引擎翻译 UI。

一种是翻译文本,另一种是翻译 HTML5 输入元素上的 'placeholder' 属性。

除了最后一个语句之外,这两个绑定(bind)都是相同的,其中一个更新元素中的文本,另一个更新属性值。

文本一个完美地工作,但占位符一个没有,我一直在寻找为什么的答案。

绑定(bind)代码如下:

译文装订

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

翻译后的占位符绑定(bind)
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

这个想法很简单,如果绑定(bind)运行并且翻译已经存在于 sessionStorage 中,那么我们拿起翻译后的字符串并将其插入与元素关联的可观察对象。

如果翻译已加载,但未找到翻译,则将“No Translation ID”插入到绑定(bind)到元素的 observable 中。

如果尚未加载翻译,请将一个空字符串插入 observable,然后等待事件“TranslationsLoaded”触发。引发此事件时,绑定(bind)到元素的 observable 会发生变化,导致发生更新,进而重新检查翻译,然后发现翻译已加载并因此采取相应措施。

然而.....

不管我多么努力,翻译的占位符绑定(bind)都不会触发它的更新。

我可以在调试器中清楚地看到,在两个绑定(bind)上都收到了事件,并且调用了 mutate 函数。

在翻译文本绑定(bind)上,我得到以下序列......

“初始化”->“更新”->“事件”->“变异”->“更新”

这正是我所期望的,它发生在绑定(bind)到该绑定(bind)的每个元素+可观察对象上。

在翻译的占位符上我得到

“初始化”->“更新”->“事件”->“变异”

但最终的更新永远不会发生。

结果,占位符的翻译字符串永远不会正确查找,具有相同代码的文本可以完美运行!

对于那些会问的人,我正在使用这样的绑定(bind):
<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>

在 View 模型中,'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);
},

话虽如此,我认为所有这些手动赛事对于 knockout 可以为您做的事情都是不合时宜的。你应该观察你的数据,绑定(bind)它,并让 knockout 为你做所有的内部事件......这就是它的作用。

一个建立在 user3297291 的 fiddle 上的例子:
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());

fiddle :https://jsfiddle.net/brettwgreen/5pmmd0va/

关于javascript - Knockoutjs valueHasMutated 无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37412304/

相关文章:

javascript - 如果文本内部在文档加载时换行,DIV 的高度计算不正确

javascript - 对以编程方式创建的内容强制进行拼写检查

c# - 需要帮助确定实际使用的设计模式吗? WP7

c# - DataGrid ComboBox 第一次点击时没有选中项

javascript - 使用 Knockout 将 optionsText 绑定(bind)到具有对象数组的属性?

javascript - React : If a useState is updated, 怎么可能同时不更新呢?

javascript - 在 UpdateView Django 中保存 ImageField

.net - 在代码背后使用演示模型的主要缺点是什么?

javascript - 我的返回值函数失败了——我认为与 Promise 相关

jquery-templates - 如何将 foreach 与特殊的第一个元素一起使用?