【问题标题】:Knockout.js Update ViewModel on button clickKnockout.js 在按钮单击时更新 ViewModel
【发布时间】:2014-06-11 04:23:56
【问题描述】:

嗯,这不是最好的情况描述......无论如何,我正在尝试更新我的 ViewModel 但它不起作用。默认情况下,我从控制器函数获取数据并通过按钮单击 - 从同一控制器中的另一个函数获取数据,但 ViewModel 仅包含第一次 ViewModel 初始化后收到的数据。

<script>
     function viewModel () {
        var self = this;
        self.currentPage = ko.observable();
        self.pageSize = ko.observable(10);
        self.currentPageIndex = ko.observable(0);
        self.salesdata = ko.observableArray();
        self.newdata = ko.observable();
        self.currentPage = ko.computed(function () {
            var pagesize = parseInt(self.pageSize(), 10),
            startIndex = pagesize * self.currentPageIndex(),
            endIndex = startIndex + pagesize;
            return self.salesdata.slice(startIndex, endIndex);
        });
        self.nextPage = function () {
            if (((self.currentPageIndex() + 1) * self.pageSize()) < self.salesdata().length) {
                self.currentPageIndex(self.currentPageIndex() + 1);
            }
            else {
                self.currentPageIndex(0);
            }
        }
        self.previousPage = function () {
            if (self.currentPageIndex() > 0) {
                self.currentPageIndex(self.currentPageIndex() - 1);
            }
            else {
                self.currentPageIndex((Math.ceil(self.salesdata().length / self.pageSize())) - 1);
            }
        }
        //Here I'm trying to update ViewModel
        self.request = function (uri) {
            $.ajax({
                url: uri,
                contentType: 'application/json',
                data: [],
                type: 'GET',
                cache: false,
            success: function (data) {
                ko.mapping.fromJS(data.$values, {}, self.salesdata);
            }
            });
        }
    }
    $(document).ready(function () {
        $.ajax({
            url: "/api/sales",
            type: "GET",
            cache: false,
        }).done(function (data) {
            var vm = new viewModel();
            vm.salesdata(data.$values);
            ko.applyBindings(vm);
        }).error(function (xhr, status, error) {
            var err = eval("(" + xhr.responseText + ")");
            alert(err.Message);
        });
        //Here i'm calling for ViewModel update
        $(".btn-default").click(function () {
            days = $(this).val();
            var uri = "/api/sales?days=" + days;     
            new viewModel().request(uri);
        });
    });
</script>

更新。 我将获取新数据的代码块更改如下:

self.request = function (uri) {
                $.getJSON(uri, function (data) {
                    ko.mapping.fromJS(data.$values, {}, viewModel);
                });
            }

不幸的是,这也不起作用。这里没有任何 JS 错误,控制器返回更新数据的适当部分。

【问题讨论】:

  • 您确定没有 JavaScript 错误并且您的请求调用了成功处理程序吗?
  • 经过一番调查,我认为这一行存在问题 - ko.mapping.fromJS(data.$values, {}, viewModel);因为当我尝试通过警报(data.$values)显示数据时,它显示的是对象而不是数据。是的,为了避免再次调用 viewmodel,我使用 clickeevnt 作为@GoTo 的建议。

标签: javascript jquery mvvm knockout.js


【解决方案1】:

我对所有这些都是新手,但是如果我正确阅读了您的代码,那么您是在视图模型的新实例上调用请求函数,而不是绑定到 html 文档的实例。您需要在初始 get 调用完成后对创建的视图模型进行请求调用。

更新: 抱歉,我应该更具体地说明我所指的代码。在代码块的末尾,您有以下代码:

    $(".btn-default").click(function () {
        days = $(this).val();
        var uri = "/api/sales?days=" + days;     
        new viewModel().request(uri);
    });

在这段代码中,似乎每次单击默认按钮时,都会创建一个新的视图模型,并在该视图模型上调用请求函数。

在您定义加载销售数据后发生的事情的文档就绪函数中,您有以下代码,它创建了 html 文档实际绑定到的视图模型:

    var vm = new viewModel();
    vm.salesdata(data.$values);
    ko.applyBindings(vm);

在这个视图模型上没有任何东西调用请求函数。我想知道您是否真正想要以某种方式将此视图模型中的请求函数绑定到默认按钮。

