Showing posts with label dialog. Show all posts
Showing posts with label dialog. Show all posts

Thursday, November 8, 2012

Using JavaScript in PeopleSoft: Popup Form with jQuery UI Dialog

I recently had a requirement to enable users to send an email from a specific PeopleSoft page. To be consistent with other elements of our interface, I wanted to popup a dialog with a form where the user could enter the message details. The input would then be processed on the server in PeopleCode to send the message.

Here is the dialog.



As in other areas of our public interface, most of the heavy lifting will be done by jQuery and jQuery UI. See my earlier posts for basics. By-the-way, we are still on PeopleTools 8.49. There may be a better way to do this in the world of 8.50  and beyond.

I used my standard technique of putting the JavaScript and related markup in an HTML definition. On Page.activate, the markup is injected into an HTML area on the page. I also added to the page a field for each of the user input fields that are to be displayed in the dialog. These fields are all set to Invisible - Modifiable by JavaScript. This setting allows me to create hidden fields on the page that will will be picked up by the component processor. I also gave the fields friendly names in the Page Field Name field under the General tab.

I first added the jQuery libraries, css and hidden fields to my HTML markup. The hidden field names and ids match those I entered in Page Field Name.


<script src="/rhijs/jquery.min.js" type="text/javascript"></script>
<script src="/rhijs/jquery-ui.min.js" type="text/javascript"></script>
<script src="/rhijs/date.js"  type="text/javascript"></script>
<link type="text/css" href="/rhijs/jquery-ui-1.8.5.custom.css" rel="stylesheet" />
<link type="text/css" href="/rhijs/demos.css" rel="stylesheet" />

<!-- following fields added for Client Timesheet Email -->
<input type='hidden' name='EMAIL_TO' id='EMAIL_TO'/>
<input type='hidden' name='EMAIL_CC' id='EMAIL_CC'/>
<input type='hidden' name='EMAIL_BCC' id='EMAIL_BCC'/>
<input type='hidden' name='EMAIL_SUBJECT' id='EMAIL_SUBJECT'/>
<input type='hidden' name='MESSAGE' id='MESSAGE'/>


Then the HTML for the dialog form. I'm using a combination of custom and PeopleSoft class names to style the form. The main <div> has the attribute style="display:none" to prevent the html from being shown on the page .


<!-- Send Client Email Dialog html -->
<div id="sendEmailDialog" title="Email Timesheet" style="display:none">
<style type="text/css">
.emailLabel {
display: block;
width: 90px;
float: left;
margin: 5px;
}
.emailInput {margin: 5px; }
.emailInputDisabled {margin: 5px; border: none; background-color:white; }
.dialogFormset {border: none;}
</style>
<p class="RH_PAGE_HDR">Send Timesheet by Email</p>
<p class="PSEDITBOX_DISPONLY">Type email addresses into the To, CC and BCC fields using a semicolon (;) as the separator.</p>

<fieldset class="dialogFormset">
<label for="emailFrom" class="PSEDITBOXLABEL emailLabel">From:</label>
<input type="text" id="emailFrom" class="emailInputDisabled" size="50" maxlength="254" value="%BIND(:17)" class="PSEDITBOX_DISPONLY" disabled="disabled"/><br/>
<label for="emailTo" class="PSEDITBOXLABEL emailLabel">To:</label>
<input type="text" id="emailTo" name="emailTo" class="emailInput" size="50" maxlength="254"/><br/>
<label for="emailCC" class="PSEDITBOXLABEL emailLabel">CC:</label>
<input id="emailCC" class="emailInput" size="50" maxlength="254"/><br/>
<label for="emailBCC" class="PSEDITBOXLABEL emailLabel">BCC:</label>
<input id="emailBCC" class="emailInput" size="50" maxlength="254"/><br/>
<label for="emailSubject" class="PSEDITBOXLABEL emailLabel">Subject:</label>
<input id="emailSubject" class="emailInput" size="50" maxlength="80"/><br/>
<label for="attachment" class="PSEDITBOXLABEL emailLabel">Attachment:</label>
<input id="attachment" class="emailInputDisabled" id="emailFrom" size="50"  value="%BIND(:18)" class="PSEDITBOX_DISPONLY" disabled="disabled"/><br/>
<label for="emailMessage" class="PSEDITBOXLABEL emailLabel">Message:</label>
<textarea id="emailMessage" class="emailInput" rows="6" cols="60"></textarea>
</fieldset>
</div>


When the user clicks on the email link, JavaScript pops up a jQuery UI dialog. Here's the code that does that:


// Send Client Timesheet Email 
function sendClientEmail() {
isDialogOpen = true;
sendClientEmailDialog.dialog('open');
}



// Send Client Email Dialog definition

var sendClientEmailDialog = $("#sendEmailDialog").dialog({
autoOpen: false,
width: 600,
modal: true,
buttons: {  "Send Email": sendEmail,
            Cancel: function() {
$( this ).dialog( "close" );
isDialogOpen = false;
}
                 }
    });


// Send button function for sendClientEmailDialog dialog
var sendEmail = function() {
var mail = $('#emailTo').val();
if (mail == "") {
alert("To: address is required");
return false;
}
$('#EMAIL_TO').val(mail); //hidden field
$('#EMAIL_CC').val($('#emailCC').val()); //hidden field
$('#EMAIL_BCC').val($('#emailBCC').val()); //hidden field
$('#EMAIL_SUBJECT').val($('#emailSubject').val()); //hidden field
$('#MESSAGE').val($('#emailMessage').val().replace(/\n/g,"<br/>")); //Replace cr with break
$('#RH_TC_DERIVED_CONFIRMED').val('Y'); //hidden field
$(this).dialog('close');
isDialogOpen = false;
return submitProxied.apply(window, localArgs); // continue submit process
};

