Skip to content

Utilizing External Libraries

You are able to make use of External libraries when building your own UI Components. This can be achieved by either specifying an external library on your Component using the Component External Library Documents field, or at a lower level using a Lazy Loading technique within your event functions (eg. a Component's Load Function). In either case, the external library needs to be installed on the Formbird platform before it can be accessed.

Installing Custom Component Modules

Please contact your Formbird administrator to request / perform this setup in your environment.

  1. Download the required module from your chosen code repository.
  2. Copy the module to a new folder under the ./server/public/vendor/custom-component-modules/ folder of the Formbird install.

For example, to enable the moment module:

  1. Download moment using npm or from it's website https://momentjs.com/.

  2. Copy the file moment.js to the following server location: ./server/public/vendor/custom-component-modules/moment/

The file should appear as follows: ./server/public/vendor/custom-component-modules/moment/moment.js

Tip: This process is not limited to modules alone. Other files including CSS and template files may be installed in the same manner.

Once the required modules are installed, use one of the following methods to access it from your Component.

Using Component External Library Documents

You can specify the external library on your UI Component using the Component External Library Documents field as discussed in section Components Structure - Component dependencies. This field provides a list of available libraries to choose from, and can be extended with any additional libraries you may require. This is the preferred approach of accessing External Libraries from a UI Component.

To extend the list with additional libraries, first ensure the library files are installed on the server, and then use the External Component Library Reference Template (eefe2d60-8e16-11e8-9fe7-4fe2d6e868a0) to create an entry for the library. An example entry for the external library proj4 follows:

Field Value
Name proj4
Description Projection library used by mapping components
Relative Library Path vendor/custom-component-modules/proj4/proj4.js

Note that the "Relative Library Path" value begins with "vendor/custom-component-modules/". Make sure this is included in your own "Relative Library Path" values.

Using Lazy Loading

Lazy loading is a technique for loading files at the point-in-time when they are needed rather than at the beginning of the process. This technique can be used to speed up the initial load time of a component by only loading what is needed to start with. Lazy loading of external libraries may be of some benefit to you if it is seldom used, for example it is an optional part of the UI Component that is rarely activated by a user, or if it is an interchangeable library/file based on configurable options in your component.

To lazy load an external library, first ensure the library files are installed on the server and then use the ocLazyLoad service to perform the task. For example:

var proj4 = $ocLazyLoad.load({name: 'proj4', files: ['vendor/custom-component-modules/proj4/proj4.js']}); 
proj4.then(
    function(){
      logger.info("proj4 loaded............");
    },function(err){
      logger.error("error lazy loading proj4: " + err); 
    }
);

The following example is sourced from the sc-note-box component's Load Function:

function(){
  if( typeof scope.tplItem.readOnly === 'undefined' 
    || scope.tplItem.readOnly === null ){
    scope.readOnly=false;
  }else{
    scope.readOnly = scope.tplItem.readOnly; 
  }
  if( !(typeof scope.tplItem.enabled === 'undefined' 
    || scope.tplItem.enabled === null) ){
    scope.readOnly = !scope.tplItem.enabled; 
  }
  if( typeof scope.tplItem.visible === 'undefined' 
    || scope.tplItem.visible === null ){
    scope.visible=true;
  }else{
    scope.visible = scope.tplItem.visible; 
  }
  if( typeof scope.tplItem.noteBoxRows === 'undefined' 
    || scope.tplItem.noteBoxRows === null ){
    scope.noteBoxRows=3;
  }else{
    scope.noteBoxRows = scope.tplItem.noteBoxRows; 
  }
  if( typeof scope.tplItem.disableSave === 'undefined' 
    || scope.tplItem.disableSave === null ){
    scope.disableSave=false;
  }else{
    scope.disableSave = scope.tplItem.disableSave; 
  }
  var ModifiedFieldService = $injector.get('ModifiedFieldService');
  var timeOutDelay=1000;
  var componentElement;
  var noteBoxDivResizable;
  var deviceDetect = $ocLazyLoad.load({name: 'deviceDetect', 
    files: ['vendor/custom-component-modules/device-detect/devicedetect.js']}); 
  deviceDetect.then(
    function(){
      logger.info("device detect loaded............");
      $timeout(function() {
        componentElement =element.find('textarea');
        logger.info("Browser name: "+detectBrowser().browser);  
        if (detectBrowser().browser === "Chrome" 
            || detectBrowser().browser === "Firefox" 
            || detectBrowser().browser === "Safari") {
          //continue for default textarea expandable1
        }else{
          //If textarea is not resizable lazy load jquery ui resizable
          var customLazyLoadA = $ocLazyLoad.load({name: 'customLazyLoadA',
            files: ['vendor/custom-component-modules/jquery-ui-resizable/jquery-ui.css'], serie: true});
          customLazyLoadA.then(function(){
            var customLazyLoad = $ocLazyLoad.load({name: 'customLazyLoad',
              files: ['vendor/custom-component-modules/jquery-ui-resizable/jquery-ui.js'], serie: true});  
            customLazyLoad.then(function(){
              $timeout(function(){  
                logger.info("jquery ui loaded............");
                if(scope.visible){
                  initializeExpandable();
                }
              });  
              scope.$watch('tplItem.visible', function(newValue, oldValue) {
                if(newValue){
                setTimeout( function() { 
                  initializeExpandable();
                  $(element).find('.ui-wrapper').css('width',
                    $(element.parent()).width()-2);
                  $(element).find('textarea').css('width',
                    $(element.parent()).width()-8);
                  }, 200);
                }
              }, true);
              $('#left_close').click(function() {
              setTimeout( function() { 
                if(!scope.tplItem.visible){
                  return;
                }
                initializeExpandable();
                $(element).find('.ui-wrapper').css('width',
                  $(element.parent()).width()-2);
                $(element).find('textarea').css('width',
                  $(element.parent()).width()-8);
              }, 500);
            });
            function initializeExpandable(){
              $(componentElement).resizable({
                //handles: 'n,s,e,w',
                maxWidth: $(element.parent()).width(),
                minWidth: $(element.parent()).width(),
                create: function( event, ui ) {
                  var textElement=$(event.target).find('textarea');
                  $(textElement).css({"width":($(event.target).width())+"px",
                    "height":($(event.target).height())+"px"});
                  $(textElement).css("border","none");
                  noteBoxDivResizable=event.target;
                  if(scope.readOnly) {
                    $(noteBoxDivResizable).css({'background-color':'#f1f1f1',
                      'cursor':'not-allowed'});
                  } else {
                    $(noteBoxDivResizable).css({'background-color':'white',
                      'cursor':''});
                  }
                  $('div[class*="ui-icon-gripsmall-diagonal-se"]').css( {
                    'background-position':'-80px -228px',//-80px -228px;
                    'width':'10px',
                    'height':'9.5px',
                    'opacity':'0.6'
                  });
                },
                stop: function( event, ui ) {
                  $(ui.element.context).css({"width":($(ui.element[0]).width())+"px",
                    "height":($(ui.element[0]).height())+"px"});
                }
              });
            }
          },function(err){
            logger.info("error on lazy load jquery ui js"); 
            logger.info(err);
          }); 
        },function(err){
          logger.info("error on lazy load jquery uiA CSS"); 
          logger.info(err);
        });
      }
    });
  },function(err){
    logger.info("error on lazy load device detect"); 
    logger.info(err);
  });

  //This is watched function for readOnly field
  scope.$watch("readOnly", function(value) {
    $timeout(function() {
      if(value){
        $(element).addClass('disabled').addClass('readonly');
        $(element.parent()).addClass('disabled').addClass('readonly');
        $(noteBoxDivResizable).css({'background-color':'#f1f1f1',
          'cursor':'not-allowed'});
      }else{
        $(element).removeClass('disabled').removeClass('readonly');
        $(element.parent()).removeClass('disabled').removeClass('readonly');
        $(noteBoxDivResizable).css({'background-color':'white','cursor':''});
      }
      timeOutDelay=300;
    },timeOutDelay);
  }, true);
}

In the above example, external libraries devicedetect and jquery-ui are lazy loaded to assist with the display of the sc-note-box component.

Refer to ocLazyLoad's documentation (at https://oclazyload.readme.io/docs/oclazyload-service) for further details on its usage.