Merge option and background image selection

By default, when a template is updated, DOM elements are replaced, but in some cases it is necessary that instances of DOM elements are not re-created, but their content and attributes are updated. To do this, the framework templates support the merge option. If the value of this option is true, then when the template is updated, the DOM of the tree is merged with the updated state.

Let's consider a case of practical application of the merge template option. Let's add to our functionality the change of the background image. We will implement this simply by changing the "background-image" style for the container with moving lines.

First, copy the file background.jpg to the :files directory. This folder is by default the free download folder of files from the client.

File :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> ...

Please note that we keep the path to the file in the _file variable, using a random full URL generation to avoid caching. This is necessary, since we will later change this picture on the server side.

Now let's add a picture change to the configurator.

File :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>

File :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]); } }; } });

Now let's look at the result.

As you can see, the input field is reset to the previous state. Since, when changing the background, we cause the template to be redrawn and the input element is updated for us. To fix this problem, just set the merge option to true for the main template. In this case, the DOM tree is merged and new elements are not recreated, but updated.

File :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, ...

Now everything should work.