PHP JavaScript deferred Loading

From HaFrWiki42
Jump to navigation Jump to search

Deferred loading is a programming technique to improve the performance of Websites by loading code only when needed. The purpose of this article is to show how to use deferred loading of Webpage parts using PHP and JavaScript in combination with AJAX and jQuery.

Deferred loading can also be used on CSS, but that is not the scope of this article.

Introduction

When a website loads, not all content is always necessary. So why should you load such content if you don't know the use is gonna use it? In this article is assumed that the website consist on (Bootstrap) navigation tabs. The user can have several roles that gives or denies him access to certain parts of the website. If the user has the admin-role, he may access everything including the admin tab. In that case you don't want to load the admin tab at all if the user hasn't the admin-role. But also if the user has the admin-role you do need the admin tab every time you access the website.

In that case you wanna use deferred loading.

Requirements

The framework we are going to make depends on PHP-server-coding and JavaScript-Client-coding. To clue the 2 parts we are using AJAX in combination with jQuery. The application loads a form with JavaScript validation and AJAX calls for checking and CRUD operations on the Database. The form has a Bootgrid part for showing the content of the database.

Used files

FileName Description
AdminHomeDb.php Front- and Backend for constants (variable-names), Form creation, Database CRUD methods and Database CRUD checks.
AppValidateJS.php Frontend, generic validation and patterns, Bootgrid variables, Event for validation (on-blur).
AdminHomeJS.php Frontend, form specific validation and patterns, validation objects, Events for specific validation (on-blur), AJAX getters for the form, AJAX CRUD, Timed Events for the form.
App.php Main application PHP page, which contains the JavaScript .ready method.
App-co.php Common PHP file which contains the link between the PHP-Frontend and the PHP-Backend, such as the Database connection and the common include files.

For this framework it must contain the AJAX actions and request definitions.

App-be.php Backend PHP file which contains the AJAX-Backend implementations.

Specific for the PHP deferred loading this file contains the Form, Form CRUD and Form CRUD Checks Backend implementations.

  • The App in the FileName is the MainApp, meaning the Main PHP Page. The App is split into 3 files App.php, App-co.php and App-be.php.
  • The AdminHome in the FileName is the WebPage Tab (deferred Form).

Form Validation

The Application validation is based on Regex with validation objects (validator).

Validation Object

A validator for a string-name has the following JS-object [1]. <syntaxhighlight lang="javascript"> var validHomeName = {

  environ  : "Home",
  name     : "<?php echo HS_HOME_NAME; ?>",
  qid      : sprintf('[name="%s"]'  , "<?php echo HS_HOME_NAME; ?>"),
  qcb      : sprintf('[name="cb%s"]', "<?php echo HS_HOME_NAME; ?>"),
  pattern  : "^[A-Za-z0-9À-ž&@#$\\*\\+\\'\\<\\>\\.\\,\\;\\:\\-\\_\\(\\)\\[\\]\\/ \\n]{3,20}",
  message  : "Length [3..20], alphanumeric",
  minlen   : 3,
  maxlen   : 20,
  flag     : "gi",
  value    : "",
  status   : jsoStatus

}; </syntaxhighlight>

Field element Field description
environ The environment for the form. In this case it is all about a house/home.
name The name (label of the html-element). The PHP-Label-Definition is made in the AdminHomeDb.php OUTSIDE the class definition.
qid The jQuery-Selector name. Enables the getting and settings of values in the form.
qcb The jQuery-Selector help/error field name. Enables the validation errors/warnings below the input-field.
pattern The RegEx pattern for the value of the input field. The actual validation of the input field. Please note the pattern has an embedded.
message The error message to be sent after an invalid input.
minlen The minimum input length, give zero (0) if the input is optional.
maxlen The maximum input length
flag The Regex flag attribute.
value The value of the input field, keep it in sync in the on blur events.
status The JavaScript jsoStatus object. This object keeps the last validation results. The jsoStatus object is part of the generic JS-Objects, see AppValidateJS.php.

AdminHomeDb.php

This PHP file is used in the Frontend and in the Backend.

  • [1] Constant declaration [2].
  • [2] Class AdminHomeDb extends the abstract class CRUD [3].
  • [3] Class AdminHomeDb has method createFormHouses which create the Client-Form [4].

<syntaxhighlight lang="php"> // [1] - The Constant definitions for the creation of the form (PHP) and the AJAX Client call (JavaScript) and the Mapping of the form Variables to the Backend (PHP). const HS_HOME_ID = "hsHomeId"; const HS_HOME_NAME = "hsHomeName";

