Сохранение состояние окна в URL
Общие принципы
-
Форма не должна содержать возможность прямого редактирования
-
Редактирование данных должно осуществляться только через диалоговое (модальное) окно
-
Изменения в форме (содержание полей ввода, кнопки и т.п.) могут только менять параметры отображения формы (фильтрация данных, отображение диалогов, скрытие/раскрытие кусков формы). Применение любых параметров возможно только через посредничество строки URL: пользователь меняет параметр → изменение отражается в URL → изменение применяется посредством считывания URL
Типовые исключения
-
Объем сохраняемых параметров потенциально очень большой. Например, перечень строк выделенных чек-боксами в табличном гриде.
Общие функции, обеспечивающие сохранение состояния в URL
mapParamFromUrl(context: { [k: string]: any }, route: { [k: string]: any }, variableName: any, alias: string) {
let paramName = variableName.name.split(/\W+|(?=[A-Z])|_/g).join("-").toLowerCase();
if (alias) {
paramName = alias + '-' + paramName;
}
switch (variableName.type) {
case 's':
context[variableName.name] = route[paramName];
break;
case 'n':
context[variableName.name] = Number(route[paramName]);
break;
case 'b':
context[variableName.name] = String(route[paramName]) === 'true';
break;
case 'a':
context[variableName.name] = route[paramName];
break;
default:
break;
}
}
mapParamsFromUrl(context: { [k: string]: any }, route: { [k: string]: any }, variableNames: any, alias: string) {
for (let variableName of variableNames) {
this.mapParamFromUrl(context, route, variableName, alias);
}
}
trySetTimeout(f: any) {
let last_timeout
clearTimeout(last_timeout);
last_timeout = setTimeout(() => {
f()
}, TIMER_INTERVAL);
}
Основной переиспользуемый код для табличной формы
Отслеживание изменений различных параметров
watch: {
// Параметры пагинации и сортировки
options: {
handler() {
this.setUrlByModelFilter();
this.getDataFromApi(this.mapModelToUrl());
},
deep: true,
},
// Параметры фильтрации
dates: {
handler() {
this.setUrlByModelFilter();
},
deep: true,
},
// Изменение маршрутизации страницы
'$route': function (route) {
this.onRouter(route);
}
},
Изменение URL
setUrlByModelFilter() {
this.$router.push({
path: this.$route.path,
query: {
...this.mapModelToUrl()
},
}, () => {
});
},
setUrlByModelFilterWithTimeout() {
this.$utils.trySetTimeout(this.setUrlByModelFilter);
},
Формирование параметров URL
mapModelToUrl() {
let parameters: { [k: string]: any } = {};
parameters['items-per-page'] = this.options.itemsPerPage ? this.options.itemsPerPage : 50;
parameters['page'] = this.options.page ? this.options.page : 1;
parameters['sort-by'] = this.options.sortBy[0] ? this.options.sortBy[0] : 'date_start';
parameters['sort-desc'] = this.options.sortDesc[0] ? this.options.sortDesc[0] : false;
if (this.dateFormatted && this.dateFormatted2 && this.dates.length === 2) {
if ((this.dates[0] && this.dates[1]) && this.dates[0] <= this.dates[1]) {
parameters['multicase_date_start'] = this.parseDate(this.dateFormatted);
parameters['multicase_date_end'] = this.parseDate(this.dateFormatted2);
} else {
parameters['multicase_date_start'] = this.parseDate(this.dateFormatted2);
parameters['multicase_date_end'] = this.parseDate(this.dateFormatted);
}
}
return parameters;
},
mapUrlToModel(parameters: { [x: string]: any; }) {
// todo: Функции установки сортировки о постраничного просмотра должны быть общими
if (parameters['items-per-page'] && parameters['page']) {
this.options.itemsPerPage = Number(parameters['items-per-page']);
this.options.page = Number(parameters['page']);
} else {
this.options.itemsPerPage = 50;
this.options.page = 1;
}
if (parameters['sort-by']) {
this.options.sortBy = [parameters['sort-by']];
this.options.sortDesc = [String((parameters['sort-desc'])) === 'true'];
} else {
this.options.sortBy = ['date_start'];
this.options.sortDesc = [false];
}
// todo: Добавить значения по умолчанию в функцию мэппинга
if (parameters['multicase_date_start'] && parameters['multicase_date_end']) {
this.$utils.mapParamsFromUrl(this, parameters,
[
{name: 'multicase_date_start', type: 'd'},
{name: 'multicase_date_end', type: 'd'},
], '');
this.dates = [parameters['multicase_date_start'], parameters['multicase_date_end']];
this.onDatePickerValueChanged();
}
},
Вызов обработки изменения URL при первоначальном создании страницы
created() {
this.onRouter(this.$route);
},
Обработка изменения URL
onRouter(route: { query: any; }) {
this.mapSession();
this.mapUrlToModel(route.query);
this.getDataFromApi(this.mapModelToUrl());
this.mapSession();
},