Loading content asynchronously

Responder
Avatar de Usuario
ricardo arraes
Mensajes: 87
Registered for: 3 years 5 months
Brazil

Loading content asynchronously

Mensaje por ricardo arraes »

Hey everybody!

I know I've been gone for a while, but I'm back with some content that I think it could be useful and I'd like to share with you some of that experiences...

This time I'd like to share with you how I load content asynchronously on my applications...

well, first of all, why loading content asynchronously is so important?

1- provides a better user experience because your page will load all of its elements without freezing while the content is being loaded;
2- improves the performance of you application, simply because now you can load as many things as you want simultaneously and independently

Basically, what is the logic behind all that?

We'll have our website, developed with mod_harbour and HTML/CSS and javascript. Inside our page(s) there'll be a script that is going to use AJAX in order to send requests to a route from our application that will work as a webservice, processing and retrieving the content we need and the script will be responsible for organizing this content inside our page.

Now, let's go step by step:

STEP 1: creating routes

First of all, let's create our routes...

Código: Seleccionar todo

DEFINE APP oApp TITLE 'vfatec';
		ON INIT Config() ;
		CREDENTIALS 'teste' COOKIE 'teste'

		DEFINE ROUTE 'root'  			URL '/' 	 		 	CONTROLLER 'home@controller.prg' 			METHOD 'GET'  OF oApp

		DEFINE ROUTE 'get-content'		URL 'get-content'		CONTROLLER 'getContent@ws.prg'			METHOD 'GET' OF oApp

	//Inicialização da aplicação
	INIT APP oApp 

STEP 2: creating the controller.prg

let's create our first controller.
this controller basically is responsible for the navigation.

Código: Seleccionar todo

CLASS controller

    METHOD New(oController) CONSTRUCTOR

    
    METHOD home(oController)  
        

ENDCLASS

METHOD New(oController) CLASS controller

RETURN Self

METHOD home(oController) CLASS controller
    oController:View("/home.view")
RETURN NIL

STEP 3: creating the ws.prg

this controller is going to be our own webservice, it will be responsible for processing the async requests that we are about to send and retrieve the content.

*I'm using my TMySQL class to manipulate the database

Código: Seleccionar todo

CLASS WS

    METHOD New(oController) CONSTRUCTOR
    
    METHOD getContent(oController)

    
ENDCLASS

METHOD New(oController) CLASS WS


RETURN Self

METHOD getContent(oController) CLASS WS

    LOCAL oTable,hResponse:={=>},aParam:={},hData:={=>}

    hData:=oController:oRequest:GetAll()
    
    Aadd(aParam,hData['param1'])
    Aadd(aParam,hData['param2'])    
    Aadd(aParam,hData['param3'])
    
    cQuery := "SELECT * FROM content WHERE field1='PARAM01' AND field2='PARAM02' AND field3 = 'PARAM03' "
       
    oTable  :=  App():oBD:QueryJson(cQuery,aParam)
    
	oController:oResponse:SendJson(oTable)

RETURN NIL

STEP 4: create our home.view

right here we are creating the only view from our application. could be our home page...
notice that I got a #content-div element. That's where our content will be loaded and located. But while it's not loaded I placed a loader inside of it just to make sure the user will be informed that something is loading on my page.

Now, take a look at the end of our view, there's a script being executed... as soon as my page is loaded a function will be executed and will send an async request via AJAX to the webservice we created.

as soon as the webservice retrieve the content (JSON), the callback function will organize the HTML elements in order to display the content properly and them... it will replace everyting inside the #content-div element (which, in this case, is just the loader element) with the new content.

Código: Seleccionar todo


{{View('/head.view')}}

<section class="pt-8" style="background-color: whitesmoke;">
  <div class="container">
    <div class="row">
      <div class="col-12">

        <!-- Heading -->
        <h2 class="mb-10 text-center">Content</h2>

      </div>
    </div>
    <div class="row" id="content-div">
      <div class="loader mx-auto"></div>
    </div>
  </div>
