Events on the DOM element and the output runtime construct.

Working with events

To bind and work with DOM events at runtime, the framework has its own set of functions (fcf.addDomListener(), fcf.removeDomListener(), fcf.emitDomEvent( )). Which make it easier to work with DOM events. In particular, it removes the need to unbind the event from the wrapper when it is destroyed and redrawn.

For an example of the application of this functionality, we will form two features.

Let's add an effect to our application, in which, when clicking on a moving line, the order of characters will be inverted. We implement this using the fcf.addDomListener() function.

File :templates/blocks/moving-containers+view-item.wrapper.js

... attach(){ this.setPosition(); this.setColor(); fcf.addDomListener(this.getDomElement(), "click", this); return super.attach(); } onClick(a_event){ let string = this.getArg("string"); string = string.split("").reverse().join(""); this.setArg("string", string); } ...

The code is quite simple. Each time the template is updated, we bind the click event handler. Note that this approach is used with the merge template option set to true. When rebinding for the same event handler owner, the event handler is simply replaced, not added.

Now let's look at the result. As you can see, everything works quite simply.

The second feature will be counting the number of bounces of lines from the edges of the container. Based on this feature, we will apply the DOM event call.

Each time it bounces off the container's border, the view-item will dispatch a custom rebound event by calling the fcf.emitDomEvent() function.

File :templates/blocks/moving-containers+view-item.wrapper.js

... setPosition(){ let selfRect = fcf.getRect(this.getDomElement()); let ownerRect = fcf.getRect(this.getParent().select(".moving-containers-view")[0]); let dx = Math.cos(this._radians) / 200; let dy = Math.sin(this._radians) / 200; if ((dx > 0 && (this._x + (selfRect.width / ownerRect.width) + dx > 1)) || (dx < 0 && (this._x + dx < 0))) { this._radians += ((Math.PI / 2) - this._radians) * 2; dx = -dx; fcf.emitDomEvent(this.getDomElement(), "rebound", {}); } else if (((dy > 0) && (this._y + (selfRect.height / ownerRect.height) + dy > 1)) || ((dy < 0) && (this._y + dy < 0))){ this._radians += (Math.PI - this._radians) * 2; dy = -dy; fcf.emitDomEvent(this.getDomElement(), "rebound", {}); } this._x += dx; this._y += dy; let rect = fcf.getRect(this.getParent().select(".moving-containers-view")[0]); this.getDomElement().style.left = (this._x * rect.width + rect.left) + "px"; this.getDomElement().style.top = (this._y * rect.height + rect.top) + "px"; } ...

In the main template code, we will display an HTML element with the number of bounces and add a handler for our new rebound event to the view-item subtemplate, but for this we first need to familiarize ourselves with the output construct with the output runtime construct.

Output runtime construct #{{}}#.

In addition to the @{{}}@ output construct, the framework supports the #{{}}# output construct at runtime. This construction automatically updates the rendered fragment without updating the template when updating the argument in automatic mode. However, due to the fact that the framework has to work directly with DOM elements, the #{{}}# construction has restrictions on usage and can be used either in as rendered content, or as attributes of the DOM element. Also, the render object is not available in the output runtime construct (But this can be fixed if the framework develops successfully).

Let's add a "_reboundCounter" template argument that will store the number of rebounds and display its value using the #{{}}# construction. The "_reboundCounter" value will be incremented by one each time the   "rebound" event handler of the "view-item" subpattern is called

File :templates/blocks/moving-containers.tmpl

... //~ARGUMENTS { _strings: fcf.argProg(), _file: fcf.argVal("/files/background.jpg?dump=@{{fcf.id()}}@"), _reboundCounter: 0 } //~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.setArg('_reboundCounter', parent.getArg('_reboundCounter')+1)" })}}@ %{{ } }}% </div> ...

And let's see the result.