当ajax中的视图模型发生变化时,knockout计算不会更新

时间:2016-05-13 07:56:04

标签: ajax knockout.js

我对敲除Js了解多少是计算机无论如何都会根据视图模型进行更新,但在我的情况下它没有发生。所以基本上我有一个关闭和打开的单选按钮并更改数据库中的日期,并且ajax调用返回并在viewmodel中推送新日期以便数据更改。

这就是摘要。但我想要的是,当单选按钮正在更新时,我想根据单选按钮将html的一部分更改为活动或禁用。

首先是HTML代码。

<div class="col-sm-4">
  <p>
    <span data-bind="text : $data.basketStatusValue"></span>
  </p>
</div>
<div class="col-sm-4">
  <div class="on_off">
    <input type="checkbox"  data-bind="bootstrapSwitchOn: {
        tocall: $root.changeActiveBasketStatus
    }" />
  </div>
</div>

这是JS代码。

function MoneyInvestedViewModel(root /* root not needed */, money) {
    var self = this;
    self.ID = money.ID;
    self.ORIG_ID = money.ORIG_ID;
    self.Available = money.Available;
    self.basketStatusValue = ko.computed (function () {
        if (self.Available == '9999-12-01') {
            return "Active";
        } else {
            return "Disabled";
        }
    });
};

接下来是更新视图模型moneyInvested的代码。因此,复选框可以显示或关闭。

self.changeActiveBasketStatus = function (bindingContext) {
    console.log(bindingContext);
    var Id = bindingContext.$data.ORIG_ID;
    var Available = bindingContext.$data.Available;
    if (Available == '9999-12-01') {
        $.ajax({
            type: 'POST',
            url: BASEURL + 'index.php/moneyexchange/changeBasketStatus/' + auth + "/" + Id + "/" + 1,
            contentType: 'application/json; charset=utf-8'
        })
        .done(function (newAvailableDate) {
            bindingContext.$data.Available = newAvailableDate;
        })
        .fail(function (jqXHR, textStatus, errorThrown) {
            self.errorMessage(errorThrown);
        })
        .always(function (data){  
        });
    } else {
        $.ajax({
            type: 'POST',
            url: BASEURL + 'index.php/moneyexchange/changeBasketStatus/' + auth + "/" + Id + "/" + 0,
            contentType: 'application/json; charset=utf-8'
        })
        .done(function (newAvailableDate) {
            bindingContext.$data.Available = newAvailableDate;
        })
        .fail(function (jqXHR, textStatus, errorThrown) {
            self.errorMessage(errorThrown);
        })
        .always(function (data) {
        });
    }
};

所以基本上问题是当完成所有这些更新后,计算出的self.basketStatusValue不会更新。因此,当我单击复选框时,它不显示活动,或关闭禁用,复选框工作正常,只有html $data.basketStatusValue没有通过计算函数更新。

如果有必要,请填写复选框的代码。

(function ($) {
    ko.bindingHandlers.bootstrapSwitchOn = {
        init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
            var options = ko.utils.unwrapObservable(valueAccessor());
            var tocall = ko.utils.unwrapObservable(options.tocall);

            $elem = $(element);
            $(element).bootstrapSwitch();
            $(element).bootstrapSwitch('setState', bindingContext.$data.Available === '9999-12-01' ? true : false); // Set intial state
            $elem.on('switch-change', function (e, data) {
                tocall(bindingContext);
                // valueAccessor()(data.value);
            });
        },
        update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        }
    };
})(jQuery);

总而言之,我想要做的就是让$data.basketStatusValue拥有&#34;有效&#34;或者&#34;禁用&#34;当复选框打开或关闭时。

3 个答案:

答案 0 :(得分:1)

你可以使用一个肮脏的技巧将整个observable清空并用新数据推送它。但说实话,它不是使用它的正确方法。我现在假设它是一个数组,但你也可以删除observable。只需输入可观察的名称而不是YourArray()。

self.refresh = function(){
        var data = YourArray().slice(0);
        YourArray.removeAll(); 
        self.YourArray(data);
        };

在完成功能

之后立即放置此功能
.done(function(newAvailableDate) {
   bindingContext.$data.Available = newAvailableDate;
  // here self.refresh();
 })

答案 1 :(得分:1)

你的绑定处理程序是错误的,让我们从那开始。

它应该:

  • init()
  • 中的元素上设置Bootstrap开关
  • update()
  • 中的更改做出反应
  • 绑定到observabe(不使用回调函数)。在我们的例子中,observable应该包含复选框状态,即truefalse
  • 到时候正确处理Bootstrap小部件。

所以,这会更好:

(function ($) {
    ko.bindingHandlers.bootstrapSwitch = {
        init: function (element, valueAccessor) {
            var options = valueAccessor();

            // set up bootstrap in init()
            $(element).bootstrapSwitch().on('switch-change', function (e, data) {
                options.value(data.value);
            });

            // see http://knockoutjs.com/documentation/custom-bindings-disposal.html
            ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
                $(element).bootstrapSwitch("destroy");
            });
        },
        update: function(element, valueAccessor) {
            var options = valueAccessor();

            // react to change in update()
            $(element).bootstrapSwitch('setState', options.value());
        }
    };
})(jQuery);

接下来我们需要相应地设置viewmodel。

  • Available需要被观察到。查看更改取决于它。
  • 我们需要一个返回truefalse的可观察对象,具体取决于Available
  • 我们需要一个返回"Active""Disabled"的可观察对象,具体取决于
  • 我们需要一个在更改时(通过订阅)更新服务器的功能
像这样:

function MoneyInvestedViewModel(money) {
    var self = this;
    self.ID = money.ID;
    self.ORIG_ID = money.ORIG_ID;
    self.Available = ko.observable(money.Available);
    self.errorMessage = ko.observable();

    self.BasketStatus = ko.computed(function () {
        return self.Available() == '9999-12-01';
    });
    self.BasketStatusText = ko.computed(function () {
        return self.basketStatus() ? "Active" : "Disabled";
    });

    // BEWARE: this is not actually correct (cicular dependency)
    self.BasketStatus.subscribe(function () {
        $.ajax({
            type: 'POST',
            url: BASEURL + 'index.php/moneyexchange/changeBasketStatus/' + auth + "/" + self.ID + "/" + 1,
            contentType: 'application/json; charset=utf-8'
        })
        .done(function (newAvailableDate) {
            self.Available(newAvailableDate);
        })
        .fail(function (jqXHR, textStatus, errorThrown) {
            self.errorMessage(errorThrown);
        });
    };
}

注意:订阅正确的observable以使用正确的值更新服务器。从您的问题中不清楚服务器更新所依赖的值。

现在可以直接将视图绑定到:

<div class="col-sm-4">
  <p><span data-bind="text: BasketStatusText"></span></p>
</div>
<div class="col-sm-4">
  <div class="on_off">
    <input type="checkbox"  data-bind="bootstrapSwitch: {
        value: BasketStatus
    }" />
  </div>
</div>

答案 2 :(得分:0)

if(self.Available == '9999-12-01'){ return "Active"; }else{ return "Disabled";}

这一行的问题在于它不会查找任何可观察或计算的值,因此它不会导致计算机被更新。

你需要制作self.Available 一个可观察的,然后做self.Available() 这是计算器的工作方式,当它们的任何可观察/计算的依赖关系发生变化时,它们会被重新计算。 Knockout将不会像您一样看到简单的属性更新。