SapUI5: Событие после загрузки данных (after loading data) / отрисовки элемента (after render)

Привет!
Сам по себе JavaScript код синхронный, события выполняются последовательно, шаг за шагом.
Но, CRUD (create, read, update, delete — «создать, прочесть, обновить, удалить») функции работают асинхронно.

Событие после загрузки данных (after loading data)

То есть Вы можете послать запрос в Backend для чтения данных, а компилятор пойдет выполнять код дальше, не дожидаясь ответа!

Ответ можно поймать в callback’е:

oModel.read("/EmployeeDataSet", {
 
//Читаем oData и устанавливаем фильтр
	filters: [new Filter({
		path: "Pernr",
		operator: "EQ",
		value1: pernr
	})],
 
//в случае успешного выполнения будет отработан callback success
	success: function(oData, response) {
 
 
	},
 
//в случае ошибки будет отработан callback success
	error: function() {
 
	}
});

Чем это плохо?
Плохо это тем, что если нам понадобятся данные, которые мы пытаемся загрузить из бэкенда, то они будут не доступны до тех пор, пока не отработает callback.

Решается это просто, при помощи обещаний (Promise)!

Promise (обещание) – это специальный объект, который содержит своё состояние. Вначале pending («ожидание»), затем – одно из: fulfilled («выполнено успешно») или rejected («выполнено с ошибкой»).

promise

Пересказывать всю теорию я не буду, подробней про обещания читайте тут — https://learn.javascript.ru/promise.

Перейдем к более конкретному примеру.

Нам надо загрузить данные, создать 3 модели в приложении а только после создания моделей продолжить выполнять код.

getPersonalization: function(pernr) {
	//ссылка на компонент
	var oComp = this.getOwnerComponent();
 
	//Вызываем методы чтения данных
	Promise.all([		models.createEmplModel(oComp, pernr),
		models.createBlockModel(oComp),
		models.createGroupModel(oComp)
	])
	.then(function(result) {		//Устанавливаем модели только после того, как методы прочитали данные
		oComp.setModel(result[0], "oEmplMdl");
		oComp.setModel(result[1], "oBlockMdl");
		oComp.setModel(result[2], "oGroupMdl");
 
		//после обновления данных продолжаем выполнять необходимый код
		this.initView(pernr);
 
	}.bind(this), function(err) {		//ошибка выполнения
	});
 
}

Разберем что написано выше!
Мы вызываем методы createEmplModel, createBlockModel, createGroupModel. Только тогда, когда каждый вернет сообщение о том, что данные загружены, компилятор пойдет дальше выполнять код, а конкретно, он попадет в блок, после then и установит на компонент три модели.

Посмотрим, что из себя представляет метод запроса данных:

createEmplModel: function(that, pernr) {
	//Возьмем модель
	var oModel = that.getModel("oDataMdl");
 
	//Пока данные в процессе чтения, пусть крутиться индикатор загрузки
	oModel.attachBatchRequestSent(function() {
		that.openBusyDlg();
	});
 
	//После чтения данных убираем индикатор загрузки
	oModel.attachBatchRequestCompleted(function() {
		that.closeBusyDlg();
	});
 
	//Создаем наше Обещание
	var promise = new Promise(function(resolve, reject) { 
		//Читаем EmployeeDataSet
		oModel.read("/EmployeeDataSet", {
 
			//установим параметр для чтения
			filters: [new Filter({
				path: "Pernr",
				operator: "EQ",
				value1: pernr
			})],
 
			//В случае успешного чтения:
			success: function(oData, response) {
				//Создадим JSON модель
				var oEmpModel = new sap.ui.model.json.JSONModel({});
 
				//Установим данные, которые вернул нам сервис oData, на модель
				oEmpModel.setData(oData.results[0]);
 
				//Вернем Promis'у Json модель
				resolve(oEmpModel);			},
 
			//В случае ошибки:
			error: function(err) {
				//Передадим в Promise, что у нас случилась какая-то ошибка
				reject(err);			}
		});
	});
 
	return promise;}

Все довольно просто!

  • Создали обещание (Promise).
  • Запросили данные. Если все прочиталось успешно, то вернули модель resolve(oEmpModel), если ошибка, то вызываем reject(err).

Событие после отрисовки элемента (after render control)

Представьте, вы динамически наполняете страницу элементами в контроллере.
Например, рисуете поле ввода мобильного телефона:

var oInput = new sap.m.MaskInput({
	mask: "+7 (~~~) ~~~-~~-~~",
	placeholder: "Введите номер телефона",
	placeholderSymbol: "_",
	value: fieldObj.Fieldvalue,
	id: Utils.toTranslit(fieldObj.Fieldlabel) + "_input",
	rules: [new sap.m.MaskInputRule({
		maskFormatSymbol: "~",
		regex: "[0-9]"
	})]
}).addStyleClass("input");

И хотите повесить на данный элемент событие .keypress(). Чтобы при каждом вводе символа в строку вызывался метод.
Сделать это будет проблематично лишь потому, что элемент мы объявили, но в DOM модели его еще нет, он просто не отрисован!

Как один из вариантов решения данной задачи — расширить событие onAfterRendering для данного элемента!

oInput.addEventDelegate({
	"onAfterRendering": function(id) {
 
		// установим обработчик события keypress на телефоне
		$(id + "_input").keypress(function(eventObject) {
				//Нажали кнопку
		});
 
	}.bind(this, "#" + Utils.toTranslit(fieldObj.Fieldlabel))
 
}, this);

После отрисовки элемента будет установлен обработчик на поле ввода.
Как получить нажатый символ читаем тут https://learn.javascript.ru/keyboard-events.
Удачи :).