Thursday, 24 July 2014

Open UI Customization - Part 4 - Applet PM and PR explained

Hello again!
Quick recap of PM from my previous blog Open UI Customization - Part 1 - Intro

Presentation Model:
A presentation model is a single or set of JavaScript files that work with runtime(data generated at client-side) and metadata (data from server) and allow you to control and customize the logic, content and client interaction.
It determines the logic to apply, captures client interactions, such as the user leaving a control, collects field values, and sets properties. A presentation model can get Properties and Methods from the proxy, and then expose them for external use. It doesn’t do any rendering of physical HTML ( you know who handles that – yes PR)

Physical Renderer:
A physical renderer is a single or set of JavaScript files that Siebel Open UI uses to build the user interface. It allows you to use custom or third-party JavaScript code to render the user interface. It binds a presentation
model to a physical control. 

Example email address validation: Let’s take a very simple example of validating email Id entered by user for a contact on Contact Form Applet at client side (no server trip). High level flow should be:
  • user types in email id and steps off the field.
  • email validation should happen at client side and error to be thrown to user if invalid email id.


Let’s first get the bird’s eye view of how to go about it.

  • your business logic should go in PM layer
    • You need to setup your PM to capture the event of user modifying email id and alert your PR to handle it. For that you will need a property – call it as – isEmailSet . Whenever user updates email id, isEmailSet will be set to true.
  • Validating email id and throwing appropriate error should go in PR layer
    • PR will trigger ValidateEmail() function whenever isEmailSet property is set by PM. ValidateEmail() function will evaluate the email id entered and will alert user if it is of wrong format.
I prefer to work with templates all the time. So, I have made it easy for you! Here are my templates that you use for all Applet PMs and PRs
All you need is copy it under /custom folder and rename it as needed. Follow the instructions provided in the .js file itself.

Presentation Model for Contact Form Applet:
Let’s create copy the Template-AppletPM.js file into /custom and rename it as ContactPM.js. You need to store your file here: \PUBLIC\enu\FILES\<Siebel_Build>\SCRIPTS\siebel\custom\ContactPM.js
I have modified the template to look like below. Let’s give a close look at what I have done.
  • It’s fine if you are not very conversant with JavaScript at this moment. Any text with Green font and gray background – you can ignore time being!
  • I replaced MyJS text with ContactPM in the whole of the template file.
  • Now, review below text with yellow background.

if( typeof( SiebelAppFacade.ContactPM ) === "undefined" ){
    SiebelJS.Namespace( "SiebelAppFacade.ContactPM" );
    define("siebel/custom/ContactPM", [], function () {
        SiebelAppFacade.ContactPM = (function () {

            function ContactPM (proxy) {
                SiebelAppFacade.ContactPM.superclass.constructor.call(this, proxy);
            }

            SiebelJS.Extend(ContactPM, SiebelAppFacade.PresentationModel);

            ContactPM.prototype.Init = function () {
                SiebelAppFacade.ContactPM.superclass.Init.call(this);
                this.AddProperty("isEmailSet", "");
                this.AddMethod("FieldChange", OnFieldChange, { sequence: false, scope: this });


                SiebelJS.Log("Model Init call");
            };
 
            function OnFieldChange(control, value) {
                SiebelJS.Log("Model OnFieldChange call for field:"+control.toString());
                if (control.GetName() === "EmailAddress") {
                    this.SetProperty("isEmailSet", (value ? true : false));
                }
            }
 
            return ContactPM;
        } ());
        return "SiebelAppFacade.ContactPM";
    });
}
  • I added Property -  isEmailSet
this.AddProperty("isEmailSet", "");
  • I added a Method to track FieldChange event and call my function: OnFieldChange ()
    this.AddMethod("FieldChange", OnFieldChange, { sequence: false, scope: this });
      • Whenever user updates any field from UI, FieldChange event will call my OnFieldChange function. If user has updated EmailAddress control then, isEmailSet will be set to true.
  • I added a custom function: OnFieldChange () – remember this function is getting called everytime a field is updated. So, first check if the control changed is EmailAddress, if so set isEmailSet to true
