Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/468.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 敲除JS值已发生突变,无法正常工作_Javascript_Mvvm_Knockout.js_Data Binding_Custom Binding - Fatal编程技术网

Javascript 敲除JS值已发生突变,无法正常工作

Javascript 敲除JS值已发生突变,无法正常工作,javascript,mvvm,knockout.js,data-binding,custom-binding,Javascript,Mvvm,Knockout.js,Data Binding,Custom Binding,希望这将是一个击倒大师快速之一 我正在编写两个自定义绑定,以帮助我在正在处理的项目中使用自定义翻译引擎翻译UI 一个是翻译文本,另一个是翻译HTML5输入元素上的“占位符”属性 除了最后一条语句外,这两个绑定是相同的,其中一个更新元素中的文本,另一个更新属性值 文本一的效果很好,但占位符一的效果不好,我一直在寻找答案 绑定代码如下: 译文装订 翻译的占位符绑定 这个想法很简单,如果绑定运行并且翻译已经存在于sessionStorage中,那么我们提取翻译后的字符串并将其插入到与元素关联的可观察对

希望这将是一个击倒大师快速之一

我正在编写两个自定义绑定,以帮助我在正在处理的项目中使用自定义翻译引擎翻译UI

一个是翻译文本,另一个是翻译HTML5输入元素上的“占位符”属性

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

文本一的效果很好,但占位符一的效果不好,我一直在寻找答案

绑定代码如下:

译文装订

翻译的占位符绑定

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

如果已加载翻译,但未找到翻译,“无翻译ID”将插入到元素的可观察绑定中

如果尚未加载转换,请将空字符串插入可观察对象,然后等待事件“TranslationLoaded”触发。当引发此事件时,绑定到元素的可观察对象会发生变化,导致发生更新,而更新又会重新检查翻译,然后发现翻译已加载,并相应地执行操作

然而

不管我怎么努力,翻译后的占位符绑定都不会触发它的更新

我可以在调试器中清楚地看到,在两个绑定上都接收到了事件,并且调用了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>
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);
},
associatedObservable(translatedText);
associatedObservable();  // get notified of updates to associatedObservable
element.setAttribute("placeholder", translatedText);

在视图模型中,“可观测”参数只是普通的可观测变量,包含字符串

干杯
肖蒂

我相信你有一些冒泡事件。。。尝试在对Values的调用发生以下变化后输入“return true”:

<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>
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);
},
associatedObservable(translatedText);
associatedObservable();  // get notified of updates to associatedObservable
element.setAttribute("placeholder", translatedText);
也就是说,我认为所有这些手动事件都与击倒能为你做什么背道而驰。你应该观察你的数据,绑定到它,让敲除为你做所有的内部事件。。。它就是这样做的

在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());
Fiddle:

触发更新处理程序 从:

当绑定应用于元素时,Knockout将首先调用
update
回调,并跟踪您访问的任何依赖项(可观察项/计算项)。当这些依赖项中的任何一个发生更改时,将再次调用
update
回调

关键是您必须访问
update
函数中的observable来获取更新。在
translatedText
绑定中,您可以执行以下操作:

ko.utils.setTextContent(element, associatedObservable());
但是在
translatedPlaceholder
update
功能中没有对
关联的可观察的
的访问。您需要像这样添加它:

<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>
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);
},
associatedObservable(translatedText);
associatedObservable();  // get notified of updates to associatedObservable
element.setAttribute("placeholder", translatedText);
更好的方法 对于您的情况,实际上不需要
update
处理程序,因为您不需要根据对viewmodel的更改来更新视图。相反,您的更新只来自事件,可以在
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'"

我试图用简化的小提琴复制你的问题,但无法复制。你能帮我找出我做了什么不同吗?你的代码看起来和我的一样,或者至少重要的部分是一样的。然而,在我的项目中,包括绑定扩展在内的所有内容都使用模块加载器。一年多后,所有内容都是使用RequireJS加载的,我收到一个通知,这个问题已经有1000次访问,所以我得到了一个徽章:-),不过我还是要道歉。在我写这篇文章大约3天后,我被转移到另一个项目(非技术经理就是他们)。结果,这件事被完全忘记了,从那时起,我不再为我写这篇文章时所在的公司签约,所以我不知道是否找到了答案,我当然从来没有得出任何可靠的结论,但是,因此我认为它将永远处于不确定状态……经过更仔细的检查,如果你想坚持己见,我认为你有一个事件冒泡的问题。第一个处理程序吃掉事件而不让它冒泡到下一个。在事件处理程序函数中的值发生变化后,尝试返回true。谢谢brett,我将尝试一下。不幸的是,我不得不依赖这种类型的事件处理,因为KO模型实际上是KO组件,而事件源来自使用绑定的组件之外。我要补充的是,您可能会使此绑定比需要的更复杂。我不清楚你为什么需要可观察的。如果将翻译代码移动到
init
代码中的某个函数,您可以先调用它,然后在获得
translationsload
事件时调用它。嗨,Michael,我之所以这样做是为了绑定,是因为我对这项工作的规范明确规定,所有翻译都必须经过相同的代码位,更重要的是,“translationTokens”需要存在于HTML中,设计师可以在HTML中找到它们,而无需阅读任何JS代码(设计团队由不懂JS的人组成)。在项目中