【问题标题】:Knockout JS: Working with old validation code that changes the DOMKnockout JS:使用更改 DOM 的旧验证代码
【发布时间】:2012-12-09 07:09:55
【问题描述】:

查看底部的编辑。

我的公司拥有庞大的代码库,我们希望开始更有效地使用淘汰赛。但是,我们已经有验证代码来处理客户端验证的所有方面。它使用 jQuery 来显示验证错误消息并清理用户输入。

例如,如果我将“validate-range”类添加到输入,它将使用 jQuery 更改/聚焦事件来跟踪更改,然后如果值超出范围,它将用 min/ 替换它使用 $(input).val() 的最大值。由于此验证代码以编程方式进行更改,因此在进行此类更改时不会更新我的淘汰视图模型。

这个验证码在系统中随处使用,暂时不能替换,所以为了使用knockout,我必须让它和这个代码一起工作。到目前为止,我尝试的是创建一个自定义值绑定,它添加了一个额外的更改事件处理程序,用于在验证代码更改输入值时更新视图模型。

这在所有情况下都非常有效,除了在 foreach 绑定中(这与我想象的使用模板/with 绑定相同)。我的更改事件处理程序不会在 foreach 内使用自定义值绑定的任何输入上被触发,即使每次可观察数组更改时自定义绑定都会重新应用于 foreach 内的所有输入。

我希望以前有人处理过这个问题,不得不使用现有的 javascript 代码进行淘汰工作,这些代码会更改 DOM 值,因此不会更新视图模型。非常感谢任何帮助。

用于自定义绑定、创建视图模型和旧验证代码的 Javascript 代码:

// custom value binding for amounts
ko.bindingHandlers.amountValue = {
  init: function (element, valueAccessor) {
    var underlyingObservable = valueAccessor(),

        interceptor = ko.computed({
          read: function () {
            var value = underlyingObservable();
            return formatAmount(value);
          },

          write: function (newValue) {
            var current = underlyingObservable(),
                valueToWrite = parseAmount(newValue);

            if (valueToWrite !== current)
              underlyingObservable(valueToWrite);
            else if (newValue !== current.toString())
              underlyingObservable.valueHasMutated();
          }
        });

    // i apply a change event handler when applying the bindings which calls the write function of the interceptor.
    // the intention is to have the change handler be called anytime the old validation code changes an input box's value via 
    // $(input).val("new value"); In the case of the foreach binding, whenever the observable array changes, and the table rows
    // are re-rendered, this code does get ran when re-applying the bindings, however the change handler doesn't get called when values are changed.
    ko.applyBindingsToNode(element, { value: interceptor, event: { change: function () { interceptor($(element).val()); } } });
  }
};

// view model creation
// auto create ko view model from json sent from server
$(function () {
  viewModel = ko.mapping.fromJS(jsonModel);
  ko.applyBindings(viewModel);
});

// old validation code
$(document).on("focusout", ".validate-range", function () {
  var $element = $(this),
      val = $element.val(),
      min = $element.attr("data-val-range-min"),
      max = $element.attr("data-val-range-max");

  if (val < min)
    // my change handler from custom binding doesn't fire after this to update view model
    $element.val(min);

  if (val > max)
    // my change handler from custom binding doesn't fire after this to update view model
    $element.val(max);

  // more code to show error message
});

在 foreach 绑定中使用自定义绑定的 HTML 代码:

<table>
  <thead>
    <tr>
      <td>Payment Amount</td>
    </tr>
  </thead>
  <tbody data-bind="foreach: Payments">
    <tr>
      <td><input type="text" class="validate-range" data-val-range-min="0" data-val-range-max="9999999" data-bind="amountValue: Amount" /></td>
    </tr>
  </tbody>
</table>

所以在上面的例子中,如果我在金额文本框中输入“-155”,我的自定义绑定就会运行并将视图模型金额设置为 -155。然后旧验证运行并使用 $(input).val(0) 将文本框的值重新设置为“0”。我的视图模型此时没有更新,仍然反映 -155 值。我的自定义绑定中的更改事件处理程序应该运行以将视图模型更新为 0,但它没有。

编辑:

正如答案中所指出的, .val() 不会触发任何更改事件。我添加的更改事件处理程序没有做任何事情。当验证代码更改 foreach 绑定之外的值时,视图模型被更新的原因是我们的 javascript 代码中的其他地方有逻辑,该逻辑使用模糊事件手动触发更改事件,这反过来又触发了我的自定义绑定运行和更新视图模型。这个模糊事件处理程序直接绑定到文本框,而不是被委托,因此它适用于页面首次呈现时存在的文本框,但不适用于由 foreach 绑定动态插入的文本框。

目前,我只是更改了此逻辑以委派文档中的事件,因此它将包括动态插入的文本框,而且它似乎工作正常。我希望将来能提出更好的解决方案。

【问题讨论】:

  • 介意发布一个示例自定义处理程序和一些示例模型/html 代码以使其更具体一点吗?

标签: javascript jquery knockout.js knockout-mapping-plugin knockout-2.0


【解决方案1】:

调用$(element).val("some value"); 不会触发更改事件。

您需要这样做:$(element).val("some value").change();

【讨论】:

  • 为什么这种方法适用于我在 foreach 绑定之外的所有字段?
  • 编辑:Nm...看来我添加的更改事件处理程序没用。我把它拿出来,一切仍然以同样的方式工作。对于 foreach 之外的所有输入,视图模型会在验证代码更改值时更新,而不会为 foreach 内的输入更新。
  • 这仍然给我留下了一个问题,即当验证代码使用 $(input).val("some value") 更改值时,为什么要更新视图模型。我的印象是,如果您以编程方式更改任何值而不使用可观察对象,则视图模型将不会更新。
  • 你能得到一些基本的东西来证明你在 jsFiddle 中的问题吗?听起来change 事件正在被某些东西触发($.val 不会触发它)。关于foreach 需要注意的一件事是它将原始子元素复制为“模板”。如果您在应用绑定之前向其添加处理程序,则处理程序将不起作用。
  • 对,这就是为什么我在调用 applybindingstonnode 时在自定义绑定中应用了我的处理程序。旧的验证代码使用 $.on 应用它的处理程序,因此它跟踪动态添加的 DOM 元素。
猜你喜欢
  • 1970-01-01
  • 2013-03-21
  • 2014-07-27
  • 1970-01-01
  • 1970-01-01
  • 2012-02-29
  • 1970-01-01
  • 2015-12-25
相关资源
最近更新 更多