По умолчанию, при обновлении шаблона происходит замена DOM элементов, но в некоторых случаях необходимо что бы экземпляры DOM элементов не пересоздавались, а выполнялось обновление их содержимого и аттрибутов. Для этого шаблоны фреймворка поддерживают опцию merge. Если значение данной опции равно true, то при обновлении шаблона выполняется слияние DOM дерева с обновленным состоянием.
Рассмотрим случай практического применения опции шаблона merge. Добавим к нашему функционалу смену картинки заднего фона. Это будем реализовывать просто изменением стиля "background-image" для контейнера с движущимися строками.
Для начала скопируйте файл background.jpg в директорию :files. Данная папка по умолчанию является папкой свободной загрузки файлов с клиента.
Файл :templates/blocks/moving-containers.tmpl
...
//~ARGUMENTS
{
_strings: fcf.argProg(),
_file: fcf.argVal("/files/background.jpg?dump=@{{fcf.id()}}@")
}
//~TEMPLATE
<div class="moving-containers-view" style="background-image: url(@{{args._file}}@);">
%{{
for(let i = 0; i < args._strings.length; ++i) {
}}%
@{{
render.template(
"+view-item",
{
string: fcf.argRef(`_strings[${i}]`),
})}}@
%{{
}
}}%
</div>
...
Обратите внимание, что путь к файлу мы держим в переменной _file, используя генерацию случайного полного URL, для исключения кэширования. Это необходимо, так как мы в последствии будем менять эту картинку на стороне сервера.
Теперь добавим в конфигуратор смену картинки.
Файл :templates/blocks/moving-containers.tmpl
...
//~TEMPLATE
...
<legend>Editor</legend>
@{{
render.template("@controls:tabs", {
items: fcf.argVal({
strings: {
title: "Strings",
content: fcf.argTmpl("+strings", {strings: fcf.argRef("_strings")})
},
settings: {
title: "Settings",
content: fcf.argTmpl("+settings")
}
})
});
}}@
...
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~ SUBTEMPLATE settings
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~TEMPLATE settings
JPG background file:
<p>
<input type="file" autocomplete="off" fcfEventChange="parent.getParent().onFile()"></input>
</p>
Файл :templates/blocks/moving-containers.wrapper.js
fcf.module({
name: "templates/blocks/moving-containers.wrapper.js",
dependencies: ["fcf:NClient/Wrapper.js"],
module: function(Wrapper){
return class WrapperImpl extends Wrapper{
constructor(a_initializeOptions) {
super(a_initializeOptions);
}
onRemoveString(a_index) {
let strings = this.getArg("_strings");
strings.splice(a_index, 1);
this.setArg("_strings", strings);
this.update();
}
onAddString() {
let strings = this.getArg("_strings");
strings.push("")
this.setArg("_strings", strings);
this.update();
}
onFile() {
let self = this;
let fileReader = new FileReader();
fileReader.onload = () => {
self.setArg("_file", fileReader.result);
self.update();
}
fileReader.readAsDataURL(this.select("input[type=file]")[0].files[0]);
}
};
}
});
Теперь давайте посмотрим на результат.
Как видно происходит сброс поля input в предыдущие состояние. Так как, при смене заднего фона мы вызываем перерисовку шаблона и у нас обновляется элемент input. Для устранения этой проблемы достаточно установить опцию merge в значение true для основного шаблона. В этом случае происходит слияние DOM дерева и новые элементы не пересоздаются, а обновляются.
Файл :templates/blocks/moving-containers.tmpl
//~OPTIONS
{
...
// DOM elements merge flag.
// If true, then existing items are not replaced when updated, but updated.
// Default: false
merge: true,
...
Теперь все должно работать.