You can download above code here – ContactPM.js

Physical Renderer for Contact Form Applet:

Let’s create copy the Template-AppletPR.js file into /custom and rename it as ContactPR.js. You need to store your file here: \PUBLIC\enu\FILES\<Siebel_Build>\SCRIPTS\siebel\custom\ContactPR.js

I have modified the template to look like below. Let’s give a close look at what I have done.
  • It’s fine if you are not very conversant with JavaScript at this moment. Any text with Green font and gray background – you can ignore time being!
  • I replaced MyJS text with ContactPR in the whole of the template file.
  • Now, review below text with yellow background.

if( typeof( SiebelAppFacade.ContactPR ) === "undefined" ){
    SiebelJS.Namespace( "SiebelAppFacade.ContactPR" );
    define("siebel/custom/ContactPR", ["order!siebel/phyrenderer"], function () {
        SiebelAppFacade.ContactPR = (function () {
            function ContactPR(pm) {
                SiebelAppFacade.ContactPR.superclass.constructor.call(this, pm);
            };            
            SiebelJS.Extend(ContactPR, SiebelAppFacade.PhysicalRenderer);
            ContactPR.prototype.Init = function () {
                SiebelAppFacade.ContactPR.superclass.Init.call(this);
                SiebelJS.Log("ContactPR - Init call");
                this.AttachPMBinding("isEmailSet", validateEmail);
            };          
            function validateEmail() {
                SiebelJS.Log("Contact PR - validateEmail");
                var controls = this.GetPM().Get( "GetControls" );
                var cntrl = controls[ "EmailAddress" ];   
                var emailcntrl  = cntrl.GetInputName();
                var email = $('input[name="'+emailcntrl+'"]').val();
                var emailReg = /^([\w-\.]+@([\w-]+\.)+[\w-]{2,4})?$/;

                if(email == "") // If email is blank then don’t validate!
                    return true;

                alert("going to validate");                
                if( !emailReg.test( email ) ) {
                    alert("Please enter a valid Email");
                    return false;
                } 
                else {
                    alert("This is a valid Email");
                    return true;
                }
            }
            return ContactPR;
        } ());
        return "SiebelAppFacade.ContactPR";
    });
}


  • In init method, I attached PM Property -  isEmailSet to PR and whenever isEmailSet is set to true calls my function validateEmail
this.AttachPMBinding("isEmailSet", validateEmail);
  • I added custom function: validateEmail() to validate email entered by user and throw appropriate error.
You can download above code here – ContactPR.js

After adding ContactPM.js and ContactPR.js, all you need is to register them again Contact Form Applet and test. Follow below high level steps:
  • Register .js files: Navigate to Sitemap –> Admin – Application –> Manifest Files and register your custom files here.image
  • Register ContactPM.js to Contact Form Applet:

    • Navigate to Sitemap –> Admin – Application –> Manifest Administration and fill details as below:
image

  • Register ContactPR.js to Contact Form Applet:

    • Navigate to Sitemap –> Admin – Application –> Manifest Administration and fill details as below:
image

  • Test!: Clear your browser cache and login to the application and test
A quick note about SiebelJS.Log. If you are using Google chrome then, right click –> Inspect Elements –> Console. You can see all your SiebelJS.Log messages from your code logged here. See example below for above test,

image
Now the final bit to explain the text with Green font and gray background previously. NameSpace: Here Open UI maintains a list of objects instantiated in at the client side.

Let’s look at ContactPM.js