In the sendClientEmailDialog definition, $("#sendEmailDialog").dialog uses the html we defined above as the body of the dialog.  The sendEmail function is called by the Send Email button. The function copies the form values into the hidden fields and continues with the normal PeopleSoft button processing. On the server, the component processor adds the hidden fields to the buffer where PeopleCode validates the input and sends the email. 


Thursday, February 17, 2011

Using JavaScript in PeopleSoft: Creating your own dialog boxes

In previous posts, I've described how I have been using JavaScript to enhance our PeopleTools 8.49 application. I've covered calculations and validation, and showed how you can proxy "delivered" PeopleSoft JavaScript to enhance your pages.

In this post I'll show how we are replacing the Peoplesoft confirmation (Yes/No OK/Cancel) message box with our own slick modal dialog boxes. I'm sure you'll agree with me that the bare, ugly pages produced by using PeopleCode messageBox() for confirmation aren't up to modern web standards. I went searching for a way to replace it. I found jQuery UI dialog. jQuery UI is a jQuery plugin designed to provide JavaScript UI elements that complement jQuery. Dialog provides a robust set of tools for creating flexible client-side dialog boxes. Here's an example of a typical OK/Cancel confirmation dialog produced by Dialog.


Dialogs are typically defined statically and called by dynamic Javascript. I've settled on a pattern that seems to work well with PeopleSoft. I define the dialog based on an empty <div>, but set most of the properties, including the html displayed in the dialog, from the event-driven code and bind variables.

Here's a typical definition.

   var $confirmDialog = $('<div></div>').dialog({
title: '%BIND(:10)',
autoOpen: false,
resizable: false,
modal: true,
minHeight: 400,
minWidth: 350,
buttons: {
OK: confirmOK,
Cancel: confirmCancel
}
});


A few things to notice. The dialog html is an empty div (<div></div>). The actually html shown in the dialog is set when it is called from a function. I'm setting the dialog title with a bind variable. autoOpen is set to false; otherwise the dialog would open when the page is loaded. The button actions are defined as named functions. They can be anonymous functions, but I find that using named functions here is cleaner, more flexible and can be reused. In many cases, I replace the actions when I call the dialog.

Here' s a function that calls the $confirmDialog:

function confirmIt(msg){ //msg must be formated as html
$confirmDialog.dialog('option' , 'height', 450);
$confirmDialog.dialog('option' , 'width', 400);
$confirmDialog.dialog('option' , 'buttons' , {OK: confirmSubmit, Cancel: closeDialog} );
$confirmDialog.html(msg);
$confirmDialog.dialog('open');
}


In this case, I'm replacing the button functions with:

// OK button function for confirm dialog
var confirmSubmit = function() {
$(this).dialog('close');
$('#TC_DERIVED_CONFIRMED').val('Y'); //hidden field
return submitProxied.apply(window, localArgs); // continue submit process
};

var closeDialog = function(){
confirmed = false;
$(this).dialog('close');
}


confirmSubmit:
  • closes the dialog box; 
  • sets a hidden field that I've added to the page with JavaScript following the PeopleTools naming convention that I can query in PeopleCode to confirm that the user has confirmed the submit on the client-side; 
  • passes the processing to the standard PeopleTools submit processing JavaScript. (I describe how this works in a previous post.)
closeDialog sets global confirmed to false and closes the dialog. This, in effect, cancels the submit and leaves the user on the original page.

You can define as many buttons as you wish, each with its own function.

The Validation Chain

This works fine for a single-step confirmation - something like "Submit your timesheet? You will not be able to make further changes. OK Cancel." But when you call a dialog box you are turning over processing to the dialog code. Unlike a PeopleSoft messageBox, it never returns a value to the calling code. So, what if you need to process several validations and confirmations? To handle this, I use a technique I call the validation chain. In the validation chain, each step is a function that can stop the processing or call the next step until the chain is complete.

Here's an example.

   function myFunction () {
       ...
       //validationChain is declared global
validationChain = [validateInOut,validateZeroHours,validateTimeOnHoliday,validateSubmit];

       return nextValidation();

       ...
  }

   // call the next validation in the chain
   function nextValidation() {
var next = validationChain.shift();
var nextUndefined = next == undefined;
if (!nextUndefined) {
           return next()
};
      return true;
}


First, we set up a global array of validation/confirmation functions; the validation chain. Then we call nextValidation().

nextValidation removes the first function from the chain and stores it in variable next. Then, if the function is defined, it is called.

Now each function can do validation or confirmation including calling a dialog box. To stop the process the function returns false. To continue, the function, or the dialog it calls, calls nextValidation(). Here's an example validation function that can be added to the validation chain:

 // User confirms time on holiday  
function validateTimeOnHoliday() {
if (timeOnHoliday()){
var msg = '%BIND(:2)'.
replace('%1',holidayDateString);
$confirmDialog.dialog('option' , 'buttons' , {OK: confirmContinue, Cancel: closeDialog} );
$confirmDialog.html(msg);
$confirmDialog.dialog('open');
return false; // we'll only get here if the user cancels
} else {
return nextValidation()
};
}

// Continue button function for validation chain dialog
var confirmContinue = function() {
$(this).dialog('close');
return nextValidation();
}

// Close the dialog without taking any action - this will end the validation chain
var closeDialog = function(){
$(this).dialog('close');
}


Now you can call any number of validations and confirmations before submitting the page to the server.

I hope you have found my JavaScript blog entries helpful. If you have your own ideas on how to use JavaScript to improve PeopleSoft applications, please let me know.