We're Almost Done...

We're Almost Done...

The JavaScript code will now generate the table code that represents the contacts (CliFou module). Not just yet.

We’ve observed that both modules utilize xhr.onreadystatechange = () => { ... }, which clearly indicates that their processing should be localized within the code of this XMLHttpRequest event. If you opt for a single definition while managing hundreds of modules or components scattered throughout your site, it could quickly become a nightmare to handle all potential behaviors.

Take, for example, the four small modules we currently have; each could exhibit both a 'browse' behavior and a 'form' behavior. That already gives us a total of eight variations. Now, considering what I have in mind, we could easily end up with a hundred different modules: a search module, a weather module, a recipe module, a geolocation module, a technology watch module, a document management module, a meeting management module, a board meeting management module, a service sheet management module, a project management module... the list is endless.

Moreover, for each of these modules, we could introduce sub-modules. For instance, the marketing suite might include a campaign management module, a mass SMS sending module, an email shot module, and so on. Managing all these different behaviors within the same xhr.onreadystatechange event simply isn’t feasible.

What we need is to develop a robust "handler" system: each module can have its own handler—a callback that is invoked at the appropriate moment. This is precisely what we’re going to implement, and I’ll show you how to do it in the simplest way possible. We’re heading towards something like this:" Feel free to let me know if you need any further adjustments!

<section>
   <quitus-module id="QM_ac0dd673-82ba-4e61-b021-c5b0443b0f75" data-module="clifou" data-function="browse" data-start-recno="1" data-handler="myHandler1">blablabla</quitus-module>

    <hr />

   <quitus-module id="QM_95d40c32-c2e7-4ed2-b21e-b815b521f9c0" data-module="clifou" data-function="form" data-start-recno="88" data-handler="myHandler2">blablabla</quitus-module>

</section>        

Notice the new attributes data-handler="myHandler1" and data-handler="myHandler2", which are defined as follows:

function myHandler1( oJSON )
{
    console.log( 'WITH HANDLER 1',oJSON );
}
function myHandler2( oJSON )
{
    console.log( 'WITH HANDLER 2',oJSON );
}        

Here is the adaptation of connectedCallback():

connectedCallback()
/*---------------*/
{
    // Get all attributes
    const attributes = this.attributes;
    const params = [];

    // Add each attribute and its value to aan array of parameters
    for ( let i = 0; i < attributes.length; i++ )
    {
        const attr = attributes[i];
        params.push(`${encodeURIComponent(attr.name)}=${encodeURIComponent(attr.value)}`);
    }

    // Create the XMLHttpRequest
    const xhr = new XMLHttpRequest();
    // Endpoint of my service
    const url = '/services/module.php';

    // POST, url, async
    xhr.open( 'POST',url,true );
    xhr.setRequestHeader( 'Content-Type','application/x-www-form-urlencoded' );

    // Handling the response
    xhr.onreadystatechange = () => {
                                        if ( xhr.readyState === 4 && xhr.status === 200 )
                                        {
                                            //console.log('Réponse:',xhr.responseText );
                                            let oJSON = JSON.parse( xhr.responseText );

                                            const handlerName = this.getAttribute('data-handler');
                                            if ( handlerName )
                                            {
                                                if ( typeof window[handlerName] === 'function' )
                                                    window[handlerName]( oJSON );
                                                else
                                                    throw new Error( `${handlerName} does not exist.` );
                                            }
                                            else
                                            {
                                                console.log( 'NO HANDLER',oJSON );
                                            }
                                        }
                                  };

    // Send the request with all parameters
    xhr.send( params.join( '&' ) );
}        

