Вопрос

Обновление данных на странице редактирования.

Добрый день.

Интересует следующее.

Часто возникает необходимость реализовывать автовычисление полей на стороне сервера во внутреннем процессе объекта, как правило это связано с безопасностью и требованием запретить пользователю напрямую изменять значения каких-то полей на странице (запрещаем на уровне администрирования прав доступа).

При этом после сохранения сущности необходимо каким-то образом актуализировать наполнение полей на открытой ранее странице редактирования. Вот тут начинаются танцы с бубном в виде прикручивания к методу onSaved всяких loadEntity или onDiscardChangesClick. как правило, сразу корректно эти варианты не работают в 90% случаев. Подскажите, пожалуйста, как наиболее корректно реализовать обновление полей?

Также интересует, как лучше делать подобное обновление, не затрагивая несохранённые изменения, сделанные пользователем на странице редактирования. (К примеру обновились значения полей при сохранении связанной сущности). Гипотетический пример: при обновлении сведений о доходах (поле) одного из заёмщиков (связанная сущность с ссылкой на основную сущность), обновляем данные о совокупном доходе всех созаёмщиков (поле) в кредитной заявке (основная сущность).

 

PS. Использовать просто this.set... в колбэке EntitySchemaQuery не предлагать.

Нравится

8 комментариев

Добрый день! Если речь идет о загрузке актуальных данных перед сохранением, то я бы посоветовал использовать вот такой метод:

/**
 * Обновляет поля карточки для сущности страницы.
 * @param {Array} fields Список обновляемых полей.
 * @param {Function} callback Функция обратного вызова.
 * @param {Object} scope Контекст функции обратного вызова.
 */
var reloadCardFromPage = function (fields, callback, scope) {
	var showSaveButton = scope.get("ShowSaveButton");
	var showDiscardButton = scope.get("ShowDiscardButton");
	var showCloseButton = scope.get("ShowCloseButton");
	if (!scope.Ext.isArray(fields) || fields.length === 0) {
		return ;
	}
	var fieldsQuantity = fields.length;
	var selectNewValues = scope.Ext.create("Terrasoft.EntitySchemaQuery", {
		rootSchemaName: scope.entitySchemaName
	});
	for (var i = 0; i < fieldsQuantity; i++) {
		selectNewValues.addColumn(fields[i]);
	}
	var id = scope.get("Id");
	selectNewValues.getEntity(id, function(result) {
		var entity = result.entity;
		if (entity ) {
			fields.forEach(function(element) {
				var newValue = entity.get(element);
				scope.set(element, newValue);
			}, scope);
			scope.set("ShowSaveButton", showSaveButton);
			scope.set("ShowDiscardButton", showDiscardButton);
			scope.set("ShowCloseButton", showCloseButton);
			callback.call(scope);
		}
	}, scope );
};

Т.е. на вход подаем список полей для обновления.

Также можно отправлять с сервера сигнал о необходимости обновления полей с помощью вебсокетов, а на клиенте получать сообщения и также с помощью этого метода обновлять.

Чубко Илья,

Добрый день.

Речь идёт не об актуализации перед сохранением, а об актуализации после сохранения, когда значение полей поменялось на стороне сервера, а нам надо продолжить работу с карточкой (значение может поменяться даже не при сохранении данной сущности, а при сохранении другой сущности. К примеру, Вы можете зайти в карточку другого объекта из детали основной карточки, что-то там сделать, сохранить, при сохранении сервер пересчитает поле основной сущности, и Вам нужно это поле обновить, отправив сообщение со страницы карточки, открытой из детали, при этом не потерять изменения, сделанные ранее на основной странице (см. мой пример из поста)).

Пользователю может быть запрещено менять значение поля (сущности основной карточки) на уровне прав. Проблема в том, что при использовании set в Вашем методе мы меняем значение поля на странице и при продолжении работы с карточкой и последующей попытке сохранить получим ошибку, что нет прав на изменение данного поля. Ваш вариант понятен, но он не подходит как раз по тем причинам, по которым приходится переносить автовычисление полей на сторону сервера. Во первых - безопасность, во вторых - гарантия согласованности данных в связанных объектах.

 

PS. По поводу моего "во-вторых" также есть притензия к платформе, заключающаяся в невозможности выполнения методов внутреннего процесса объекта в одной транзакции, но это уже тема для другого поста.

 

PPS. Хотелось бы услышать ещё варианты.

Чубко Илья, 

Да и вообще, не совсем понятно, для чего актуализировать перед сохранением. Помимо того, что сохранить после такой актуализации не получится.

Добрый день, 

Вы можете на необходимой схеме настроить событие "После сохранения записи", в котором реализовать логику публикации сообщения по WebSocket.

После чего заместить ClientMessageBridge, и реализовать рассылку сообщений. И уже после, на необходимой странице, обрабатывать полученное по WebSocket сообщение необходимым образом, к примеру актуализировать значения на странице.

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

Пример: https://academy.terrasoft.ru/documents/technic-sdk/7-8/clientmessagebri…

Добрый день.

Это-то всё понятно, и про рассылку сообщений, и про подписку, вопрос как раз в этой вот обработке "должным образом", как её реализовать наиболее правильно и универсально, чтобы можно было обернуть функциональность в миксин, к примеру, и не опасаться, что на разных страницах будут возникать разные "косяки". Т.е. "научить" страницы заполнять свои поля актуальными значениями не только при открытии страницы...

Есть соображение, что это должно делаться похожим образом с тем, как это делается при начальной инициализации, но когда страница уже загружена - на ней начинают работать dependencies, бизнес-правила и прочее, что было бы, возможно, лишним в данной ситуации. Кроме того при начальном заполнении и изменении значений на загруженной странице, контролы (например, справочные поля, кнопки), ведут себя по-разному. Поэтому тут надо действовать "тонко". Понятно, что придётся использовать EntitySchemaQuery с this.set в цикле в кол-бэке для получения и присвоения значений, но какие-то системные атрибуты страницы, видимо, придётся приводить к значениям "до onEntityInitialized", чтобы, например, не менялось состояние объекта changedValues. Но, в то же время, надо понимать, что при этом могут пострадать "параллельно" работающие процессы в экземпляре страницы. Тут, наверняка, много подводных камней, поэтому задача представляется довольно комплексной.



Уффф... много текста...

Добрый день.

Для загрузки актуальных данных с сервера у наследников BasePage есть метод this.reloadEntity(). В системе есть примеры его вызова на onSaved.

Второй вопрос не совсем понятен. Вы хотите сохранить не сохраненные данные после сохранения? Это что-то вроде, пока шел Save пользователь что-то изменил? Странно, но он не может этого сделать, т.к. будет висеть маска загрузки

Пример:

* меняем что-то на странице физ-лица (не сохраняем)

* заходим на страницу документа - меняем документ на основной

* сохраняем (при этом в физ. лице заполняется текстовое поле документа данными из сохранённой сущности документа)

* закрываем документ - возвращаемся на страницу физ. лица - вот тут надо обновить текстовое поле документ, и, если это сделать при помощи reloadEntity, потеряем сделанные ранее на странице изменения.

Показать все комментарии