【问题标题】:Passing input element's value as a parameter to a viewmodel function将输入元素的值作为参数传递给视图模型函数
【发布时间】:2017-09-24 07:07:39
【问题描述】:

input 控件的value 传递给视图模型函数的语法是什么(假设有)?在我的场景中,我对将输入的值绑定到视图模型上的属性不感兴趣。我只需要对输入到输入控件中的值进行操作(基本上我正在遍历一组项目并过滤掉那些不包含输入文本的项目)。

<input data-bind="text: filterText($data), valueUpdate: 'afterkeydown'">

我已经尝试过filterText($data, value),但 Knockout 正在尝试在视图模型上找到 value 属性。我实际上需要输入控件的当前值。

这可能吗?

【问题讨论】:

    标签: knockout.js


    【解决方案1】:

    处理此用例的典型方法是使用textInput 绑定和对调用filterText 的绑定值的订阅。

    <input data-bind="textInput: filter">
    

    在您的脚本中:

    filter.subscribe(function(newValue) {
        filterText(newValue)
    });
    

    你可以简化为:

    filter.subscribe(filterText);
    

    但是您可能仍然在考虑这个错误。您的过滤列表应该是一个计算值,它引用 textInput-bound filter 值来计算过滤列表。

    filteredList = ko.pureComputed(function() {
        // return the list filtered by the bound filter() value
    }, self);
    

    然后,您可以在需要过滤数据列表的任何地方使用filteredList()

    【讨论】:

      【解决方案2】:

      首先要做的事情。您的示例代码在 input 节点上使用 a text binding,这并不是那么有用(这意味着从视图模型到 DOM 的 单向 绑定,即“文本”内容input 没有意义)。鉴于存在valueUpdate 绑定,您可能是指the value binding?注意the textInput binding 是在现代版本的 KnockoutJS 中结合这两者的方式。

      至于你的实际问题,缺少重要的背景:为什么你(认为你)想要这样做?根据具体情况,解决方案会有所不同,或者您甚至可能拥有XY-problem

      无论如何,答案。

      选项 1
      尽管如此,为了回答具体问题,我第二次 @JohnnyHK's answer 在您的 observable 上写一个 .subscribe 作为一种可能的解决方案。

      选项 2
      另一种可能的解决方案与该解决方案非常相似,但试图满足“我对输入的值不感兴趣”部分,我建议使用只读计算的 observable:

      function Root() {
        var self = this;
        
        self.filter = ko.computed({
          read: function() { return ""; }, // <-- not recommended, read context!
          write: function(newValue) {
            // You're free to discard the newValue   <-- not recommended, read context!
            alert("Input has been changed.");
          }
        });
      }
      
      ko.applyBindings(new Root());
      <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
      <input data-bind="textInput: filter">

      现在这会显式丢弃写入位中的newValue(根据您的要求),因此还有一个看起来很奇怪的read 函数。 我不建议这样做,而是建议使用带有支持 observable 的私有变量来进行读写。但实际上,这将使该选项等同于其他答案中的第一个选项。

      一个有趣的注释,你的问题是关于“收集器”和过滤输入的:如果你看一下the docs from writeable computeds,你会发现如果它满足某个条件 ,是否接受用户输入> 实际上是一个用例。

      选项 3
      我会推荐什么,如果我稍微改一下您的要求:

      当您的操作不关心实际的 value 时,您如何对使用惯用 KnockoutJS 的 input value 更改做出反应?

      对于编写与 DOM 的自定义交互,有 custom binding handlers。您可以拥有一个根本不使用 ViewModel 的模型,也可以拥有一个具有 observable 的模型。

      选项 3.A

      ko.bindingHandlers["opacitor"] = {
        init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
          $(element).on("keydown", function() {
            $(this).animate({ opacity: 0.05 }, 1000, function() { $(this).animate({ opacity: 1.0 }, 1000); });
          });
        }
      }
      
      ko.applyBindings({});
      input { background-color: gold; }
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
      
      <input data-bind="opacitor">

      选项 3.B
      或者使用视图模型的第二个选项:

      ko.bindingHandlers["opacitor"] = {
        init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
          $(element).on("keydown", function() {
            var speed = ko.utils.unwrapObservable(valueAccessor)();
            $(this).animate({ opacity: 0.05 }, speed, function() { $(this).animate({ opacity: 1.0 }, speed); });
          });
        }
      }
      
      // speed1 and speed2 could also be observables
      ko.applyBindings({ speed1: 500, speed2: 2000 });
      input { background-color: gold; }
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
      
      <input data-bind="opacitor: speed1">
      <input data-bind="opacitor: speed2">

      选项 3A 和 3B 的缺点是您需要编写自定义事件处理逻辑。如果您查看the textInput source from KO,您会发现跨浏览器正确处理这些事情并非易事。所以使用选项 1 或 2 可能仍然更好(即使“你不感兴趣”,你也会有一些视图模型交互)。

      选项 4
      使用the event binding。这具有与选项 3 相同的缺点,但仍然可能是一个简单的解决方案。这是一个例子:

      function Root(){
        var self = this;
        self.myFn = function(data, element) {
          console.log(element.target.value);
          return true;
        };
      }
      
      ko.applyBindings(new Root());
      <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
      <input data-bind="event: { keyup: myFn }">

      您将在最后一个中看到一个微妙的变化,以及一个我想结束的问题:您实际上是否没有 this issue,您实际上需要 new 值,因此不应该看afterkeydown,而是看不同的事件?

      【讨论】:

        【解决方案3】:

        使用 $element.value 访问输入的值。

        【讨论】:

          【解决方案4】:

          如果您没有将属性绑定到视图模型,那么您可以使用 jquery/javascript 通过执行类似的操作直接在您的视图模型函数中获取该输入控件的值。

          self.Filter= function () {           
             var filter = $('#textBoxID').val();
             //    
          }
          

          这样您就不需要将值传递给您的视图模型函数参数。

          【讨论】:

          • 这不适用于 OP 的视图代码,它具有 text 绑定。此外,假设一个value 绑定,这个解决方案在技术上是可行的,但它根本不是惯用的 KnockoutJS,它依赖于 KO 内部工作方式的副作用,并且在我的经验中会导致问题。
          • 但是这家伙说“在我的场景中,我对将输入的值绑定到视图模型上的属性不感兴趣。”我相信我的解决方案适用于他的场景。
          • 发布的代码does not work with OP's view。修复所有问题后(缺少id,将text 更改为value,将filter 更改为Filter),应该包含在答案中的修复,it'll work,它可能会解决 OP 的问题,但恕我直言,从长远来看,这将是非惯用的 knockoutjs 代码,这将导致问题,因此是不好的建议。 other answer(有订阅)是更好的建议,我也试图在我的回答中展示一些更好的选择。
          猜你喜欢
          • 1970-01-01
          • 2020-12-23
          • 2017-10-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-05-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多