Friendly Open Space JS: Client-Side Rendering and Wrapper Creation

Friendly Open Space is a very young framework, but already knows how to run :-)



In this article on the development of "Friendly Open Space", we will master the rendering of the template in the browser and launching the application on the local file database.



The core of the framework supports two types of template assembly on the client:



  1. Full client side rendering
  2. A request is made to render the template to the server, followed by its output in the browser window.


The first mode has one feature, the data necessary for rendering the template is requested from the server, i.e. the client executes FSQL queries. There is no particular danger in this if you use the access restriction and the fosAccess module, but there is the possibility of unloading raw data by copy pasteur. However, this approach significantly reduces the load on the server.



The second type of rendering is already devoid of this feature. The client sends the template parameters and receives already from the HTML server. Yes, the load on the server will certainly increase, but such a method is more suitable for open Internet solutions.



Preparing the application and setting it up



And so, we are faced with the task of creating a one-page application that will render 2 templates (windows) on the client side. In view of a fairly simple task, we will do without a MySQL database and projections, so we will direct all FSQL work to a file, i.e. we will use the database on the file to work with the internal mechanisms of the framework. Well, let's get started.



Create the directories:



templates - templates directory

css - directory of css files

fos - download the latest beta friendlyopenspace.site/en/download

Place the annoying favicon.ico in the root directory of the application: favicon.ico



Also, immediately place the styles files in the css directory: window.css and styles.css



Next, create the application.js application file itself:



var fos = require("./fos/fos"); fos.module({ name: "application.js", dependencies: [ "fos:NServer/Application.js", ], module: function(application) { application.setSettings({ port: 3001, packages: [], dynamicLoading: true, clientRenderingMode: "client", dataClient: { defaultConnection: "default", connections: { default: { type: "file", file: "data.fosdb" } }, }, onInitialize: function(a_event) { if (!a_event.error) { application.run(); } else { console.error(a_event.error); } } }); application.getRouter().add([ { route: "", controller: "fos:NServer/NControllers/Tmpl.js", source: "templates/page.tmpl", }, { route: "/css/*", controller: "fos:NServer/NControllers/File.js", source: "css", }, { route: "/templates/*", controller: "fos:NServer/NControllers/File.js", source: "templates", }, { route: "favicon.ico", controller: "fos:NServer/NControllers/File.js", source: "favicon.ico", }, ]); application.initialize(); } });
      
      





Now let's look at the contents of the application.js file



We disabled all packages, as they were not needed (the packages parameter of the setSettings method):



  ... application.setSettings({ port: 3001, packages: [], dynamicLoading: true, clientRenderingMode: "client", ...
      
      





The clientRenderingMode application parameter, new to us, is responsible for the type of rendering on the client and has two values:



"Client" - rendering is performed entirely by the browser. The client independently loads the dependencies and executes FSQL queries to the server, after which it collects the HTML itself



“Server” - the client makes a request to the server to render the template and receives ready HTML as a response



  ... packages: [], dynamicLoading: true, clientRenderingMode: "client", dataClient: { defaultConnection: "default", ...
      
      





And the last innovation for us is connecting a database on a file. The framework cannot fully work without the ability to process configuration variables that have a table structure. Therefore, instead of MYSQL, we will use a regular file.



 ... defaultConnection: "default", connections: { default: { type: "file", file: "data.fosdb" } }, }, ...
      
      





As can be seen from the above excerpt, in this case the database type (type parameter) is “file”, and the only connection parameter file should contain the path to the data file. If the file is missing, the application will create it yourself.



Create Page Template



Now it's time to create the application page template file templates / page.tmpl, which we have registered in the root URL route.



 //~OPTIONS { args:{ fosInclude: ["css/styles.css"], } } //~BLOCK main default <!DOCTYPE html> <html> <head> <meta charset="utf-8"/> %{{ render.renderHTMLHeader(); }}% <script> function onClientSideRendering(a_event){ a_event.preventDefault(); fos.application.render({ template: "templates/window.tmpl", owner: document.body, args: { title: "Client side rendering", context: "Simple example of client side rendering" }, onResult: function(a_error, a_template){ } }); } function onServerSideRendering(a_event){ a_event.preventDefault(); fos.application.render({ template: "templates/window.tmpl", owner: document.body, renderMode: "server", args: { title: "Server side rendering", context: "Simple example of server side rendering" }, onResult: function(a_error, a_template){ } }); } </script> </head> <body> <div class="mainwrapper"> <div class="header markup"> Client Side Rendering </div> <div class="body-wrapper markup"> <div class="body markup"> <p class="example-link--container"><a onclick="onClientSideRendering(event);">Client side rendering</a></p> <p class="example-link--container"><a onclick="onServerSideRendering(event);">Server side rendering</a></p> </div> <div class="clear-body"></div> </div> </div> </body> </html>
      
      





The page template has two links, “Client side rendering” & “Server side rendering”. Clicking on which will display windows that are not yet available. But there is a code to call them. And so let's figure out the template code.



When we click on the “Client side rendering” link, we call the onClientSideRendering () function, which renders the “templates / window.tmpl” template. Completely on the client side, as in the application settings, the clientRenderingMode parameter was set to "client". Despite the fact that this is the default value :-).



 function onClientSideRendering(a_event){ a_event.preventDefault(); fos.application.render({ template: "templates/window.tmpl", owner: document.body, args: { title: "Client side rendering", context: "Simple example of client side rendering" }, onResult: function(a_error, a_template){ } }); }
      
      





The render method actually renders our window and places it in the body of the page, as specified in the property of the owner argument. We pass 2 arguments to the window template: title & context, in fact, what will be displayed in the displayed window. For more information about the method, see fos :: NClient :: Application :: render



The second link calls the onServerSideRendering () function, which similarly renders the same template, but on the server side, and the client receives ready-made HTML. This mode is set in the property of the renderMode argument of the render method to "server".



 function onServerSideRendering(a_event){ a_event.preventDefault(); fos.application.render({ template: "templates/window.tmpl", owner: document.body, renderMode: "server", args: { title: "Server side rendering", context: "Simple example of server side rendering" }, onResult: function(a_error, a_template){ } }); }
      
      





Creating a pop-up template and writing a wrapper template



The popup window template itself is very simple. Create the templates / window.tmpl file. The following is its contents.



 //~OPTIONS { args:{ fosWrapper: true, fosClass: "window", fosInclude: ["css/window.css"], title: "", context: "", } } //~BLOCK main default <div class="window-container"> <div class="window-close" name="close">x</div> <div class="window-title">${{args.title}}$</div> <div class="window-context">${{args.context}}$</div> </div>
      
      





Here for you there are two new parameters fosWrapper and fosClass.



Let's start with fosWrapper. If this flag is set to true, then the HTML template is placed in the span container and a wrapper object fos :: NRender :: Wrapper is created for it.



Launch the application, go to localhost : 3001 and click on the link “Client side rendering”. The pop-up window is our template. Window popup is implemented entirely by css (css / window.css file) - I just mentioned that you would not be looking for hidden JS :-).