【讨论】:

  • 对于那些投反对票的人来说,包括关于他们投反对票的原因的评论会很有帮助。我怀疑只是因为我匆忙回答并且没有确保示例代码清楚。你有权发表你的意见,但我只是想知道为什么,以便我以后可以尝试改进我的答案。
  • 你是对的。我的错。这个问题有两个答案,GoTo 非常详细,并提到了点击处理程序的一个重要点,而我发现你的答案有点笼统。提问者在这里似乎需要更多细节。因此,我对 GoTo 的回答投了赞成票,对你的回答投了反对票。您现在已经编辑并改进了您的答案,因此我删除了反对票。不发表评论是我的错。
  • 我会投反对票,因为这个答案没有如何更新原始视图模型,正如我所说的 OP 正在尝试做的那样。
【解决方案2】:

我会尝试通过提供context: self 并使用以下success 方法来更新视图模型salesdata observable:

self.request = function (uri) {
        $.ajax({
            url: uri,
            contentType: 'application/json',
            context: self,
            data: [],
            type: 'GET',
            cache: false,
        success: function (data) {
            this.salesdata(data.$values);
        }
        });
    }

编辑:

我可以看到您使用 jQuery 附加了一个单击事件。 您应该改用淘汰赛 clck 绑定:

<button data-bind="click: clickEvent" value="1">Click me!</button>

在视图模型中

clickEvent: function (data, event) { 
    days = event.target.value;
    var uri = "/api/sales?days=" + days;     
    data.request(uri);
}

这样您可以检索您的视图模型,而不是像使用 new viewModel().request(uri); 那样创建一个新视图模型

有关点击绑定的更多信息,请参阅http://knockoutjs.com/documentation/click-binding.html

【讨论】:

    【解决方案3】:

    在@brader24 的回答的基础上稍微建立:

    在更新按钮的click 事件中,您使用这行代码:

    new viewModel().request(uri);

    所做的是创建一个 new viewModel(与您已经实例化并应用绑定的那个分开)并通过您的 request 函数用数据填充它的可观察数组.它根本不会影响您原来的viewModel(在 DOM 上应用了它的绑定!)。所以您不会看到任何错误,但您也不会看到页面上发生任何事情,因为您所做的只是在内存中创建一个新的viewModel,用数据填充它,然后什么都不做。

    试试这段代码(viewModel 函数中的一切看起来都很好)。

    $(document).ready(function () {
        var vm = new viewModel(); // declare (and instantiate) your view model variable outside the context of the $.ajax call so that we have access to it in the click binding
        $.ajax({
            url: "/api/sales",
            type: "GET",
            cache: false,
        }).done(function (data) {
            vm.salesdata(data.$values);
            ko.applyBindings(vm);
        }).error(function (xhr, status, error) {
            var err = eval("(" + xhr.responseText + ")");
            alert(err.Message);
        });
        //Here i'm calling for ViewModel update
        $(".btn-default").click(function () {
            days = $(this).val();
            var uri = "/api/sales?days=" + days;     
            vm.request(uri); // don't use a new instance of a view model - use the one you have already instantiated
        });
    });
    

    使用 Knockout 点击绑定而不是使用 jQuery 附加点击事件处理程序通常是推荐的路线,但它不是必需的 - 因此您现有的代码(经过上述修改)应该可以正常工作。有关这方面的更多信息,请参阅 Knockout 文档中的 Using unobtrusive event handlers

    【讨论】:

    • 这就是我所说的,但描述得不够清楚。我更新了我的答案,但这个答案更好地解释了它,并提供了一个解决方案,在我目前缺乏经验的情况下,我不准备提供。
    • 伙计们,您的建议看起来合乎逻辑,但不幸的是它不起作用。
    【解决方案4】:

    嗯。基于@GoTo 答案的最终解决方案是: 这里是viewmodel中通过click databind调用函数的方法。

    <button type="button" class="btn btn-default" id="7" value="7" data-bind="click: getDays.bind($data, '7')">7</button>
    

    这是函数。如您所见,我调用的是 self.salesdata 而不是 viewModel。该解决方案运行良好,但不知何故,现在我遇到了以这种方式绑定的数据格式的问题- &lt;td data-bind="text: moment($data.whensold).format('DD.MM', 'ru')"&gt;&lt;/td&gt;

     self.getDays = function (days) {
                        var uri = "/api/sales?days=" + days;
                        $.getJSON(uri, function (data) {
                            ko.mapping.fromJS(data.$values, {}, self.salesdata);
                        });
                    }
    

    【讨论】:

    • 我应该给哪个答案? @brader24 和 Goto 一样都给出了解决方案的想法。
    猜你喜欢
    • 2023-03-19
    • 1970-01-01
    • 2012-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-01
    • 1970-01-01
    相关资源
    最近更新 更多