From then on, it becomes easy to isolate the response handling logic for each module (see how the handler's name is extracted from the attributes and how it is triggered if the underlying function exists: window[handlerName]( oJSON );

At this stage, I will refactor the source code to establish a stable foundation.

Test Code (https://quitus.trql.io/test-modules/)

<?php
use \trql\vaesoli\Vaesoli       as v;

{   /* Load classes */
    if ( ! defined( 'VAESOLI_CLASS_VERSION' ) )
        require_once( "{$_SERVER['snippet-center']}/trql.vaesoli.class.php" );
}   /* Load classes */
?>

<script>
    function myHandler1( oJSON )
    {
        console.log( 'WITH HANDLER 1',oJSON );
    }

    function myHandler2( oJSON )
    {
        console.log( 'WITH HANDLER 2',oJSON );
    }


    class QuitusModule extends HTMLElement
    {
        constructor()
        /*---------*/
        {
            super();
        }

        connectedCallback()
        /*---------------*/
        {
            // Get all attributes
            const attributes = this.attributes;
            const params = [];

            // Add each attribute and its value to aan array of parameters
            for ( let i = 0; i < attributes.length; i++ )
            {
                const attr = attributes[i];
                params.push(`${encodeURIComponent(attr.name)}=${encodeURIComponent(attr.value)}`);
            }

            // Create the XMLHttpRequest
            const xhr = new XMLHttpRequest();
            // Endpoint of my service
            const url = '/services/module.php';

            // POST, url, async
            xhr.open( 'POST',url,true );
            xhr.setRequestHeader( 'Content-Type','application/x-www-form-urlencoded' );

            // Handling the response
            xhr.onreadystatechange = () => {
                                                if ( xhr.readyState === 4 && xhr.status === 200 )
                                                {
                                                    //console.log('Réponse:',xhr.responseText );
                                                    let oJSON = JSON.parse( xhr.responseText );

                                                    const handlerName = this.getAttribute('data-handler');
                                                    if ( handlerName )
                                                    {
                                                        if ( typeof window[handlerName] === 'function' )
                                                            window[handlerName]( oJSON );
                                                        else
                                                            throw new Error( `${handlerName} does not exist.` );
                                                    }
                                                    else
                                                    {
                                                        console.log( 'NO HANDLER',oJSON );
                                                    }
                                                }
                                          };

            // Send the request with all parameters
            xhr.send( params.join( '&' ) );
        }
    }

    // Define the custom element
    customElements.define( 'quitus-module',QuitusModule );
</script>

<style>
    table { width: 80%;
        margin: 2em auto;
        background-color: #fff;
        border: 1px solid silver;
    }
       table th,
       table td { border: 1px solid silver;
       }
</style>


<section>
   <quitus-module id="QM_ac0dd673-82ba-4e61-b021-c5b0443b0f75" data-module="clifou" data-function="browse" data-start-recno="1" data-handler="myHandler1">blablabla</quitus-module>

    <hr />

   <quitus-module id="QM_95d40c32-c2e7-4ed2-b21e-b815b521f9c0" data-module="clifou" data-function="form" data-start-recno="88" data-handler="myHandler2">blablabla</quitus-module>

</section>        

Server-Side Code:

<?php
use \trql\vaesoli\Vaesoli               as v;
use \trql\db\IllicoDB3\IllicoDB3        as IllicoDB3;

if ( ! defined( 'VAESOLI_CLASS_VERSION' ) )
    require_once( '/home/vaesoli/snippet-center/trql.vaesoli.class.php' );

if ( ! defined( 'ILLICODB3_CLASS_VERSION' ) )
    require_once( '/home/vaesoli/snippet-center/trql.illicodb3.class.php' );

if ( ! defined( 'HTTP_STATUS_CODES' ) )
    require_once( '/home/vaesoli/snippet-center/trql.http-error-codes.h.php' );

$errorCode  = HTTP_STATUS_CODE_NOT_IMPLEMENTED;
$fields     = null;
$records    = null;
$messages   = null;

$DBName     = 'Quitus';
$folder     = '/home/vaesoli/domains/trql.io/quitus/databases/';

$t1 = microtime( true );
$oDB = new IllicoDB3();

if ( $success = $oDB->open( $DBName,$folder ) )
{
    $messages[] = 'DB open';
    if ( $_POST['data-module'] === 'clifou' )
    {
        $messages[] = 'CliFou module';

        if ( $table = $oDB->contacts ?? null )
        {
            $messages[]     = 'Contacts found';
            $fields         = $table->fields;
            $table->recno   = (int) $_POST['data-start-recno'] ?? 1;

            if ( ( $operation = $_POST['data-function'] ) === 'browse' )
            {
                $messages[] = 'BROWSE requested';

                while ( ! $table->eof() )
                {
                    $records[] = $table->record();
                    $table->skip();
                }   /* while ( ! $table->eof() )*/

                $errorCode = HTTP_STATUS_CODE_OK;
            }   /* if ( ( $operation = $_POST['data-function'] ) === 'browse' ) */
            elseif ( ( $operation = $_POST['data-function'] ) === 'form' )
            {
                $messages[] = 'FORM requested';
                $records[]  = $table->record();
                $errorCode = HTTP_STATUS_CODE_OK;
            }
        }   /* if ( $table = $oDB->contacts ?? null ) */
    }   /* if ( $_POST['data-module'] === 'clifou' ) */
}   /* if ( $success = $oDB->open( $DBName,$folder ) ) */

$t2 = microtime( true );

$response = [ 'prolog'  => [ 'status'   => $errorCode   ,
                             'params'   => $_GET        ,
                             'data'     => $_POST       ,
                             'perf'     => $t2 - $t1    ,
                             'debug'    => $messages    ,
                           ],
              'payload' => [ 'table'    => 'contact'    ,
                             'fields'   => $fields      ,
                             'records'  => $records     ,
                           ]
            ];
echo json_encode( $response );
?>        

The server-side code is poorly written, but it is simple to understand. It only handles requests related to the 'CliFou' module (if ($_POST['data-module'] === 'clifou')) and within this module, it only processes the browse and form requests (if (($operation = $_POST['data-function']) === 'browse') and (($operation = $_POST['data-function']) === 'form')).

This code is perfect (but poorly written, I repeat) for handling the two quitus modules that are listed in the test code.

Form Handling

"First, we will focus on the handling of the response for module2 because it is the simplest

<quitus-module id="QM_95d40c32-c2e7-4ed2-b21e-b815b521f9c0" data-module="clifou" data-function="form" data-start-recno="88" data-handler="myHandler2">blablabla</quitus-module>        

We are indeed calling the 'form' functionality (data-function='form') and we want to edit record 88 (data-start-recno='88'). As we can see in the module, it is the handler 'myHandler2' that will receive control for the processing of the service response (data-handler='myHandler2'). How is this function 'myHandler2()' defined for now:

function myHandler2( oJSON )
{
    console.log( 'WITH HANDLER 2',oJSON );
}        

I will slightly modify this definition to ensure that this is indeed where changes need to be made.

function myHandler2( oJSON )
{
    console.log( 'THIS IS WHERE I NEED TO MAKE SOME CHANGES',oJSON );
}        

Here's the result:

So this is indeed where I need to build my form. I will indeed create one, but I will greatly simplify and shorten it because I am only interested in the principle.

Let's take a look at a small modification to the callback function myHandler2!

function myHandler2( oJSON )
{
    console.log( 'THIS IS WHERE I NEED TO MAKE SOME CHANGES',oJSON );

    // The ID is returned by the service to easily identify the origin of the request.
    const id = oJSON?.prolog?.data?.id ?? null;

    if ( id )
    {
        const module = document.getElementById( id );

        if ( module )
        {
            module.innerHTML = "THIS IS WHERE A FORM MUST APPEAR";
        }
    }
}        

To ensure that the display is somewhat successful, I added CSS classes and styles. The test code has then become:

<style>
    section.modules { width: 100%;
        display: block;
        box-sizing: border-box;
    }
    quitus-module { margin: 2em;
        width: calc( 100% - 4em );
        padding:4em;
        background-color: lightyellow;
        color: black;
        height: 10em;
        display: block;
        box-sizing: border-box;
    }
    table { width: 80%;
        margin: 2em auto;
        background-color: #fff;
        border: 1px solid silver;
    }
       table th,
       table td { border: 1px solid silver;
       }
</style>

<section class="modules">
   <quitus-module id="QM_ac0dd673-82ba-4e61-b021-c5b0443b0f75" class="quitus-module" data-module="clifou" data-function="browse" data-start-recno="1" data-handler="myHandler1">blablabla</quitus-module>

    <hr />

   <quitus-module id="QM_95d40c32-c2e7-4ed2-b21e-b815b521f9c0" class="quitus-module" data-module="clifou" data-function="form" data-start-recno="88" data-handler="myHandler2">blablabla</quitus-module>
</section>        

Now let's see what our modification of myHandler2 yields:

We indeed have our two modules displayed. Let's take it a step further with the form, shortened as I mentioned.

Let's advance further and create a simplistic form:

function myHandler2( oJSON )
{
    console.log( 'THIS IS WHERE I NEED TO MAKE SOME CHANGES',oJSON );

    // The ID is returned by the service to easily identify the 
    // origin of the request.
    const id = oJSON?.prolog?.data?.id ?? null

    if ( id )
    {
        const module = document.getElementById( id );
        let HTML = '';

        // If module found
        if ( module )
        {
            // Construct the HTML
            HTML += `<form method="POST">`;
                HTML += `<fieldset>`;
                    HTML += `<legend>Formulaire</legend>`;
                    HTML += `<li><label for="txtID">ID:              </label><input type="text" name="txtID"      id="txtID"      value="" /></li>`;
                    HTML += `<li><label for="txtf_fname">First name: </label><input type="text" name="txtf_fname" id="txtf_fname" value="" /></li>`;
                    HTML += `<li><label for="txtf_lname">Last name:  </label><input type="text" name="txtf_lname" id="txtf_lname" value="" /></li>`;
                HTML += `</fieldset>`;
            HTML += `</form>`;

            module.innerHTML = HTML;
        }   /* if ( module ) */
    }   /* if ( id ) */
}   /* End of function myHandler2( oJSON ) */        

And here is the form:

A simplistic form

This form corresponds to the HTML code that was generated, which was very straightforward. We’re going to enhance it a bit to capture the values from the fields we display.

In the prolog block, we have the return code (prolog.status). We will definitely put that to good use! In the payload block, we have the record associated with the form. Specifically, it’s an array containing only a single element. This is the data we need to extract.

By refining this form, we can ensure it not only displays information clearly but also effectively captures user input. The prolog block will help us manage the status of our operations, while the payload will provide us with the necessary data for further processing. This approach sets us up for a more dynamic and interactive experience, allowing us to build upon this foundation as we progress.

Let's start by the status and the ID of the Quitus Module:

    function myHandler2( oJSON )
    {
        console.log( 'THIS IS WHERE I NEED TO MAKE SOME CHANGES',oJSON );

        // The ID is returned by the service to easily identify the 
        // origin of the request.
        const id        = oJSON?.prolog?.data?.id ?? null
        const status    = oJSON?.prolog?.status ?? 403;
        
        console.log( "STATUS CODE:",status );

        if ( status === 200 )
        {
            console.log( "ID:",id );

            // If we have found the originating module
            if ( id )
            {
                const module = document.getElementById( id );
                let HTML = '';

                // If module found
                if ( module )
                {
                    // Construct the HTML
                    HTML += `<form method="POST">`;
                        HTML += `<fieldset>`;
                            HTML += `<legend>Formulaire</legend>`;
                            HTML += `<li><label for="txtID">ID:              </label><input type="text" name="txtID"      id="txtID"      value="" /></li>`;
                            HTML += `<li><label for="txtf_fname">First name: </label><input type="text" name="txtf_fname" id="txtf_fname" value="" /></li>`;
                            HTML += `<li><label for="txtf_lname">Last name:  </label><input type="text" name="txtf_lname" id="txtf_lname" value="" /></li>`;
                        HTML += `</fieldset>`;
                    HTML += `</form>`;

                    module.innerHTML = HTML;
                }   /* if ( module ) */
            }   /* if ( id ) */
        }
    }   /* End of function myHandler2( oJSON ) */        

It keeps working ... the status code is displayed in the console and the ID of the quitus-module is also shown in the console.

It's now time to retrieve the record and fill the input zones with their values. The only thing that matters is how I have added more fields and how I have prefilled the values:

function myHandler2( oJSON )
{
  console.log( 'THIS IS WHERE I NEED TO MAKE SOME CHANGES',oJSON );

  // The ID is returned by the service to easily identify the
  // origin of the request.
  const id        = oJSON?.prolog?.data?.id ?? null
  const status    = oJSON?.prolog?.status ?? 403;

  console.log( "STATUS CODE:",status );

  if ( status === 200 )
  {
    console.log( "ID:",id );

    // If we have found the originating module
    if ( id )
    {
      const module = document.getElementById( id );
      const record = oJSON?.payload?.records[0];
      const table  = oJSON?.payload?.table;

      console.log ( record );

      let HTML = '';


      // If module found
      if ( module )
      {
        // Construct the HTML
        HTML += `<form method="POST">`;
          HTML += `<fieldset>`;
            HTML += `<legend>Formulaire</legend>`;
            HTML += `<li><label for="txtID">ID:                 </label><input type="text"     class="${record['id']         .field.type}" name="txtID"             id="txtID"          value="${record['id'].value.trim()}" /></li>`;
            HTML += `<li><label for="txtf_fname">First name:    </label><input type="text"     class="${record['f_fname']    .field.type}" name="txtf_fname"        id="txtf_fname"     value="${record['f_fname'].value.trim()}" /></li>`;
            HTML += `<li><label for="txtf_lname">Last name:     </label><input type="text"     class="${record['f_lname']    .field.type}" name="txtf_lname"        id="txtf_lname"     value="${record['f_lname'].value.trim()}" /></li>`;
            HTML += `<li><label for="txtf_birthdate">Birthdate: </label><input type="date"     class="${record['f_birthdate'].field.type}" name="txtf_birthdate"    id="txtf_birthdate" value="${str2date(record['f_birthdate'].value.trim())}" /></li>`;
            HTML += `<li><label for="txtf_rating">Rating:       </label><input type="number"   class="${record['f_rating']   .field.type}" name="txtf_rating"       id="txtf_rating"    value="${record['f_rating'].value}" /></li>`;
            HTML += `<li><label for="txtf_rewards">Rewards:     </label><input type="number"   class="${record['f_rewards']  .field.type}" name="txtf_rewards"      id="txtf_rewards"   value="${record['f_rewards'].value}" /></li>`;

            HTML += `<input type="hidden" name="illicoDB3-table-name"  id="illicoDB3-table-name"  value="${table}" />`;
            HTML += `<input type="hidden" name="illicoDB3-table-recno" id="illicoDB3-table-recno" value="${record['recno'].value}" />`;
          HTML += `</fieldset>`;

          HTML += '<button type="submit" class="btn btn-primary">Submit</button>';

        HTML += `</form>`;

        module.innerHTML = HTML;
      }   /* if ( module ) */
    }   /* if ( id ) */
  }
}   /* End of function myHandler2( oJSON ) */

function str2date( value )
{
  return ( `${value.slice(0, 4)}-${value.slice(4, 6)}-${value.slice(6)}` );
}        

Here's what it gives ...

A first "Not-Too-Bad" form (saving the data isn't possible at the moment)

For the presentation I have added a few styles:

<style>
    section.modules { width: 100%;
        display: block;
        box-sizing: border-box;
    }
    quitus-module { margin: 2em;
        width: calc( 100% - 4em );
        padding:4em;
        background-color: lightyellow;
        color: black;
        height: auto;
        display: block;
        box-sizing: border-box;
    }
        quitus-module form { color: black;
        }
            quitus-module form li { list-style-type: none;
            }
                quitus-module form li label { display: inline-block;
                    width: 8em;
                }
                quitus-module form li input.int,
                quitus-module form li input.float { text-align: right;
                }

            quitus-module form fieldset { border: 1px solid red;
                 background-color: #fff;
            }


        quitus-module table { width: 80%;
            margin: 2em auto;
            background-color: #fff;
            border: 1px solid silver;
        }
           quitus-module table th,
           quitus-module table td { border: 1px solid silver;
           }
</style>        

We're going to focus on the browse functionality now, and here too, we will simplify things to highlight the principles rather than the details. So, it's 'myHandler1' that we will need to modify! Are you ready? Brace yourself now!

function myHandler1( oJSON )
{
  console.log( 'WITH HANDLER 1',oJSON );

  // The ID is returned by the service to easily identify the
  // origin of the request.
  // The ID is returned by the service to easily identify the
  // origin of the request.
  const id        = oJSON?.prolog?.data?.id ?? null
  const status    = oJSON?.prolog?.status ?? 403;

  console.log( "STATUS CODE:",status );

  if ( status === 200 )
  {
    console.log( "ID:",id );

    // If we have found the originating module
    if ( id )
    {
      const module  = document.getElementById( id );
      const records = oJSON?.payload?.records ?? null;
      const table   = oJSON?.payload?.table ?? null;
      let HTML      = '';

      // If module found
      if ( module )
      {
        // If we have records to show
        if ( records )
        {
          // Build the HTML table with all the records
          HTML += `<table class="${table}">`;
            HTML += `<caption>${table}<caption>`;
            HTML += `<thead>`;
              HTML += `<tr>`;
                HTML += `<th class="recno"><em>RECNO</em></th>`;
                HTML += `<th class="id">ID</th>`;
                HTML += `<th class="fname">First name</th>`;
                HTML += `<th class="lname">Last name</th>`;
                HTML += `<th class="birthdate">Birthdate</th>`;
                HTML += `<th class="rating">Rating</th>`;
                HTML += `<th class="rewards">Rewards</th>`;
              HTML += `</tr>`;
            HTML += `</thead>`;

            HTML += `<tbody>`;
              for ( let record of records )
              {
                //console.log( record )
                HTML += `<tr onclick="document.getElementById('${id}').setAttribute('data-recno',this.getAttribute('data-recno'))" data-recno="${record.recno.value}">`;
                  HTML += `<td class="recno">${record.recno.value}</td>`;
                  HTML += `<td class="id">${record.id.value.trim()}</td>`;
                  HTML += `<td class="fname">${record.f_fname.value.trim()}</td>`;
                  HTML += `<td class="lname">${record.f_lname.value.trim()}</td>`;
                  HTML += `<td class="birthdate">${str2date(record.f_birthdate.value)}</td>`;
                  HTML += `<td class="rating">${record.f_rating.value}</td>`;
                  HTML += `<td class="rewards">${record.f_rewards.value}</td>`;
                HTML += `</tr>`;
              } /* For each record */
            HTML += `</tbody>`;
          HTML += `</table>`;
        }
        module.innerHTML = HTML;
      }   /* if ( module ) */
    }   /* if ( id ) */
  }   /* if ( status === 200 ) */
}   /* End of function myHandler1( oJSON ) */        

The code isn’t difficult: we simply create a table with the records (a subset of fields) that we insert into the innerHTML of the module, and that’s it!

Here's what it leads to...

Our first browse built in the front-end.

It’s starting to take shape. Now, what we need to do is implement a navigation mechanism. Essentially, when I move from one record to another, I want to notify the form of the record change so that it can refresh accordingly.For now, let’s establish a straightforward mechanism that everyone can easily understand. We can always refine it later with something more comprehensive and complex. Let’s start with something simple.

Additional Thoughts

This approach not only keeps things manageable but also lays a solid foundation for future enhancements. By focusing on clarity and simplicity at this stage, we ensure that everyone involved can follow along without feeling overwhelmed. Once we’ve got the basics in place, we can explore more sophisticated solutions that will enhance functionality and user experience. Let’s dive in and get started!

Click on the RECNO Column

The objective here is to intercept the click event on a row of the table, allowing us to inform the form about the change in record. We will tackle half of this process now, while the remaining part will be addressed in the upcoming Article 7d.

A Simple Approach

This task is quite straightforward. We will simply set up a onclick event during the table creation process. This onclick event will trigger a console.log() statement, which will serve as our proof that we can successfully intercept the change in record.

Future Enhancements

In Article 7d, we will go beyond just logging to the console. Instead, we will publish an event that the "Form" module will subscribe to. This way, it will be notified of any changes in records and can respond accordingly based on its own logic.

The construction of the body of the table becomes:

HTML += `<tbody>`;
  for ( let record of records )
  {
    HTML += `<tr onclick="console.log( 'recno is ${record.recno.value}' )">`;
      HTML += `<td class="recno">${record.recno.value}</td>`;
      HTML += `<td class="id">${record.id.value.trim()}</td>`;
      HTML += `<td class="fname">${record.f_fname.value.trim()}</td>`;
      HTML += `<td class="lname">${record.f_lname.value.trim()}</td>`;
      HTML += `<td class="birthdate">${str2date(record.f_birthdate.value)}</td>`;
      HTML += `<td class="rating">${record.f_rating.value}</td>`;
      HTML += `<td class="rewards">${record.f_rewards.value}</td>`;
    HTML += `</tr>`;
  }   /* For each record */
HTML += `</tbody>`;        

Please take note of the onclick event on the table row, which triggers a log to the console. This is a crucial element that we will need to modify—along with a few other components—to enable the publication of an event that the form can capture. By doing so, we ensure that the form remains updated and informed about any changes to the RECNO. This enhancement will facilitate better communication between the table and the form, ultimately improving user experience and functionality.

Conclusion

Phew! What a significant advancement! We have nearly resolved all outstanding issues and established a solid foundation for linking to an event publication system that other modules can subscribe to. Each of the two modules on our page has its own service handler, and we have successfully created the form and the browsing functionality. We are now capturing changes in the table position, and it seems we have a mechanism in place that will allow us to connect our event publication seamlessly.

I believe we will have everything ready to finalize in Article 7d, as anticipated. Once we have everything set up for the four core modules of our Small Business Suite, it will be time to consider adding additional modules. I already have hundreds of ideas in mind!

Oh, and just a quick note: I will be publishing the complete code in Article 7d.

See you soon, and let’s keep things uncomplicated!


Previous article - Next article





要查看或添加评论,请登录

Patrick Boens的更多文章

  • Forging a ChatBot in the Digital Wilderness

    Forging a ChatBot in the Digital Wilderness

    In the relentless landscape of technological evolution, silence is not the absence of action—it is the crucible of…

  • AI Scanning an Invoice

    AI Scanning an Invoice

    This new issue, dedicated to ChatGPT and Sermo (my programming gateway to ChatGPT, Perplexity, and Claude 3.5 Sonnet)…

  • Software Engineers and AI

    Software Engineers and AI

    Through numerous articles written on the subject of artificial intelligence in the context of digital transformations…

  • Using templates to mimic sophisticated object

    Using templates to mimic sophisticated object

    The Power of Templates in IllicoDB3: Revolutionizing Database Structure In the realm of traditional databases, the…

  • More, Faster, Easier...

    More, Faster, Easier...

    In my previous article, I showed you how to create a small todo management app in record time. Now, based on this first…

  • AI at the Developers' Bedside

    AI at the Developers' Bedside

    Let's dive into the world of AI-powered app creation, showcasing just how effortless it can be to bring your ideas to…

    1 条评论
  • AI and IT

    AI and IT

    Here's the question I asked to "Sonar Huge", the AI model of Perplexity.ai: With the advent of AI taking by storm the…

  • The Imperative of AI in Digital Transformation Projects: A Wake-Up Call for Businesses

    The Imperative of AI in Digital Transformation Projects: A Wake-Up Call for Businesses

    In today's rapidly evolving digital landscape, companies that continue to approach their digital transformation and…

  • Data Migration Projects

    Data Migration Projects

    "Mise en bouche" My first interesting encounter with a data migration project dates back to 1999. The tech world was…

  • IllicoDB3 and AI

    IllicoDB3 and AI

    I have mentioned in the past that IllicoDB3 allows the use of artificial intelligence to generate code related to…