【问题标题】:knockout subscription not working淘汰订阅不起作用
【发布时间】:2016-08-10 00:05:46
【问题描述】:

我一直在尝试订阅下拉值何时更改。我有以下逻辑,但我似乎无法让它工作。

HTML

            <div id="case-pin-@modelItem.CaseID" data-caseid="@modelItem.CaseID" class="row hidden popovercontainer pinBinding">
                <select data-bind="options:userPins,
                        value:selectedPin,
                        optionsCaption:'-- please select --',
                        optionsText: 'Name',
                        optionsValue: 'Id'"></select>
            </div>

JS

function UserPinViewModel(caseId) {
    var self = this;
    self.selectedPin = ko.observable();
    self.userPins = ko.observableArray([]);
    self.caseId = caseId;

    self.selectedPin.subscribe(function (newValue) {
        console.log(newValue);
        //addCaseToPin(newValue, self.caseId);
    });
}

var pinObjs = [];

$(function () {
    pinObjs = [];

    $(".pinBinding").each(function () {
        var caseId = this.getAttribute("data-caseid");
        var view = new UserPinViewModel(caseId);
        pinObjs.push(view);

        ko.cleanNode(this);
        ko.applyBindings(view, this);
    });
})

userPins 数组由对服务器的 AJAX 调用填充,因为下拉列表中的值取决于网站的另一个部分,该部分可以更改下拉列表中的值 - 这里是我用来填充数组的逻辑。

function getPins() {
    $.ajax({
        type: 'POST',
        url: '/Home/GetPins',
        success: function (data) {
                for (var i = 0; i < pinObjs.length; i++) {
                    pinObjs[i].userPins(data);
                }
        },
        error: function (request, status, error) {
            alert("Oooopppppsss! Something went wrong - " + error);
        }
    });
}

下拉列表中的实际值都会更改以匹配从服务器返回的值,但是每当我手动更改下拉列表时,都不会触发订阅事件。

【问题讨论】:

  • 所以你没有在console.log上得到任何东西?你可以发布小提琴吗?
  • 它在这里工作jsfiddle.net/kyr6w2x3/39
  • 是的 - 我也让它在小提琴中孤立地工作,但是使用完全相同的逻辑,它在它实现的主应用程序中不起作用

标签: javascript knockout.js


【解决方案1】:

您同时使用 jQuery 和 Knockout 来操作 DOM,这不是一个好主意。 Knockout 的整个想法是你不操纵 DOM,它会。你操纵你的 viewModel。

使用cleanNode 也是一种代码异味,表明你做事的方式不对。如果您使用 Knockout 提供的工具,Knockout 会处理这个问题。

在这种情况下,我将建议一个自定义绑定处理程序,但看起来您真正想要的只是创建一个 UserPinViewModel 对象并将其应用于 HTML 中 .pinBinding 元素的每个实例。如果您在 viewModel 中公开 UserPinViewModel 构造函数,则可以使用 with binding 执行此操作。

function UserPinViewModel(caseId) {
  var self = this;
  self.selectedPin = ko.observable();
  self.userPins = ko.observableArray([]);
  self.caseId = caseId;

  self.selectedPin.subscribe(function(newValue) {
    console.log(newValue);
    //addCaseToPin(newValue, self.caseId);
  });

  // Pretend Ajax call to set pins
  setTimeout(() => {
    self.userPins([{
      Name: 'option1',
      Id: 1
    }, {
      Name: 'option2',
      Id: 2
    }, {
      Name: 'option3',
      Id: 3
    }])
  }, 800);

  // Later, the options change
  setTimeout(() => {
    self.userPins([{
      Name: 'animal1',
      Id: 'Elephant'
    }, {
      Name: 'animal2',
      Id: 'Pony'
    }, {
      Name: 'animal3',
      Id: 'Donkey'
    }])
  }, 4000);

}

ko.bindingHandlers.pin = {
  init: () => null,
  update: () => null
};

ko.applyBindings({
  pinVm: UserPinViewModel
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div id="case-pin-@modelItem.CaseID" data-bind="with: new pinVm('someCaseId')" class="row hidden popovercontainer pinBinding">
  <select data-bind="options:userPins,
                     value:selectedPin,
                     optionsCaption:'-- please select --',
                     optionsText: 'Name',
                     optionsValue: 'Id'"></select>
</div>

您的getPins 函数建议.pinBinding 元素应对应于正在接收的数据。在这种情况下,pinObjs 应该真正成为您的 viewModel 的一部分,并且应该从数据中生成元素(可能在 foreach 中),而不是硬编码。不过,我不知道这与我认为的服务器端 @modelItem.CaseID 是如何工作的。

【讨论】:

  • 谢谢您-只是出于好奇,由于数组的加载发生在视图模型内部,这将如何支持动态更改数组,就像我对 getPins 函数所做的那样-数组可以而且很可能会发生变化,这意味着需要更新下拉值以反映变化?
  • 也许我应该把时间延迟稍微长一点,但是当我的 sn-p 启动时,列表中没有选项。 8/10 秒后,它们被加载。如果您再次更改它们,它们将在 DOM 中更改。这就是 Knockout 正在做的事情。我将更新 sn-p 以更改几次。
  • 感谢 Roy - 但令人沮丧的是,作为你的小提琴和我自己的工作,订阅事件仍然没有在应用程序中触发 - 我现在想回到绘图板!
  • 确保您在订阅后没有重新分配变量。使用 self.selectedPin = something 而不是 self.selectedPin(something) 是一个常见的错误,它会用 observable 丢弃订阅。
猜你喜欢
  • 1970-01-01
  • 2012-09-20
  • 2013-11-17
  • 1970-01-01
  • 1970-01-01
  • 2016-02-29
  • 2013-03-28
  • 2014-05-10
  • 2019-03-28
相关资源
最近更新 更多