Step 1: Verify that ContactPM Object class doesn’t exist as you can have only one instance of class in JavaScript                                       
if( typeof( SiebelAppFacade.ContactPM ) === "undefined" ){

Step 2: Add ContactPM to Siebel SiebelAppFacade NameSpace.                  
    SiebelJS.Namespace( "SiebelAppFacade.ContactPM" );
Step3: Define custom Presentation model file location and other dependencies if any. Presently we have no dependencies hence []                         
    define("siebel/custom/ContactPM", [], function () {
Step 4: Add ContactPM Constructor within the class                          
        SiebelAppFacade.ContactPM = (function () {
            Step 4.1: declare Class constructor as function                 
            function ContactPM (proxy) {
            Step 4.2: inherit super Class constructor to custom class       
                SiebelAppFacade.ContactPM.superclass.constructor.call(this, proxy);
            }
            Step 4.3: declare your class as an extension of PM. Extended class now can access all prebuilt functions within default PM                  
            SiebelJS.Extend(ContactPM, SiebelAppFacade.PresentationModel);

            step 4.4: init method to add properties and methods             
            ContactPM.prototype.Init = function () {
                SiebelAppFacade.ContactPM.superclass.Init.call(this);
                this.AddProperty("isEmailSet", "");
                this.AddMethod("FieldChange", OnFieldChange, { sequence: false, scope: this });
                SiebelJS.Log("Model Init call");
            };

step 5: define custom methods here                                          

            function OnFieldChange(control, value) {
                SiebelJS.Log("Model OnFieldChange call for field:"+control.toString());
                if (control.GetName() === "EmailAddress") {
                    this.SetProperty("isEmailSet", (value ? true : false));
                }
            }

            return ContactPM;
        } ());
        return "SiebelAppFacade.ContactPM";
    });
}

Now, let’s look at ContactPR.js


Step 1: Verify that ContactPR Object class doesn’t exist as you can have only one instance of class in JavaScript                                     
if( typeof( SiebelAppFacade.ContactPR ) === "undefined" ){

Step 2: Add ContactPR to Siebel SiebelAppFacade NameSpace.                 
    SiebelJS.Namespace( "SiebelAppFacade.ContactPR" );

Step3: Define custom Physical Renderer file location and other dependencies if any. Presently we have no dependencies hence []                        

    define("siebel/custom/ContactPR", ["order!siebel/phyrenderer"], function () {

Step 4: Add ContactPR Constructor within the class                         

        SiebelAppFacade.ContactPR = (function () {





            Step 4.1: declare Class constructor as function                

            function ContactPR(pm) {

            Step 4.2: inherit super Class constructor to custom class      

                SiebelAppFacade.ContactPR.superclass.constructor.call(this, pm);
            };

            Step 4.3: declare your class as an extension of PR. Extended class now can access all prebuilt functions within default PR                

            SiebelJS.Extend(ContactPR, SiebelAppFacade.PhysicalRenderer);

            step 4.4: init method to Attach PM Binding                     

            ContactPR.prototype.Init = function () {
                SiebelAppFacade.ContactPR.superclass.Init.call(this);
                SiebelJS.Log("ContactPR - Init call");
 
                this.AttachPMBinding("isEmailSet", validateEmail);
            };

step 5: define custom methods here                                         

            function validateEmail() {
                SiebelJS.Log("Contact PR - validateEmail");
 
                var controls = this.GetPM().Get( "GetControls" );
                var cntrl = controls[ "EmailAddress" ];   
                var emailcntrl  = cntrl.GetInputName();
                var email = $('input[name="'+emailcntrl+'"]').val();
                var emailReg = /^([\w-\.]+@([\w-]+\.)+[\w-]{2,4})?$/;
 
                if(email == "") // If email is blank then don’t validate!
                    return true;
 
                alert("going to validate");
                
                if( !emailReg.test( email ) ) {
                    alert("Please enter a valid Email");
                    return false;
                } 
                else {
                    alert("This is a valid Email");
                    return true;
                }
            }
 
            return ContactPR;
        } ());
        return "SiebelAppFacade.ContactPR";
    });
}


I hope you enjoyed  this thorough explanation for Applet PM and PR with a simple example. If so, please hit like! Let me know if you have any questions.

Shiv

No comments:

Post a Comment