AnsweredAssumed Answered

[UTIL] Forms AJAX rendering component

Question asked by alejandrogarciaseco on Feb 11, 2013
Latest reply on Jun 19, 2013 by paiyyavj13
Hi all,

This is something I needed for some customization I'm performing in Share.It is in a very premature state, but perhaps is useful for others. It is a client-side utility component for dynamically render forms retrieved to the forms component (/share/service/components/form) via AJAX requests. I'm not a JavaScrip guru so I'm open to any possible improvement/suggestion/bug fix. There you go:


/**
* Client-side JavaScript library.
*/

// Defines root namespace
if (typeof MyCustom == undefined || !MyCustom) {
   var MyCustom = {};
}

// Defines top-level "custom" namespace, which will contain customization or extensions of existing components or objects in Alfresco
MyCustom.custom = MyCustom.custom || {};

// Defines top-level "util" namespace
MyCustom.util = MyCustom.util || {};

/**
* Renderization and submission of forms generated by Forms Engine via Ajax requests.
*
* To know more about forms engine, invocation parameters and behavior: http://wiki.alfresco.com/wiki/Forms_Developer_Guide
*
* @class MyCustom.util.AjaxFormUI
*/
(function()
{
   var Dom = YAHOO.util.Dom,
      Event = YAHOO.util.Event;
  
   MyCustom.util.AjaxFormUI = function(htmlId, components)
   {
      components = YAHOO.lang.isArray(components) ? components : [];
     
      return MyCustom.util.AjaxFormUI.superclass.constructor.call(
         this,
         "MyCustom.util.AjaxFormUI",
         htmlId,
         components);
   };

   YAHOO.extend(MyCustom.util.AjaxFormUI, Alfresco.component.Base,
   {
      /**
       * The default render config used by method render()
       *
       * @property options
       * @type object
       */
      options:
      {
         itemId : null,
         mode : null,
         htmlid : null,
         container : null,
         successCallback : null,
         successMessage : null,
         failureMessage : null,
         cancelCallback : null
      },
     
      /**
       * Reference to the DOM element which wraps up the form
       *
       * @property formWrapper
       * @type HTMLElement
       */
      formWrapper: null,
     
      /**
       * Retrieves and renders the form by performing a request to the forms engine according
       * to the configuration object provided.
       *
       * @method renderForm
       * @param config {object} Description of the form to be generated
       * The config object has the following form:
       * {
       *    itemId : {string},              // The identifier of the item the form is for, this will be different for each "kind" of item, for "node" it will be a NodeRef.
       *    mode : {string},                // The mode the form will be rendered in, valid values are "view", "edit" and "create".
       *    htmlid : {string},              // The htmlid of the current Surf component
       *    container : {HTMLElement|string},  // Where the form will be allocated
       *    successCallback : {Object}      // A callback object literal used on form submission success
       *    successMessage : {String}       // A submit success message
       *    failureMessage : {String}       // A submit failure message
       *    cancelCallback : {String}       // A callback object literal used when form's cancel button is pressed
       * }
       */
      render: function() {
         // TODO: to check mandatory options/parameters
        
         // Perform AJAX request to get form content from Forms Engine
         Alfresco.util.Ajax.request({
            url: Alfresco.constants.URL_SERVICECONTEXT + "components/form",
            dataObj:
            {
               htmlid: this.options.htmlid, // Ensure unique IDs
               itemKind : "node", // It is fixed at the moment but could be dynamic in the future
               itemId : this.options.itemId,
               mode: this.options.mode,
               submitType: "json",
               formUI: true,
               showCancelButton: true
            },
            successCallback : {
               fn : function(response)
               {
                  // Create form wrapper where the form content is going to be inserted
                  this.formWrapper = document.createElement("div");
                  this.formWrapper.setAttribute("id", this.options.htmlid + "-form-wrapper"); // Set appropriate id attribute
                  this.formWrapper.setAttribute("class", "share-form"); // Set appropriate class
                 
                  // Fill the wrapper with the form component returned by the XHR request into
                  this.formWrapper.innerHTML = response.serverResponse.responseText;
                 
                  // Append form wrapper to container element
                  Dom.get(this.options.container).appendChild(this.formWrapper);
               },
               scope : this
            },
            failureMessage : Alfresco.util.message("message.failure"), // Generic failure message
            scope: this,
            execScripts: true // Automatically executes script tags (<script>) returned in the forms engine's response
         });
        
         // Adjust form to work in dialog
         YAHOO.Bubbling.on("formContentReady", this._onFormContentReady, this);
        
         // When form is submitted make sure we hide the dialog after a successful submit and display a message when it fails.
         YAHOO.Bubbling.on("beforeFormRuntimeInit", this._onBeforeFormRunTimeInit, this);
      },
     
      /**
       *
       *
       * @method _onFormContentReady
       * @param layer
       * @param args
       * @private
       */
      _onFormContentReady: function(layer, args)
      {
         if (Alfresco.util.hasEventInterest(this.options.htmlid + "-form", args))
         {
            // Close dialog when cancel button is clicked
            var cancelButton = args[1].buttons.cancel;
           
            // Destroy the form when cancel button is clicked, by default
            cancelButton.addListener("click", this._destroy, this, true);
           
            // Execute custom function on button click if the object that describes it exists
            if (this.options.cancelCallback && YAHOO.lang.isFunction(this.options.cancelCallback.fn))
            {
               cancelButton.addListener(
                  "click", // Event triggered
                  this.options.cancelCallback.fn, // Function executed
                  this.options.cancelCallback.scope || {}, // Scope
                  true); // The custom object that is passed is used for the execution scope (so it becomes "this" in the callback)
            }
         }
      },
     
      /**
       *
       *
       * @method _onBeforeFormRunTimeInit
       * @param layer
       * @param args
       * @private
       */
      _onBeforeFormRunTimeInit: function(layer, args)
      {
         if (Alfresco.util.hasEventInterest(this.options.htmlid + "-form", args))
         {
            args[1].runtime.setAJAXSubmit(true,
            {
               successCallback :
               {
                  fn : function PopupMananger_displayForm_formSuccess(response)
                  {
                     // Destroy the form wrapper and its content
                     this.options.container.removeChild(this.formWrapper);
                    
                     // Invoke success
                     if (this.options.successCallback && YAHOO.lang.isFunction(this.options.successCallback.fn))
                     {
                        // TODO: does the callback function really needs to receive arguments??
                        this.options.successCallback.fn.call(this.options.successCallback.scope || {}, response, this.options.successCallback.obj)
                     }
                  },
                  scope : this
               },
               successMessage : this.options.successMessage,
               failureMessage : this.options.failureMessage
            });
         }
      },
     
      /**
       * Implements self-destruction of the component
       *
       * @method _destroy
       * @param event
       * @param obj
       * @private
       */
      _destroy: function(event, obj)
      {
         // Remove the form wrapper from the DOM
         obj.options.container.removeChild(Dom.get(obj.formWrapper));
        
         // Form destruction signal
         YAHOO.Bubbling.fire("formContainerDestroyed");
        
         // Unsubscribe events
         YAHOO.Bubbling.unsubscribe("beforeFormRuntimeInit", this._onBeforeFormRunTimeInit, obj);
         YAHOO.Bubbling.unsubscribe("formContentReady", this._onFormContentReady, obj);
        
         // Clean instance attributes
         delete this.formWrapper;
        
         // Invoke super (Alfresco.component.Base) destroy method
         this.destroy();
      },
   });
})();


A form can be easily initialized as follows:


                        var form = new MyCustom.util.AjaxFormUI();
                        form.setOptions(
                        {
                           itemId : "workspace://SpacesStore/73ddea6e-c937-4db3-af65-44c82150a72f",
                           mode : "edit",
                           htmlid : parent.id,
                           container : Dom.get(parent.id + "-container"),
                           successCallback:
                           {
                              fn: parent.onCreateUserFormCancelClick,
                              scope: parent
                           },
                           successMessage : parent._msg("message.update-success"),
                           cancelCallback:
                           {
                              fn: parent.onCreateUserFormCancelClick,
                              scope: parent
                           }
                        });
                        form.render();


Hope it helps.

Regards.

Outcomes