jqgrid: как отправлять и получать данные строк, сохраняя режим редактирования - PullRequest
0 голосов
/ 08 июля 2011

jqGrid содержит столбцы с именем сотрудника и идентификатором сотрудника.

Если employee name изменилось, для проверки имени должен быть вызван метод проверки сервера.Текущие столбцы строк должны обновляться на основе данных, возвращаемых этим методом.

Если employee id изменилось, должен быть вызван метод проверки сервера для проверки идентификатора.Текущие столбцы строк должны обновляться на основе данных, возвращаемых этим методом.

Желательно, чтобы jqGrid оставался в режиме редактирования, чтобы у пользователя была возможность продолжать изменять, принимать или отклонять изменения.

Как реализовать этов линейном и редактировании формы?Я думаю о следующих возможностях:

Возможность 1.

Использование editrules с пользовательским валидатором, таким как

            editrules = new
            {
                custom = true,
                custom_func = function(value, colname) { ??? }
            },

Проблемы: Как получить данные из всех столбцов, выполнить синхронизациюили асинхронный вызов и обновление столбцов с результатами этого вызова.

Возможность 2.

Требуется, чтобы пользователь нажал клавишу Enter, чтобы сохранить строку.Проблемы: как найти, какой столбец был изменен и передать этот номер столбца на сервер.Как обновить данные текущей строки из ответа сервера.

Возможность 3.

с использованием размытия, как описано в великолепном ответе Олега в jqgrid, изменить значение ячейки и остаться в режиме редактирования

Проблемы: размытие не срабатывает, если данные вводятся и ввод нажимается немедленно.Как применить размытие в этом случае?

В общем случае вычисление / проверка sice сервера должно быть выполнено следующим образом:

Если столбец изменен, а фокус перемещен или нажата кнопка ввода в измененном столбце для сохранения, на стороне сервера синхронизации или, если это невозможно, должен быть вызван асинхронный метод.Измененное имя столбца и текущие значения редактируемой строки, как в методе редактирования, передаются в качестве параметров этому методу.

Этот метод возвращает новые значения для редактируемой строки.текущие отредактированные значения строки должны быть заменены значениями, возвращаемыми этим методом.

Обновление

Ответ Олег предполагает, что первичный ключ изменен.Этот фактор не важен.Вот новая версия вопроса без первичных ключей и других обновлений:

jqGrid содержит столбцы со штрих-кодом продукта и именем продукта.

Если product name изменилось, для проверки имени должен быть вызван метод проверки сервера.Текущие столбцы строки должны обновляться на основе данных, возвращаемых этим методом.

Если product barcode изменилось, должен быть вызван метод проверки сервера для проверки штрих-кода продукта.Текущие столбцы строк должны обновляться на основе данных, возвращаемых этим методом.

jqGrid должен оставаться в режиме редактирования, чтобы у пользователя была возможность продолжать изменять, принимать или отклонять изменения.

Как реализовать это ввстроенное редактирование и редактирование форм?Я думаю о следующих возможностях:

Возможность 1.

Использование editrules с пользовательским валидатором, таким как

            editrules = new
            {
                custom = true,
                custom_func = function(value, colname) { ??? }
            },

Проблема: custom_func не срабатывает, если элемент ввода теряет фокус.Вызывается перед сохранением для всех элементов.Поэтому его нельзя использовать.

Возможность 2.

Требуется, чтобы пользователь нажал клавишу Enter, чтобы сохранить строку.Проблемы: как найти, какой столбец был изменен и передать этот номер столбца на сервер.Метод сохранения должен содержать известный столбец (имя или порядок изменения штрих-кода) и заполнять различные столбцы.Это выглядит неоправданно.

Возможность 3.

с использованием размытия:

