Опция merge и выбор фонового изображения

По умолчанию, при обновлении шаблона происходит замена 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, ...

Теперь все должно работать.