当observable发生变化时,knockout bind不会更新

时间:2017-06-22 09:58:59

标签: javascript knockout.js

我有一个下拉按钮,在ajax请求完成后应该可以使用。

<div class="form-input">
   <label class="">Sort by:</label>
   <select name="orderby" class="selectpicker" data-bind="value: sortBy, optionsCaption: 'Default', disable: waiting">
      <option value="some_value">some_option</option>
      <option value="some_value">some_option</option>
   </select>
</div>

在请求的页面上,它最初加载数据

$(function() {
    //Initialization
    var vm = new ArticleViewModel();
    initialLoadArticles(vm);
    ko.applyBindings(vm, $("#article-plugin")[0]);
});

function ArticleViewModel() {
    var self = this;

    //options =>
    this.articles = ko.observableArray([]);
    this.pageSize = 12;

    this.sortBy = ko.observable('asc');

    this.currentPage = ko.observable(1);
    this.waiting = ko.observable(true);
    this.totalPages = 0;
    this.initMode = true;
    this.timerId = null;
    this.viewTemplate = ko.observable('listview-template');
    if (this.viewTemplate() === "listview-template") {
        this.pageSize = 4
    } else {
        this.pageSize = 12
    };


    this.sortBy.subscribe(function(event) {
        console.log(event);
        self.optionChanged();
        loadArticles(self);
    });

    this.optionChanged = function() {
        this.currentPage(1);
    }


    this.setCardView = function() {
        self.viewTemplate('cardview-template');
        loadArticles(self);
    }
    this.setListView = function() {
        self.viewTemplate('listview-template');
        loadArticles(self);
    }

}

function initialLoadArticles(vm) {
    vm.waiting(true);
    var params = {
        page: vm.currentPage(),
        size: vm.pageSize,
        sortby: vm.sortBy()
    };

    api.ajax.get(api.urls.article.getArticles, params, function(response) {
        console.log('waiting: ' + vm.waiting());
        if (response.success) {
            vm.articles(response.data.items);
            vm.waiting(false);
        }
    });

}

好吧,在一个页面上显示所有文章,但下拉按钮仍然被阻止,我不知道究竟是什么问题。

1 个答案:

答案 0 :(得分:2)

我建议您对viewmodel进行一些更改,通过订阅自动加载。

我认为您总是希望在加载后将waiting设置为false,而不管请求是否成功。还要考虑低级请求错误,需要为这些错误添加处理程序。

function ArticleViewModel() {
    var self = this;

    self.articles = ko.observableArray();

    self.pageSize = ko.observable();
    self.sortBy = ko.observable('asc');
    self.currentPage = ko.observable();
    self.waiting = ko.observable(true);
    self.viewTemplate = ko.observable();

    // API
    self.setCardView = function() {
        self.viewTemplate('cardview-template');
        self.pageSize(12);
        self.currentPage(1);
    };
    self.setListView = function() {
        self.viewTemplate('listview-template');
        self.pageSize(4);
        self.currentPage(1);
    };

    // compute Ajax-relevant parameters
    self.ajaxParams = ko.pureComputed(function () {
        return {
            page: self.currentPage(),
            size: self.pageSize(),
            sortby: self.sortBy()
        };
    }).extend({ rateLimit: { timeout: 10, method: 'notifyWhenChangesStop' } });

    // auto-load when params change
    self.ajaxParams.subscribe(function (params) {
        self.waiting(true);
        api.ajax.get(api.urls.article.getArticles, params, function (response) {
            if (response.success) {
                self.articles(response.data.items);
            }
            self.waiting(false);
        });
    });

    // set inital view (also triggers load)
    self.setListView();
}

$(function() {
    var vm = new ArticleViewModel();
    ko.applyBindings(vm, $('#article-plugin')[0]);
});

更严格地说,我建议您将truefalse作为“加载”指标。技术上可能会运行多个Ajax请求,这将是竞争条件。第一个返回的请求将重置“加载”状态,下一个请求仍会覆盖视图模型数据。使用计数器,或在有待处理请求时阻止新请求。

rateLimit扩展程序可确保对参数进行快速连续更改,例如调用setListView()时发生的更改,不会导致多个Ajax请求。

如果您的Ajax请求是由jQuery在内部完成的,我建议您使用以下设置来使用donefailalways承诺处理程序:

function ApiWrapper() {
    var self = this;

    function unwrapApiResponse(response) {
        if (response.success) {
            return new $.Deferred().resolve(response.data).promise();
        } else {
            return new $.Deferred().reject(response.error).promise();
        }
    }

    self.getArticles = function (params) {
        return $.get('articleUrl', params).then(unwrapApiResponse);
    };
    // more functions like this
}

var api = new ApiWrapper();

并在您的viewmodel中:

self.ajaxParams.subscribe(function (params) {
    self.waiting(true);
    api.getArticles(params).done(function (data) {
        self.articles(data.items);
    }).fail(function (err) {
        // show error
    }).always(function () {
        self.waiting(false);
    });
});