Template argument change events.

In addition to the possibility of referencing, reading and writing data, the functionality of the template arguments supports the ability to monitor the change in the state of the argument. This is implemented through the onArg and onArg[ARG_NAME] methods of the wrapper object. Each time the template argument is changed by the setArg method, the fcf.NClient.Wrapper.onArg and fcf.NClient.Wrapper.onArg[ARG_NAME] methods are called, which can be defined in the wrapper class and act as an observer of the change state of the argument.

Method fcf.NClient.Wrapper.onArg

The fcf.NClient.Wrapper.onArg method is called whenever the template argument changes.

The method has the following signature:

onArg(string a_argName, mixed a_value, fcf.NClient.Wrapper a_editor, bool a_ignoreRedrawing, bool a_isInnerCall, string a_suffix)

Аргументы:

  • string a_argName - Argument name.
  • mixed a_value - New set value.
  • fcf.NClient.Wrapper a_editor - The object on which the setArg method was called. When using references, a_editor and this may not be equal
  • bool a_ignoreRedrawing - Flag that disables redrawing. Set by setArg method.
  • bool a_innerCall - Internal call flag from the template itself, used to build internal processing logic. Set by setArg method.
  • string a_suffix - The path of the value in the argument to change.

Method fcf.NClient.Wrapper.onArg[ARG_NAME]

Unlike the fcf.NClient.Wrapper.onArg method, the fcf.NClient.Wrapper.onArg[ARG_NAME] method is called whenever a specific template argument is changed. The full method name is formed from the onArg prefix and the ARG_NAME suffix. The suffix is the name of the template argument starting with a capital letter.

The method has the following signature:

onArg[ARG_NAME](mixed a_value, fcf.NClient.Wrappera_editor, bool a_ignoreRedrawing, bool a_isInnerCall, string a_suffix)

Аргументы:

  • mixed a_value - New set value.
  • fcf.NClient.Wrapper a_editor - The object on which the setArg method was called. When using references, a_editor and this may not be equal
  • bool a_ignoreRedrawing - Flag that disables redrawing. Set by setArg method.
  • bool a_innerCall - Internal call flag from the template itself, used to build internal processing logic. Set by setArg method.
  • string a_suffix - The path of the value in the argument to change.

Practical application of the fcf.NClient.Wrapper.onArg method

Let's add to our application a change in the state of the "enable" argument for the "Save" button. This argument is responsible for the button activity. If the template arguments have not been changed, the "enable" state will be false, and the first time the configuration is edited, it will change to true.

We will implement this using the onArg method. The ability to track template argument changes gives you more development flexibility. It is for this task that this technique is best suited. So yes, it relieves the programmer of the task of tracking the change in arguments or creating sets of separate functions to set values.

Let's get started. In the _modify argument, we will store the state of changing the arguments, this argument will be passed to the "Save" button template by reference as the "enable" argument.

File :templates/blocks/moving-containers.tmpl

... //~ARGUMENTS { _strings: fcf.argProg(), _file: fcf.argVal("/files/background.jpg?dump=@{{fcf.id()}}@"),
_reboundCounter: 0, _modify: false } //~TEMPLATE <div class="moving-containers-view" style="background-image: url(@{{args._file}}@);"> <div class="moving-containers-view-info"> Rebound counter: <span name="rebound_counter">#{{args._reboundCounter}}#</span> </div> %{{ for(let i = 0; i < args._strings.length; ++i) { }}% @{{ render.template( "+view-item", { string: fcf.argRef(`_strings[${i}]`), fcfEventRebound: "parent.onReboundString(event)" })}}@ %{{ } }}% </div> <fieldset> <legend>Editor</legend> @{{ render.template("@controls:tabs", { items: fcf.argVal({ strings: { title: "Strings", data: fcf.argTmpl("+strings", {strings: fcf.argRef("_strings")}) }, settings: { title: "Settings", data: fcf.argTmpl("+settings") } }) }); }}@ @{{ render.template("@controls:button", {title: fcf.t("Save"), enable: fcf.argRef("_modify"), fcfEventClick: "parent.onSave()"}); }}@ ...

And add work with the _modify argument to the wrapper file

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); } onArg(a_argName, a_value, a_editor, a_ignoreRedrawing, a_isInnerCall, a_suffix) { if ((a_argName == "_strings" || a_argName == "_file") && !this.getArg("_modify")) { this.setArg("_modify", true); } } 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]); } onSave() { this.send({strings: this.getArg("_strings")}, [this.select("input[type='file']")[0]]); this.setArg("_modify", false); } }; } });

As you can see, the functional code takes only a few lines. Now let's look at the result.