Open the DevTools browser (Ctrl + Alt + i), go to the Elements tab and review the structure of our window.



image



The blue line in the figure marks our span wrapping container with which the fos :: NRender :: Wrapper object is connected.



The next system argument to the template is fosClass. It simply adds a CSS class to the wrapper span container.



And so, everything was done well, but if we try to close our pop-ups, nothing will come of it. Yes, we have not written a closing operation yet!



As we said earlier, if the fosWrapper system argument is true, then the wrapper object fos :: NRender :: Wrapper is created for the template. It provides a standard interface for interacting with the template on the client. To redefine the standard wrapper for a template, it is enough to create a module with the name corresponding to the following format [PATTERN NAME] .wrapper.js, and the module should be inherited from the class fos :: NRender :: Wrapper.



Now create a wrapper file for the templates / window.tmpl template. The new class will have to close our pop-up window, when you click on the symbol "x".



File templates / window.wrapper.js:



 fos.module({ name: "templates/window.wrapper.js", dependencies: ["fos:NRender/Wrapper.js"], module: function(Wrapper){ return function(a_initializeOptions) { var self = this; Wrapper.call(this, a_initializeOptions); var parentAttach = this._attach; this._attach = function(a_cb) { parentAttach.call(this, function(){ fos.addDomListener(fos.select(self.getDomElement(), "[name=close]")[0], "click", function(){ self.getDomElement().classList.add("window-hide"); setTimeout(function() { self.destroy(); }, 2000); }); a_cb(); }); } } } });
      
      





Let's analyze the contents of our module. First, we connect the base class fos :: NRender :: Wrapper and inherit from it through the call method.



 fos.module({ name: "templates/window.wrapper.js", dependencies: ["fos:NRender/Wrapper.js"], module: function(Wrapper){ return function(a_initializeOptions) { var self = this; Wrapper.call(this, a_initializeOptions); ...
      
      





After we redefine the method fos :: NRender :: Wrapper :: _ attach, which is called when the template is associated with the object. In this method, we will connect the event of clicking on the link to close the window. Overriding is done simply by declaring the method, but in the beginning we must keep the reference to the parent implementation. The method has an “asynchronous nature”, so we put the implementation of our actions in the callback function of the parent implementation.



  ... var parentAttach = this._attach; this._attach = function(a_cb) { parentAttach.call(this, function(){ fos.addDomListener(fos.select(self.getDomElement(), "[name=close]")[0], "click", function(){ self.getDomElement().classList.add("window-hide"); setTimeout(function() { self.destroy(); }, 2000); }); a_cb(); }); } ...
      
      





Connecting to the event of clicking on the symbol “x” we perform by calling fos :: addDomListener, which does not reset the connected events when changing the parent of the DOM element.



In the event handler, we close the window. First, we nicely remove the window from the screen by adding the CSS class “window-hide”. After the animation is completed, we call the fos :: NRender :: Wrapper :: destroy method, which removes the template and the wrapper object.



ALL APPLICATION WRITTEN, LAUNCHED AND REJOINT !!!



 node application.js
      
      





Official development site



Link to an example



All Articles