</section>




      <!-- JAVASCRIPT -->
      <!-- Libs JS -->
      <script src="/teste/lib/@fancyapps/fancybox/dist/jquery.fancybox.min.js"></script>
      <script src="/teste/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/feather-icons/4.9.0/feather.min.js"></script>
      <script src="https://cdn.jsdelivr.net/npm/js-cookie@rc/dist/js.cookie.min.js"></script>
  
  
    <script>

window.onload = function() {   
    

        var div = document.querySelector('#content-div');
        

        $.ajax({

            type: "GET",
            url: "http://localhost/teste/get-content?param1=X&param2=Y&param3=Z",              

        }).done(function(data,status) {
        
            var prodhtml=""
            for(var i = 0; i < data.length; i++) 
            {
                var obj = data[i];
                
                if(i % 5==0)
                {
                    prodhtml+='<div class="w-100 d-none d-lg-block"></div>'
                }

                prodhtml+='<div class="col-6 col-md-3 col-lg">'+                                        
                                '<div class="card mb-7" data-toggle="card-collapse">'+                                        
                                    '<a href="#">'+
                                        '<img class="card-img-top" src="img/content/'+obj.field1+'.jpg" alt="..." onerror="this.onerror=null; this.src='+"'img/content/00000.jpg'"+'" />'+
                                    '</a>'+
                                    '<div class="card-collapse-parent">'+                                            
                                        '<div class="card-body px-0 bg-white text-center">'+
                                            '<div class="mb-1 font-weight-bold">'+
                                                '<a class="text-body" href="#">'+obj.field2+'</a>'+
                                            '</div>'+                                            
                                            '<div class="mb-1 font-weight-bold text-muted">'+
                                                '$'+obj.field3+
                                            '</div>'+                                                                                        
                                        '</div>'+                                                                                    
                                    '</div>'+
                                '</div>'+
                            '</div>'
                
                    
                
            }
            div.innerHTML=prodhtml

        }).fail(function(xhr, status, error) {


        });
    }


    </script>

  </body>
</html>




*There are some security improvements to be made, but I tried to make this example as simple as possible for you guys to understand the whole idea :)

Hope it helps you!
The work always comes before the belief

ramirezosvaldo
Mensajes: 127
Registered for: 3 years 5 months
Mexico

Mensaje por ramirezosvaldo »

Thanks a lot

If where possible, could you upload a little video how you web page look it ?

Thanks in advance
Osvaldo Ramirez

Avatar de Usuario
ricardo arraes
Mensajes: 87
Registered for: 3 years 5 months
Brazil

Mensaje por ricardo arraes »

Hey Osvaldo, sure, here it is:




In this video I'm refreshing three times my page (the first one is a little bit slow, not sure why... :lol: )
As you can see, the page loads before the content itself retrieved by the async request.

if I haven't implemented the async request, probably my page would take a little more seconds to load, and depending on the amount of data it requires, could seems like it's freezing...
The work always comes before the belief

Otto
Mensajes: 50
Registered for: 3 years 5 months
Austria

Mensaje por Otto »

Hello friends,
We use asynchronous loading in our web page, too.

It is an appointment management similar to a desk folder or a monthly folder.
We only use the file-system and no databases.
A folder is created for each day.
The appointments are then moved into the corresponding day folder as an HTML file.
All the JPG are stored in small and large size. First all JPGs are loaded and then we load the large ones and replace the small ones. You see a meter at the top of the webpage, showing the status.


Sincerely
Otto

https://mybergland.com/fwforum/scheduler.mp4

Imagen

Imagen

Avatar de Usuario
ricardo arraes
Mensajes: 87
Registered for: 3 years 5 months
Brazil

Mensaje por ricardo arraes »

great Otto!

async requests give us a lot of possibilities to work with!

Otto escribió: Jue Jun 03, 2021 10:36 pm Hello friends,
We use asynchronous loading in our web page, too.

It is an appointment management similar to a desk folder or a monthly folder.
We only use the file-system and no databases.
A folder is created for each day.
The appointments are then moved into the corresponding day folder as an HTML file.
All the JPG are stored in small and large size. First all JPGs are loaded and then we load the large ones and replace the small ones. You see a meter at the top of the webpage, showing the status.


Sincerely
Otto

https://mybergland.com/fwforum/scheduler.mp4

Imagen

Imagen
The work always comes before the belief

Responder