colModel: [{"label":"ProductCode","name":"ProductCode","editoptions":{
"dataEvents":[
{"type":"focus","fn":function(e) { ischanged=false}},
{"type":"change","fn":function(e) {ischanged=true}},
{"type":"keydown","fn":function(e) {ischanged=true }},
{"type":"blur","fn":function(e) { if(ischanged) validate(e)} }
]},

Для реализации проверки я нашел код от Олега великого ответа в jqgrid изменить значение ячейкии оставайтесь в режиме редактирования

Сводная информация о требованиях:

Если столбец изменен, а фокус перемещен или введен ввод в измененном столбце для сохранения, синхронизации на стороне сервера или, если это невозможно,асинхронный метод должен быть вызван.Измененное имя столбца и текущие значения отредактированной строки, как в методе редактирования, передаются в качестве параметров этому методу.

Этот метод возвращает новые значения для отредактированной строки.текущие отредактированные значения строк должны быть заменены значениями, возвращаемыми этим методом.

Update2

Этот вопрос не о параллелизме. Это проблема одного пользователя и jqGrid. Обновление означает, что один пользователь меняет название продукта или штрих-код, а сервер должен предоставлять дополнительные данные (идентификатор продукта и / или имя / штрих-код) в ответ на это.

Обновление 4

Я попробовал код ниже. Если пользователь вводит новый код и нажимает клавишу Enter, не переходя в другую строку, размытие не происходит и проверка не вызывается.

Как отключить метод сохранения jqGrid, если ячейка грязная, или другая идея, как заставить этот код работать, если нажата клавиша enter, чтобы завершить редактирование, не теряя фокус из измененной ячейки внешнего ключа?

function validate(elem, column) {
ischanged = false;
var i, form, row;
var postData = { _column: column  };
var colModel = $("#grid").jqGrid('getGridParam', 'colModel');
var formEdit = $(elem).is('.FormElement');
// todo: use jQuery serialize()  ???
if (formEdit) {
    form = $(elem).closest('form.FormGrid');
    postData._rowid = $("#grid").jqGrid('getGridParam', 'selrow');
    for (i = 0; i < colModel.length; i++)
        eval('postData.' + colModel[i].name + '="' + $('#' + colModel[i].name + '.FormElement', form[0]).val() + '";');
}
else {
    row = $(elem).closest('tr.jqgrow');
    postData._rowid = row.attr('id');
    for (i = 1; i < colModel.length; i++)
        eval('postData.' + colModel[i].name + '="' + $('#' + postData._rowid + '_' + colModel[i].name).val() + '";');
}
$.ajax('Grid/Validate', {
    data: postData,
    async: false,
    type: 'POST',
    success: function (data, textStatus, jqXHR) {
        for (i = 0; i < data.length; i++) {
            if (formEdit)
                $('#' + data[i].name + '.FormElement', form[0]).val(data[i].value);
            else
                $('#' + postData._rowid + '_' + data[i].name).val(data[i].value);
        }
    }
});
}

colModel определяется как:

{"name":"ProductBarCode",
"editoptions":    {"dataEvents":  
[{"type":"focus","fn":function(e) {ischanged=false}
},
{"type":"change","fn":function(e) {ischanged=true},
{"type":"keydown","fn":function(e) {if(realchangekey()) ischanged=true}
},{"type":"blur","fn":function(e) { if(ischanged) {  validate(       e.target,ProductBarCode')}}
}]},"editable":true}

1 Ответ

2 голосов
/ 10 июля 2011

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

В любой реализации управления параллелизмом важно, чтобы сервер первым смог обнаружить проблему параллелизма.Может случиться, что два (или более) пользователя вашего веб-приложения прочитают одну и ту же информацию, что и информация о сотруднике.Информация может быть отображена в jqGrids, например.Если вы разрешите изменить идентификатор сотрудника, то первой проблемой будет для обнаружения ошибки параллелизма .Допустим, один пользователь изменит идентификатор сотрудника, а другой пользователь попытается изменить того же сотрудника на основе ранее загруженной информации.После того, как пользователь отправит посредничество, серверное приложение просто получит запрос «edit», но не найдет соответствующую запись в базе данных .Сервер должен будет отправить ответ об ошибке без каких-либо подробностей.Так что errorfunc из editRow или обработчик событий errorTextFormat из editGridRow должен вызвать «reloadGrid» для перезагрузки всей сетки.

Если вы разрешитечтобы редактировать первичный ключ, тогда я могу представить себе более опасную ситуацию, как описано выше.Может случиться так, что другой пользователь не только изменит идентификатор текущей строки редактирования на другое значение, но также может изменить идентификатор еще одной записи так, чтобы его новый идентификатор был таким же, как текущий идентификатор редактирования.В случае, если запрос на сохранение строки будет перезаписывать другую запись .

Чтобы предотвратить такие проблемы и упростить оптимистический контроль параллелизма , можно добавить дополнительный столбец, которыйпредставляют любую форму метки времени в каждой таблице базы данных, которая может быть изменена.Я лично использую Microsoft SQL Server и добавляю, я использовал для добавления необнуляемого столбца типа rowversion (аналогично типу timestamp в предыдущей версии SQL Server).Значение rowversion будет отправлено в jqGrid вместе с данными.Запрос на изменение, который будет отправлен на сервер, будет содержать rowversion .Если какие-либо данные будут сохранены в базе данных, соответствующее значение в соответствующем столбце rowversion будет автоматически изменено базой данных SQL.Таким образом, сервер может очень легко обнаруживать ошибки параллелизма с помощью следующего кода

CREATE PROCEDURE dbo.spEmployeesUpdate
    -- @originalRowUpdateTimeStamp used for optimistic concurrency mechanism
    -- it is the value which correspond the data used by the user as the source
    @Id int,
    @EmployeeName varchar(100),
    @originalRowUpdateTimeStamp rowversion,
    @NewRowUpdateTimeStamp rowversion OUTPUT
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    -- ExecuteNonQuery() returns -1, but it is not an error
    -- one should test @NewRowUpdateTimeStamp for DBNull
    SET NOCOUNT ON;

    UPDATE dbo.Employees
    SET Name = @EmployeeName
    WHERE Id=@Id AND RowUpdateTimeStamp=@originalRowUpdateTimeStamp;

    -- get the new value of the RowUpdateTimeStamp (rowversion)
    -- if the previous update took place
    SET @NewRowUpdateTimeStamp = (SELECT RowUpdateTimeStamp
                                  FROM dbo.Employees
                                  WHERE @@ROWCOUNT > 0 AND Id=@Id)
END

. В коде серверного приложения можно проверить, что выходной параметр @NewRowUpdateTimeStamp будет установлен хранимой процедурой * 1044.*.Если он не установлен, серверное приложение может выдать DBConcurrencyException исключение.

Так что, по моему мнению, вы должны внести изменения в базу данных и код приложения сервера, чтобы реализовать оптимистичный контроль параллелизма.После этого код сервера должен вернуть ответ с кодом ошибки HTTP в случае ошибки параллелизма.errorfunc editRow или обработчик события errorTextFormat editGridRow должны перезагрузить новые значения текущей измененной строки.Вы можете использовать более сложный способ или просто перезагрузить сетку и продолжить модификацию текущей строки.В случае неизмененного rowid вы можете легко найти новую загруженную строку и начать ее редактирование после перезагрузки сетки.

В существующей базе данных вы можете использовать

ALTER TABLE dbo.Employees ADD NewId int IDENTITY NOT NULL
ALTER TABLE dbo.Employees ADD RowUpdateTimeStamp rowversion NOT NULL
ALTER TABLE dbo.Employees ADD CONSTRAINT UC_Employees_NewId UNIQUE NONCLUSTERED (NewId)
GO

Тогда вы можете использовать NewId вместо идентификатора в jqGrid или в любом другом месте, которое вам нужно.NewId может сосуществовать с вашим текущим первичным ключом, пока вы не обновите другие части вашего приложения, чтобы использовать более эффективные NewId.

ОБНОВЛЕНО : Я не думаю, что нужно действительно реализовывать какие-либо сложные исправления ошибок для ошибки параллелизмаВ проектах у моих клиентов данные, которые нужно редактировать, не могут содержать длинных текстов.Таким образом, достаточно простого сообщения, которое описывает причину, по которой текущие модификации не могут быть сохранены.Пользователь может вручную перезагрузить полную сетку и проверить текущее содержание строки, которую он редактировал.Не следует забывать, что любые сложные процедуры могут привести к дополнительным ошибкам в проекте, реализация сложна, она увеличивает бюджет на разработку, и в основном дополнительные инвестиции никогда не окупятся.

Если вам нужно внедрить автоматическое обновлениенапример, в строке редактирования я бы никогда не реализовал проверку ячейки в событии «размытие».Вместо этого можно проверить внутри errorfunc editRow или внутри errorTextFormat обработчика события editGridRow , что сервер возвращает ошибку параллелизма.В случае ошибки параллелизма можно сохранить идентификатор текущей строки редактирования в переменной, к которой можно получить доступ в дескрипторе события loadComplete.Затем, после отображения сообщения об ошибке, можно просто перезагрузить сетку с отношением $('#list').trigger('reloadGrid',[{current:true}]) (см. здесь ).Внутри дескриптора события loadComplete можно проверить, установлена ​​ли переменная прерванной строки редактирования.В этом случае можно вызвать editRow или editGridRow и продолжить редактирование строки.Я думаю, что при изменении текущей строки другие строки страницы также могут быть изменены.Так что перезагрузка текущей страницы лучше, так как перезагрузка данных только одной текущей ячейки или одной строки сетки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...