// [2] - The class declaration. class AdminHomeDb extends CRUD {

  /**
   * [3] Creates the admin form for Home Maintenance.
   * @param  array $aReq Request parameters
   * @return void
   */
  public function createFormHouses( $aReq ) {
     $this->log->trace( sprintf( logFormatLBW, __method__, "aReq", print_r($aReq, true)));

$r = sprintf('

%s


', _h("admin-houses-header"));

     // Form Houses
     $r.= sprintf('<form id="adminhouses" class="form-horizontal" role="form" method="post" action="Energy.php" onsubmit="return validateEdit();">');
     // House / Home id
     $r.= sprintf('
           <label class="control-label col-sm-3" for="%s">%s:</label>
              <input class="form-control" id="%s" type="text" name="%s" placeholder="%s" disabled value="%s">

',

     HS_HOME_ID, _h('hs-home-id-label'),
     HS_HOME_ID, HS_HOME_ID, _h('hs-home-id-placeholder'), "Id");
     $r.= sprintf('
              <button type="button" class="btn btn-default btn-cons" name="%s" value="Update"   title="%s" %s>%s</button>
               
              <button type="button" class="btn btn-default btn-cons" name="%s" value="Clear"    title="%s" %s>%s</button>
               
              <button type="button" class="btn btn-default btn-cons" name="%s" value="Retrieve" title="%s" %s>%s</button>
               
              <button type="button" class="btn btn-default btn-cons" name="%s" value="Check"    title="%s" %s>%s</button>
               
              <button type="button" class="btn btn-default btn-cons" name="%s" value="Delete"   title="%s" %s>%s</button>

',

     HS_BUT_UPDATE  , _h('hs-but-update-title'  ), "disabled", _h('hs-but-update')   ,
     HS_BUT_CLEAR   , _h('hs-but-clear-title'   ), "disabled", _h('hs-but-clear')    ,
     HS_BUT_RETRIEVE, _h('hs-but-retrieve-title'), "disabled", _h('hs-but-retrieve') ,
     HS_BUT_CHECK   , _h('hs-but-check-title'   ), "disabled", _h('hs-but-check')    ,
     HS_BUT_DELETE  , _h('hs-but-delete-title'  ), "disabled", _h('hs-but-delete')
     );
     $r.= sprintf('</form>');
     return $r;
  }  // createFormHouses
  /**
   * [4] Update (and Inserts) the given admin-home.
   * @ajax       ajaxUpdateAdminHome
   * @javascript doAHUpdate
   * @param  array $aReq Request parameters
   * @return array $aRet Response parameters.
   */
  public function updateAdminHome($aReq) {
     $this->log->trace( sprintf( logFormatLBW, __method__, "aReq", print_r($aReq, true) ));
     if ( intval($aReq[HS_HOME_ID]) > 0 ) {
        $query = sprintf("

Update %s Set housename= '%s', .... Where id = %u; ",

        $this->popo->getTableName('houses'),
        $aReq[HS_HOME_NAME],
        ...

} // class </syntaxhighlight>

AppValidateJS.php

The PHP-file AppValidateJS.php contains the JavaScript generic validators. <syntaxhighlight lang="PHP"> <?php /** Javascript-PHP-File AppValidateJS.php implements Javascript methods with embedded PHP-blocks inside the code. The files is specially made for screen validations. ...

  • /

const EnergyValidateJSVersionNumber = "5.0.7.1"; const EnergyValidateJSVersionDate = "17 May 2018"; ?>

<script> /**

* Enumeration of validations.
* @type enum
*/

var enumValidation = {

  UNKOWN         :  0,
  OK             :  1,
  EMPTY          :  2,
  PENDING        :  4,
  ERROR          :  8,
  ERROR_LEN      : 16,
  ERROR_CHARS    : 32,
  ERROR_EXISTANCE: 64

};

/**

* JavaScript object instance to be used for the returning of the status, error and description.
* @type JavaScript Object.
* @since 5.0.6.1
*/

var jsoStatus = {

  enum         : enumValidation.UNKNOWN,
  statusstring : "0 - Unknown",
  error        : "",
  description  : ""

};

/**

* Converts an enumeration to a readable string format.
* @param  enumValue Enumerated integer value
* @return string
*/

function stringValidation(enumValue) {

  'use strict';
  var met = "stringValidation";
  switch(enumValue) {
     case enumValidation.UNKNOWN      : return " 0 - Unknown";
     case enumValidation.OK           : return " 1 - Ok";
     case enumValidation.EMPTY        : return " 2 - Ok Empty";
     case enumValidation.PENDING      : return " 4 - Pending";
     case enumValidation.ERROR        : return " 8 - Error";
     default                          : return ">8 - Error";
  }

} // stringValidation

/**

* Validates the current input of the Edit-Fields.
* @param object  validEdit JS-Object with validation data.
* @param boolean noDialog  [Optional] flag not to show the dialog. [true].
* @param boolean
* @return boolean true|false
*/

function validateEdit( validEdit, noDialog ) {

  'use strict';
  var met     = 'validateEdit';
  var nod     = typeof noDialog !== 'undefined' ? noDialog : true;
  var ret     = validateMatch(validEdit, nod);
  if (debug) {
     logts( sprintf( logFormatLBW, met, "Ret-EnumVal", ret + " = " + stringValidation(ret) ));
     logts( sprintf( logFormatLBW, met, "enum"       , prfStr(validEdit.status.enum) ));
  }
  if (ret <= enumValidation.EMPTY) {
     $(validEdit.qid).removeClass("error");
     $(validEdit.qid).attr("title", "");
     return true;
  } else {
     $(validEdit.qid).addClass("error");
     $(validEdit.qid).attr("title", validEdit.status.description);
  }
  return false;

} // validateEdit

/** Validates a text field using the regular expression match method. This is the default method for the getMatch PHP input field. Added the findMismatchChars @param validator Javascript object with

              - qid       jQuery selector
              - pattern   Regex pattern for validation.
              - minlen    Minimum length
              - maxlen    Maximum length
              - flag      Reqex flag
              - status    Object jsoStatus

@param noDialog Indication to not use directly the dialog and setFocus. [default: false] @global validationE Validation enumeration variable (UNKNOWN, ) @return enumValidation instance (PENDING, EMPTY, ERROR_LEN, ERROR_CHARS, OK)

  • /

function validateMatch(validator, noDialog) {

  'use strict';
  var met = "validateMatch";
  var nod = typeof noDialog !== 'undefined' ? noDialog : false;
  var ti  = (window.domLanguage === 31
            ? "Foute invoer voor '%s'."
            : "Invalid input for '%s'.");
  var me  = (window.domLanguage === 31
            ? "Leeg veld is niet toegestaan voor veld '%s'."
            : "Empty field not allowed for field '%s'.");
  var mi  = (window.domLanguage === 31
            ? "Ongeldige invoer voor veld '%s'.
%s."  : "Invalid input for field '%s'.
%s"); var ml = (window.domLanguage === 31)  ? "Ongeldige invoer voor veld '%s'.
Veld lengte tussen %u en %u."  : "Invalid input for field '%s'.
Field length between %u en %u." var rFlag = validator.flag; var idValue = $(validator.qid).val(); var r = new RegExp(validator.pattern, rFlag); var duration = 300; var modal = false; var result, aResults;
  var tmsg = sprintf(ti, validator.name);
  if (debug) {
     logts( sprintf( logFormatLBW, met, "Enum/qid/Name" , validationE + " for qid: " + validator.qid +", " + validator.name + ".") );
     logts( sprintf( logFormatLBW, met, "Validator minLen", validator.minlen) );
  }
  // Checks for pending validation to prevend circular loops.
  if (validationE === enumValidation.PENDING) {
     logtrace( sprintf( logFormatLBW, met, "Validation Enum", "PENDING") );
     return enumValidation.PENDING;
  }
  if (debug) {
     logts( sprintf( logFormatLBW, met, validator.qid  , idValue) );
     logts( sprintf( logFormatLBW, met, "Pattern", validator.pattern));
  }
  window.validationOk = true;
  validator.status    = { enum: enumValidation.UNKNOWN, statusstring: "0 - Unknown", error: "", description: ""};
  // Checks on minimum length, allowed.
  if (validator.minlen === 0 && idValue === "") {
     validator.status.enum        = enumValidation.EMPTY;
     validator.status.error       = "";
     validator.status.description = sprintf( window.domLanguage === 31
        ? "Invoer '%s', is leeg, hetgeen is toegestaan."
        : "Input '%s', is empty, which is allowed!",
        validator.name);
     logtrace( sprintf( logFormatLBW, met, "Validate-EMPTY", validator.status.description));
     return enumValidation.EMPTY;
  }
  // Checks on minimum length, not-allowed.
  if (validator.minlen > 0  && idValue === "") {
     validator.status.enum        = enumValidation.ERROR_LEN;
     validator.status.error       = '<?php echo _h("valmatch-empty-field-not-allowed"); ?>';
     validator.status.description = validator.status.error;
     logtrace( sprintf( logFormatLBW, met, "Invalid", "Empty string not-allowed."));
     if (! nod) {
        var bmsg = sprintf(me,  validator.name);
        openIconDialog( "notok", bmsg, tmsg, 450, modal);
        wait4Blur(validator.qid, duration);
     }
     window.validationOk = false;
     return enumValidation.ERROR_LEN;
  }
  if (validator.minlen > 0 && (validator.minlen > idValue.length || validator.maxlen < idValue.length) ) {
     validator.status.enum        = enumValidation.ERROR_LEN;
     validator.status.error       = sprintf('<?php echo _h("valmatch-invalid-length"); ?>',
                                             validator.minlen, validator.maxlen);
     validator.status.description = validator.status.error;
     if (! nod) {
        var bmsg = sprintf(ml,  validator.name, validator.minlen, validator.maxlen);
        openIconDialog( "notok", bmsg, tmsg, 450, modal);
        // wait4Blur(validator.qid, duration);
     }
     window.validationOk = false;
     return enumValidation.ERROR_LEN;
  }
  if (rFlag.indexOf("g") !== -1) {
     aResults = idValue.match(r);
     logtrace( sprintf( logFormatLBW, met, "aResults", r ));
     if (aResults !== null) {
        result = aResults[0];
     }
  } else {
     result = idValue.match(r);
  }
  // Undefined result, meaning the regex matched nothing!
  if (result === undefined) {
     if (debug) {
        logts(sprintf( logFormatLBW, met, "Regex Result"   , "undefined"));
        logts(sprintf( logFormatLBW, met, "Regex Undefined", validator.pattern));
        console.dir(aResults);
     }
     if (! nod) {
        var bmsg = sprintf(mi,  validator.name, "Regex Result undefined");
        openIconDialog( "notok", bmsg, tmsg, 450, modal);
        wait4Blur(validator.qid, duration);
     }
     validator.status.enum        = enumValidation.ERROR_CHARS;
     validator.status.error = '<?php echo _h("valmatch-invalid-input"); ?>';
     validator.status.description = validator.status.error;
     return enumValidation.ERROR_EXISTANCE;
  }
  // Defined result but not equal to idValue
  if (result !== idValue ) {
     var jsoFirstInvalidChar = findMismatchChars(idValue, r);
     validator.status.enum        = enumValidation.ERROR_CHARS;
     validator.status.description = sprintf("Input '%s' : %s", validator.name, jsoFirstInvalidChar.description);
     logtrace( sprintf( logFormatLBW, met, "Description", validator.status.description));
     if (! nod) {
        var bmsg = sprintf(mi,  validator.name, jsoFirstInvalidChar.description);
        openIconDialog( "notok", bmsg, tmsg, 450, modal);
        $(validator.qid).focus();
        // wait4Blur(validator.qid, duration);
     }
     window.validationOk = false;
     return enumValidation.ERROR_CHARS;
  }
  validator.status.enum = enumValidation.OK;
  validator.status.description = '<?php echo _h("valmatch-no-errors"); ?>';
  validationE = enumValidation.OK;
  return enumValidation.OK;

} // validateMatch

/**

* Finds the mismatched characters from a string given the pattern.
* The function is used after you have found errors.
* @param  String txt     The text string to be examined.
* @param  RegEx  regex   The regular expression.
* @return ret Object status {index, char, description}.
*/

function findMismatchChars(txt, regex) {

  'use strict';
  var met         = 'findMismatchChars';
  var domLanguage = window.domLanguage;
  var template    = '<?php echo _h("valmatch-mismatched-chars"); ?>';
  var ret = {index: 0, char: "", description: ""};
  regex.test( txt );
  if (regex.lastIndex <= txt.length) {
     ret.index       = 1 + regex.lastIndex;
     ret.char        = txt.substr( regex.lastIndex, 1 );
     ret.description = sprintf(template, 1 + regex.lastIndex, txt.substr( regex.lastIndex, 1 ));
  }
  return ret;

} // findMismatchChars


</syntaxhighlight>

See also

top

Reference

top

  1. JS = JavaScript
  2. AdminHomeDb.php - Constant declaration for the deferred Form.
  3. AdminHomeDb class extends CRUD
  4. AdminHomeDB class has method createFormHouses