проверка нокаута - пользовательский интерфейс расширенного поиска

Я создаю пользовательский интерфейс расширенного поиска, аналогичный веб-интерфейсу построителя запросов TFS. Использование нокаута для реализации на стороне клиента и все более или менее работает, кроме окончательной проверки, чтобы убедиться, что определенные необходимые элементы в основном выбраны. Это как бы работает, поскольку дает мне ошибку проверки, если я выбираю элемент, а затем отменяю выбор элемента. Это нормально, но я хотел бы, чтобы форма проверялась при нажатии кнопки поиска.

Я почти уверен, что мне нужно использовать метод ko.validatedobservable, я просто не уверен, как именно. В любом случае, у меня есть скрипка, на которую можно посмотреть: http://jsfiddle.net/sstolp/uXBSA/ если у кого-то есть время или желание помочь мне. Я был бы глубоко признателен.

Спасибо за уделенное время.

scvm.SearchLine = function () {
var self = this;
self.selectedField = ko.observable().extend({ required: true });
self.selectedOperator = ko.observable().extend({ required: true });
self.firstdate = ko.observable(new Date());
self.lastdate = ko.observable(new Date());
self.thedate = ko.observable(new Date());

return self;};

scvm.Criteria = function () {
var self = this,
    lines = ko.observableArray([]),

    // Put one line in by default
    loadInitialData = function () {
        lines.push(new scvm.SearchLine());
    },

    rowcount = ko.computed(function () {
        return lines().length;
    }),

    // Operations
    addLine = function () {
        lines.push(new scvm.SearchLine());
    },

    removeLine = function (line) {
        lines.remove(line);
    },

    search = function () {
        var data = $.map(lines(), function (line) {
            return line.selectedField() ? {
                selectedField: line.selectedField().searchfield,
                selectedOperator: line.selectedOperator().name,
            } : undefined
        });
        alert("Send to server: " + JSON.stringify(data));            
    },

    clear = function () {
        lines.removeAll();
    };

return {
    lines: lines,
    loadInitialData: loadInitialData,
    rowcount: rowcount,
    addLine: addLine,
    removeLine: removeLine,
    search: search,
    clear: clear
};
}();

person Steve    schedule 10.02.2013    source источник


Ответы (1)


Да, все ваши объекты SearchLine должны быть заключены в ko.validatedObservable. Также вы должны реализовать вычисляемое свойство, которое будет проверять isValid() для каждой строки критериев и возвращать глобальный флаг достоверности.

scvm.SearchLine = function () {
    var self = this;
    self.selectedField = ko.observable().extend({ required: true });
    self.selectedOperator = ko.observable().extend({ required: true });
    self.firstdate = ko.observable(new Date());
    self.lastdate = ko.observable(new Date());
    self.thedate = ko.observable(new Date());

    return ko.validatedObservable(self);
};

scvm.Criteria = function () {

    // ...

    return {
        lines: lines,
        loadInitialData: loadInitialData,
        rowcount: rowcount,
        addLine: addLine,
        removeLine: removeLine,
        search: search,
        clear: clear,
        // new property that indicates validity of all lines
        linesValid: ko.computed(function(){
            var items = lines();
            for (var i = 0, l = items.length; i < l; i++)
                if (!items[i].isValid()) return false;
            return true;
        })
    };
}();

Это новое свойство можно использовать в enable привязке вашей кнопки "Поиск":

<input type="button"
       data-bind="enable: linesValid, click: search"
       title="Clicking this button will run a search."
       value="Search" />

Я изменил вашу скрипку. Взгляните: http://jsfiddle.net/ostgals/uXBSA/8/


Обновлять:

Также мы должны немного изменить метод Criteria.search, так как наш линейный массив содержит наблюдаемые объекты, а не объекты:

        //...

        search = function () {
            var data = $.map(lines(), function (line) {
                line = ko.utils.unwrapObservable(line);
                return line.selectedField() ? {
                    selectedField: line.selectedField().searchfield,
                    selectedOperator: line.selectedOperator().name,
                } : undefined
            });
            alert("Send to server: " + JSON.stringify(data));            
        },

        //...
person Rango    schedule 10.02.2013
comment
Привет f_martinez. Спасибо за ответ и за пример скрипки. Я продолжал работать над этим после того, как опубликовал вопрос, и на самом деле придумал реализацию, которая немного отличалась от того, что вы опубликовали. Основное отличие, которое я заметил, заключается в том, что ваш пример повторяет объект строк, чтобы предоставить свойство linesValid. Кроме того, в вашем примере, хотя у меня есть действительные критерии и кнопка поиска включена, когда я нажимаю ее, я получаю сообщение об ошибке, что line.selectedField не является функцией, тогда как я не получал это сообщение ранее, и я не получить эту ошибку в моей. - person Steve; 10.02.2013
comment
Ошибка возникает из-за того, что line теперь можно наблюдать, и мы должны использовать line(), чтобы получить доступ к его реальному интерфейсу. Я не проверял нажатие кнопки "Поиск" - приношу свои извинения. Обходной путь в моем случае — переписать метод Criteria.search с распаковкой line раньше. Я обновил свой ответ. - person Rango; 10.02.2013
comment
Ваш метод - первый, о котором я подумал, но мне показалось, что этот метод требует переписывания большего количества кода. Может быть, я ошибаюсь. В любом случае спасибо за интересный вопрос. - person Rango; 10.02.2013