javascript Knockout.js 在按钮单击时更新 ViewModel

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23293378/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 00:40:51  来源:igfitidea点击:

Knockout.js Update ViewModel on button click

javascriptjquerymvvmknockout.js

提问by andrey.shedko

Well, that's not the best situation description... Anyway, I'm trying to update my ViewModel but it's not working. By default I'm getting data from controller function and by button click - from another function in same contoller, but ViewModel contain only data received after first ViewModel initialization.

嗯,这不是最好的情况描述...无论如何,我正在尝试更新我的 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>

UPDATE.I chaged block of code where I'm getting new data to be as follow:

更新。我修改了获取新数据的代码块,如下所示:

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

Unfortunately this is not working as well. Here is no any JS errors, controller return proper portion of updated data.

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

采纳答案by andrey.shedko

Well. Final solution based on @GoTo answer is: Here is the way to call function in viewmodel via click databind.

好。基于@GoTo 答案的最终解决方案是: 这是通过单击数据绑定在视图模型中调用函数的方法。

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

Here is the function.As you can see I'm calling self.salesdatainstead of viewModel. This solution is working fine but somehow now I have problem with data format that is binded this way - <td data-bind="text: moment($data.whensold).format('DD.MM', 'ru')"></td>.

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

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

回答by brader24

I'm new to all of this, but if I'm reading your code correctly, you are calling the request function on a new instance of the view model and not the one that was bound to the html document. You need to make the request call on the view model that you created after the initial get call completed.

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

Update: Sorry, I should have been more specific about the code I was referring to. At the end of your code block you have the following code:

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

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

In this code, it appears that each time the default button is clicked, a new view model is created and the request function is called on that view model.

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

In the document ready function where you are defining what happens after the sales data is loaded, you have the following code which is what creates the view model that the html document is actually bound to:

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

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

Nothing ever calls the request function on this view model. I wonder if what you really want is to somehow bind the request function in this view model to the default button.

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

回答by G?T?

I would try updating the viewmodel salesdataobservable, by giving context: selfand using the following successmethod:

我会尝试salesdata通过提供context: self和使用以下success方法来更新 viewmodel 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);
        }
        });
    }

EDIT:

编辑:

I can see you attached a click event with jQuery. You should use knockout clck binding instead:

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

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

And in the viewmodel

在视图模型中

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

This way you can retrieve your viewmodel instead of creating a new one as you did with new viewModel().request(uri);

通过这种方式,您可以检索您的视图模型,而不是像以前那样创建一个新的视图模型 new viewModel().request(uri);

For more on click binding see http://knockoutjs.com/documentation/click-binding.html

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

回答by rwisch45

Building slightly on the answer from @brader24 here:

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

In your update button's clickevent, you use this line of code:

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

new viewModel().request(uri);

new viewModel().request(uri);

What that is doing is creating a newviewModel(separate from the one that you already have instantiated and have applied bindings for) and filling it's observable array with data via your requestfunction. It isn't affecting your original viewModelat all (the one that has it's bindings applied on the DOM!). So you won't see any errors, but you also won't see anything happening on the page because all you did was create a new viewModelin memory, fill it with data, and do nothing with it.

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

Try this code (everything in your viewModelfunction looks fine).

试试这个代码(你的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
    });
});

Using a Knockout click binding instead of attaching a click event handler using jQuery is usually the recommended route, but it is not necessary- so your existing code (with the modifications above) should work fine. For more info on that, see Using unobtrusive event handlersin the Knockout docs

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