©2013 IBM Corporation
ICM Web Form Design and
Coding Guidelines
IBM Technical Solutions
May 2015
©2013 IBM Corporation Page 2
TABLE OF CONTENTS
DOCUMENT CONTROL .............................................................................................................. 4
DOCUMENT OVERVIEW ............................................................................................................. 5
1.1 PURPOSE .......................................................................................................................... 5
USER EXPERIENCE (UX) ........................................................................................................... 6
2.1 APPLYING A BIT OF AGILE .................................................................................................. 6
2.2 CHALLENGING REQUIREMENTS .......................................................................................... 6
2.3 TESTING ............................................................................................................................ 7
USER INTERFACE (UI) ............................................................................................................... 9
3.1 WEB FORM LAYOUT ........................................................................................................... 9
3.2 WEB FORM OBJECT NAMING CONVENTION ......................................................................... 9
3.3 TABLE FORMATTING ........................................................................................................ 10
3.4 ROW FORM FORMATTING ................................................................................................. 11
3.5 ENABLING CSS (CASCADING STYLESHEETS) ...................................................................... 13
CLIENT SIDE CODING .............................................................................................................. 15
4.1 UNDERSTANDING THE JS TEMPLATE ................................................................................. 15
4.2 WHAT MAKES A FUNCTION REUSABLE? ............................................................................. 20
4.3 CONSTANTS FOR MAINTAINABILITY .................................................................................... 21
4.4 HARDCODING WEB FORM / WEB FORM FILTER / REPORT IDS ............................................... 21
4.5 FORWARDING AND REFRESHING WEB FORMS AFTER SUBMISSION ...................................... 22
4.6 DEBUGGING JAVASCRIPT .................................................................................................. 24
4.7 COMMENTING YOUR CODE ............................................................................................... 25
4.8 SLOW PAGE LOADS ......................................................................................................... 25
4.9 DYNAMIC # OF ROW FORMS ............................................................................................. 26
4.10 BE AWARE OF USER CONCURRENCY ............................................................................. 28
4.11 LEVERAGING WINDOW.NAME ........................................................................................ 28
4.12 DETERMINING YOUR CLIENTS DATE FORMAT ................................................................. 29
4.13 BE AWARE OF THE 512 PARAMETER CEILING ................................................................. 30
JQUERY .................................................................................................................................... 31
5.1 PURPOSE ........................................................................................................................ 31
5.2 TABLE TAGS AND INCLUSION OF CELLS ............................................................................ 32
5.3 HIDING COLUMNS ............................................................................................................ 32
5.4 ENABLE EDITS ................................................................................................................. 34
5.5 SWAPPING COLUMNS ...................................................................................................... 34
5.6 BREAKING A ROW FORM INTO TWO OR MORE ROWS ........................................................ 35
5.7 IE8 AND NTH-CHILD ........................................................................................................ 35
5.8 TRIM VS REGULAR EXPRESSIONS ..................................................................................... 36
5.9 DISABLING INPUT FIELDS IN THE ROW ............................................................................... 36
5.10 DISABLING INPUT FIELDS BASED ON VALUES IN ONE COLUMN .......................................... 36
5.11 POPULATING COLUMNS BASED ON SELECTED DROPDOWN VALUES ................................. 36
©2013 IBM Corporation Page 3
5.12 LOOKUPS WITHIN A TABLE BASED ON MULTIPLE CRITERIA ............................................... 36
5.13 AJAX VALIDATION AGAINST LARGE TABLES .................................................................... 37
©2013 IBM Corporation Page 4
DOCUMENT CONTROL
Version
Date
Description
Author
Pre 1.0
Jan 2013
Initial draft
Diego Zuluaga, Afsheen
Jameel
1.0
May 2013
Revised the UX section, adding Section 2.1 and 2.3
Revised the UI section, adding Section 3.2 ~ 3.4
Revised Section 4.1: Understanding the JS Template
Nori Yumiyama
1.1
June 2013
Added Section 5: jQuery, from 5.1 ~ 5.12
Vladimir Pjevic
1.2
June 2013
Added Section 4.5: Forwarding and Refreshing Web Forms
After Submission
Afsheen Jameel
1.3
June 2013
Added Section 2.2: Challenging Requirements
Added Section 4.8: Slow Page Loads
Added Section 4.9: Dynamic # of Row Forms*
Added Section 4.13: Be Aware of The 512 Parameter
Ceiling**
Nori Yumiyama,
*Code courtesy of Diego
Zuluaga
**On behalf of Tim
Meynell
1.4
December
2014
Added section 4.3: Constants for maintainability
Added Section 4.6: Debugging JavaScript
Added section 4.11: Leveraging window.name
Added Section 4.12 Determining your client’s date format
Added section 5.7: IE8 and Nth-Child**
Steven Ye
**On behalf of Tim
Meynell
1.5
May 2015
Updated the look-and-feel
Section 4.3: Included a comment about Config()
encapsulating all hardcoded values
Section 4.11: Minor change to the problem statement
Section 5.2: Minor changes to the how the placement of
<table> tags could lead to inclusion of unwanted web cells.
Nori Yumiyama
©2013 IBM Corporation Page 5
DOCUMENT OVERVIEW
1.1 PURPOSE
The purpose of this document is to outline a set of best practices on design and coding for Web
Forms with the intent of helping to standardize development to this specific domain. The
objective is to achieve better quality code through maintainability, simplification and reusability.
This document can be used as a reference document when developing Web Forms using IBM
ICM application.
The intended audience for this document is IT Support teams and Form developers.
This document divides the form design issues into separate sections. Each section contains a
basic overview of the design issue as well as a number of best practices for resolving these
issues. The following information is provided with each best practice:
Overview, explanation and background information for the practice
Screen shots and Code Examples
Solution and Discussion
Snippets included in most examples can be found in the JSHelper singleton class that can be
obtained from Technical Solutions.
©2013 IBM Corporation Page 6
USER EXPERIENCE (UX)
Web Form Design and User Experience make the foundation of good Web Forms. Before
initiating Web Form development, it is the responsibility of the business consultants to provide
detailed description about the functionality of the Web Form along with its context. This is
typically covered during discovery and design. Two key points to keep in mind are:
Follow the design template to capture the necessary requirements
Ensure the clients involved with the mockup and use case decisions are those that have
full knowledge and authority over the business workflows
2.1 APPLYING A BIT OF AGILE
Even if the client has signed off on the mockups and use cases, expect for changes to occur. It
is frustrating for everyone when the Web Forms have to make it into the end user’s hands
before realizing it has missed the mark. What works best is an iterative process that gets the
initial implementation out to the end users as quickly as possible. This first session may be a
demo of what has been generated so far. Developers go back to working on the Web Forms
preparing for the next session. The project team and the end users work together to narrow the
gaps through these sessions, in an iterative manner, to get to a production ready state.
2.2 CHALLENGING REQUIREMENTS
The following table lists requirements that have appeared manageable when captured during
discovery but often proved difficult to implement once the end users have had a chance to test
and identify gaps. These should be flagged as potential areas of risk when identified during the
discovery phase and hashed out in full detail to understand the complexities.
Requirement
Management of
territories or
accounts through
effective dating.
Management of
quotas through
bottom up and top
down processes
spanning multiple
hierarchy levels.
©2013 IBM Corporation Page 7
Applying wildcard
searches on input
fields and drop
downs.
Ability to upload,
search, and
download files.
Real time email
notifications.
2.3 TESTING
On the eve of going live, it would be comforting to know that the Web Forms and the workflow
processes have gone through multiple rounds of web users connecting from different time
zones, different regions, executing on well thought out scenarios. Getting to this stage requires
©2013 IBM Corporation Page 8
testing at multiple levels; unit testing by the developer, functional testing by the ICM project
team and the client’s compensation team, and finally user acceptance testing.
The last thing the project team would want to encounter is a severity 1 defect that is blocking the
web users from proceeding, causing numerous hours in delays, allocating as many resources
as possible to remedy the issue and deploy them through all the environments. In the past, the
following severity 1 defects could have been avoided through proper testing.
Client-side numeric arithmetic failing in countries outside of North America because
commas represent the decimal point in those countries
Date validation failing in countries outside of North America because, for example,
dd/mm/yyyy is the preference over mm/dd/yyyy
Multiple web users manipulating the same transaction where none of them are aware of
the changes they are making
Data sources that are retrieving more than 1000 rows because all of the Web Form
filters haven’t been applied
Not enforcing the selection of all the Web Form filters causing JavaScript errors and still
allowing the web user to submit values causing unexpected data inserts/updates
©2013 IBM Corporation Page 9
USER INTERFACE (UI)
3.1 WEB FORM LAYOUT
The diagram shows different sections of a Web Form in the designer view using standard HTML
widgets for creating tables, check boxes, radio buttons, popups and CSS.
Table Ids are what the JavaScript needs to pass to the DOM to retrieve data source and row
form information. Without these ids, the JavaScript cannot manipulate or interact with the HTML
widgets.
Typically Web Form requirements include client-side validation which may not be possible
without retrieving more data sources. These data sources must be configured in the designer
view and hidden with the style=”display:none;” attribute.
3.2 WEB FORM OBJECT NAMING CONVENTION
PROBLEM
There is no quick way to identify if a Web Form object is a data source or a row form, other than
to right click on the object and viewing the editing wizard.
©2013 IBM Corporation Page 10
SOLUTION
Use a common naming convention for the HTML widget ids.
HTML Widget Type
Id Naming Convention Prefix
Parent Table
"tableID_"
Data Source
"dsID_"
Row Form
"rfID_"
Select
"selID_"
Input
"ipID_"
Text Area
"txtAreaID_"
Here are 2 Web Form objects adhering to the id naming convention where top object is a row
form and the second object is a data source.
DISCUSSION
Following a common naming convention not only makes the designer view easier to read and
maintain, the JavaScript that references these objects benefit in the same manner.
3.3 TABLE FORMATTING
PROBLEM
When there are multiple tables stacked top to bottom within the designer view, the way they are
rendered to the web user is unpredictable.
SOLUTION
A common approach is to format all the tables so that the widths and its columns are locked
through the HTML style attribute.
The following designer view contains HTML that sets the table width to 1500 pixels. Individual
column widths are also configured with the sum of those widths equaling 1500.
©2013 IBM Corporation Page 11
The HTML configured in the far left Web Form cell is:
</td></tr></table><table id='dsID_GLBDispute' style="display:none;width:1500px;table-layout:fixed;">
<col width=0>
<col width=200>
<col width=130>
<col width=130>
<col width=130>
<col width=130>
<col width=130>
<col width=130>
<col width=130>
<col width=130>
<col width=130>
<col width=130>
<col width=0>
<col width=0>
<col width=0><tr><td>
Looking closely at the data source, there is an empty Web Form cell to its left. The HTML
needs to account for this empty cell which is why the first column width is set to 0, <col
width=0>.
The browser displays the columns where the widths from left to right are 200 pixels, followed by
10 columns at 130 pixels each.
DISCUSSION
The way the tables, columns and the data are rendered becomes predictable. As a developer,
it is a nice way to control the presentation of the tables to the end user.
3.4 ROW FORM FORMATTING
PROBLEM
Row forms configured in the designer view bring in all the columns. Rearranging these columns
or hiding certain ones with JavaScript requires trial and error that could consume time and
become frustrating to the developer.
©2013 IBM Corporation Page 12
SOLUTION
To gain the flexibility a developer needs with formatting row forms, create each editable/input
field as an HTML widget.
The example below highlights 4 fields required to enter new referrals. Starting from the left Web
Form cell, there is a SELECT drop down followed by 3 INPUT fields.
JavaScript will populate the SELECT drop down with the necessary selectable key-value pairs
and enforce any web user entry validation on the 3 INPUT fields.
Hide the row form that will insert into the ICM model.
When the user clicks on the submit button, the JavaScript will:
Auto-generate a unique identifier for the PK column
Capture the entered values from the HTML widgets and set them to the corresponding
row form
Set other values in the row form
Finally submit the Web Form
DISCUSSION
The example showed how the row form had many columns but only the FARep, Company,
ClientFirst and ClientLast columns were visible and editable by the web user. On top of that,
the Company column was to be displayed to the left of ClientFirst and ClientLast. The use of
HTML widgets eliminated the need for the JavaScript to manipulate the row form directly; hiding
and reordering columns.
©2013 IBM Corporation Page 13
3.5 ENABLING CSS (CASCADING STYLESHEETS)
PROBLEM
To maintain the same presentation/style (CSS) without having to rewrite the same code or
define the same style settings for every element.
SOLUTION
Cascading Style Sheets can be applied to Web Forms by including them in the JavaScript
section. By following this structure:
</script> <!Notice how the script tag ends the previous open script section -->
<style type="text/css">
.tblWoBorder{ border:none; }
.tblWithBorder{ border: solid 1px black; }
</style>
<script> <!Notice how the script tags opens the section for JavaScript code again-->
DISCUSSION
Separating presentation and content has many benefits e.g. speed, maintainability,
customizations and accessibility.
CSS are custom files to be deployed in a separate web application on the same server in order
for web forms to use a relative URL. The same CSS file can be referenced/imported in each
Web Form.
©2013 IBM Corporation Page 14
©2013 IBM Corporation Page 15
CLIENT SIDE CODING
4.1 UNDERSTANDING THE JS TEMPLATE
PROBLEM
Enforcing code consistency and best practices in Web Form development across all client
implementations.
SOLUTION
JavaScript Coding Guidelines
The following diagram defines the general structure of Web Form code. Every Web Form must
leverage this structure in order to standardize code across multiple implementations. By
adhering to best practices and consistency in coding styles and conventions, we can ensure
optimized page loading, performance and maintainable code. Code provided along with this
documentation is for learning purposes and it is not guaranteed to be free of bugs.
©2013 IBM Corporation Page 16
©2013 IBM Corporation Page 17
This general structure is a good baseline to start with when coding Web Forms. However, it
should not restrict the developer from extending this structure when they feel it promotes
readability and maintainability. The following is where the overall structure was adhered to but
slightly different coding practices have been applied.
This first section resembles the baseline code above.
The second section is an implementation of WFSection1. It has been modified to be a
Singleton.
©2013 IBM Corporation Page 18
Lastly, an example of a Config class is shown.
©2013 IBM Corporation Page 19
DISCUSSION
Web Form Object
When a new Web Form is created, by default there is no JavaScript and the above
structure/code needs to be incorporated by selecting the JavaScript icon within a Web
Form.
Observe usage of constants for each section in the Web Form and avoid hardcoding of
indexes. This technique helps improve code maintainability. Global constants and
variables can be defined in the Config class section. The global constants and variables
are global in context of a particular Web Form i.e. independent of each Web Form and
cannot be shared across Web Forms.
Observe Web Form initialization when the page loads. This technique helps to
encapsulate a single point of entry to the Web Form. The initialization section will
generally contain code for formatting tables, web page and other objects to their desired
structure (e.g. hiding of buttons or columns, number formatting etc.), defining and setting
of variables relevant to the individual sections of a Web Form. This does not will help in
optimizing page loading but is recommended as standard or common practice.
Observe declaration of Web Form section objects and also the usage of the Helper class
functions.
All sections in the above code structure are customizable within the JavaScript window
for each distinct Web Form.
©2013 IBM Corporation Page 20
4.2 WHAT MAKES A FUNCTION REUSABLE?
PROBLEM
How to create reusable functions in Web Forms resulting in reduced time and effort and
increased performance.
SOLUTION
JavaScript and jQuery code can be made reusable and modular by:
Using and passing of parameters, rather than long and complicated function signatures
with many individual parameters, utilize the technique of passing in a single object,
which simulates a collection of name/value pairs. This makes code readable code and
easy to implement.
Using variables instead of hard coding and designing functions to be generic for code
reuse.
Limit the number of lines per function/method: By limiting the number of lines of
code per method/function, code becomes more testable and maintainable. It is
recommended that lines of code per method should not exceed 20 (average lines of
code is around 12). A long and complicated function should be broken into a number of
smaller functions.
Reusable functions are a concept and best practice; all JavaScript and jQuery functions
on a Web Form can be reused by the same Web Form.
Start function names with a verb to convey a purpose: The following snippet
demonstrates a function which initializes a Web Form. Code becomes more readable
because the methods convey their purpose.
//Web Form class initializer
WebForm.prototype.initialize = function() {
WebForm.prototype.initializePage();
new WFSection1().initialize();
new WFSection2().initialize();
};
DISCUSSION
JSHelper class stores reusable functions and methods. This class is stored on the Web Form
itself and contains standard static functions applicable to all Web Forms. Consult with your
solution architect to obtain latest version of Helper Class.
©2013 IBM Corporation Page 21
4.3 CONSTANTS FOR MAINTAINABILITY
PROBLEM
How to leverage constants in the JavaScript code to improve maintainability.
SOLUTION
When referencing hardcoded values, global variables can be used as constants. The “const”
keyword should not be used as it is not supported by IE. For cross-browser compatibility,
declare Config() within the WebForm() object (screenshot below). The purpose of Config() is to
encapsulate all the hardcoded values in one central location.
Global scope declarations like “MY_CONST1” should be avoided as it’s against the intent to
encapsulate values.
In terms of best practice, constants should only reference hardcoded values or elements that
are expected to remain static like column mappings. If a column mapping is shifted or
hardcoded value is changed in the future, only the variable declaration needs to be changed
instead of everywhere it is referenced.
DISCUSSION
Declaring a variable in the global scope does not protect it from potential changes later in the
code. Caution should be exercised as to not assign values to the variable after its initial
declaration.
Since using “const” would break compatibility with IE, its usage should be prohibited unless the
client’s browser standard is confirmed to be otherwise.
4.4 HARDCODING WEB FORM / WEB FORM FILTER / REPORT IDS
PROBLEM
How to reference web form objects (web forms, web form filters, and reports) without
hardcoding the ID values within the JavaScript code. These ID values may change when
migrated to other environments.
©2013 IBM Corporation Page 22
SOLUTION
A custom table and saved import can be created to store the static object ID’s from the back-
end tables. The custom table can then be referenced by data sources in Web Forms to retrieve
the static object ID values by name.
Create a custom table named WebFormObjects, with columns ID (primary key),
ObjectType, and ObjectName
ObjectType can be a picklist, referencing types such as Filters, Web Forms, etc…
Create a saved import with the query below. It grabs the object ID values from the back-
end tables and imports them into the WebFormObjects table.
SELECT WebFormID as 'ID', 'WebForm' as ObjectType, Name as ObjectName FROM WebForm
UNION
SELECT FilterID as 'ID', 'Filter' as ObjectType, Name as ObjectName FROM WebFormSourceFilter
To reference web object ID on Web Forms, create a datasource using WebFormObjects
table, then restrict on the ObjectName and ObjectType to return a row containing the ID.
The ID returned in the row can then be retrieved and used via JavaScript.
DISCUSSION
Since WebFormObjects table is restricted on ObjectName to retrieve an ID, ensure the object
name is unique when it is created in the model.
In case the model was updated with new web objects, the saved import has to run to update the
WebFormObjects table with ID’s for the new web objects.
After a migration to other environments, ensure the saved import is ran in all the other
environments to update the WebFormObjects table.
4.5 FORWARDING AND REFRESHING WEB FORMS AFTER
SUBMISSION
PROBLEM
How to redirect a Web Form to a different page (a report or another Web Form) once it has
been submitted.
SOLUTION
Redirecting the Web Form to another URL and passing parameters from Web Form to the new
page.
The following steps are needed:
Ø Retrieving the Report or Web Form ID dynamically. Please note that we cannot
hardcode these IDs as they can change between different environments.
Ø Set the link of the new URL (report/web form) in the Admin Client.
©2013 IBM Corporation Page 23
Ø In Submit function, the following code should be placed after validations and
prior to returning true. The window.name variable can be set to any name, for
this example we are using (“SUBMIT_ACTION”).
Ø The below code needs to be placed at the beginning of initialize function (prior
to running any other validations/functions):
$j('#lnkBack tr:gt(0) td:nth-child(1) a').attr('href');
The above line retrieves the new URL (report or web form link) dynamically and redirects the
Web Form to this page.
DISCUSSION
In cases where parameters are not required to be passed, the parameter section in edit link can
be left empty. When “SUBMIT_ACTION” is captured, the above code will set window.name to
©2013 IBM Corporation Page 24
an empty string. The variable window.name retains value set after form refresh and can be
used to check if redirection is needed.
Since window.name is a global variable residing on the client’s browser, it is important to see if
window.name has been leveraged by other Web Forms. If a hashmap-style key+value pairings
are used to store client side information, then the above code to set window.name to an empty
string may break other Web Forms.
4.6 DEBUGGING JAVASCRIPT
PROBLEM
What tools can be utilized to debug JavaScript during runtime.
SOLUTION
Google’s Chrome browser provides a suite of developer tools that are extremely helpful for
debugging JavaScript during runtime. For a full feature list and user guide on how to use the
different aspects of the tool, see here. In this section, the console tab will be the focus as it is
the most commonly used feature when debugging web forms.
When the Web Form is loaded, any runtime errors and warnings will appear in the console tab
(screenshot above). The text above the error in red identifies that the error occurred on line
1323 of the source file. Clicking on the same text will open the source file to the line where the
error occurred (screenshot below). From here, the error can be further analyzed.
©2013 IBM Corporation Page 25
Another helpful feature is console.log, which is a built-in function that prints texts onto the
Console tab. This logging feature can be utilized to track logic and variable values during
runtime.
DISCUSSION
Console.log is enabled by default on the Chrome browser, but may not be for other browsers
such as IE8 (when developer tools is disabled). If the console.log function is executed on an
incompatible browser, a JavaScript error will occur and any further code executions will
terminate. To prevent this, add the following line to the beginning of the JavaScript code.
if(!window.console) console = {log: function() {}};
As a best practice, all console.log lines in the code should be commented out before committing
for production as they are meant to serve as debug messages only.
4.7 COMMENTING YOUR CODE
PROBLEM
What best practices should be followed when commenting JavaScript codes for Web Forms.
SOLUTION
In following best practices of programming, the developer should strive to make the code as
simple as possible to understand without relying on comments as a crutch. Comments should
not be how something is done, but rather why it is done. This mindset should be applied when
developing JavaScript for Web Forms, and the subsequent principles should be followed.
As a header, state the author, ICM Web Form name, and the purpose of the Web Form
Before variables, functions, and object declarations, state the purpose of the code
For functions that are called from the ICM Web Form elements (not directly from the
code), state this clearly in the function
DISCUSSION
Coming soon…
4.8 SLOW PAGE LOADS
PROBLEM
Web Forms can be built with too much content including too many data sources and row forms
that it hinders the page from loading within the client’s level of acceptance.
©2013 IBM Corporation Page 26
SOLUTION
The following are common areas of focus when page loads become an issue:
Data sources can be thought as queries that run against the database. The simpler the
query, the quicker the database will return results to the Web Form. Simpler means:
o Reducing the number of joining tables
o Making the first data source the one with the smallest result set
o Joining on the primary keys
o Avoiding nested joins (joins to picklisted columns)
o Returning less than 10 of columns
Reducing the number of data sources within a Web Form. There may be data sources
that appear to repeat with only the restrictions being different across these similar data
sources. Combining these data sources and implementing JavaScript to parse through
the data is an option to consider.
Reducing the number of row forms within a Web Form. Having less than 5 row forms is
acceptable. If more are required or the number of row forms has to be dynamic, then
Section 4.9 Dynamic # of Row Forms should be considered.
Picklist drop downs appearing for editable data sources and row forms can cause major
page load delays when those drop downs contain hundreds, thousands, tens of
thousands of selectable items. Two common options are to:
o Filter the picklisted column to reduce the drop down size. The filter can be
applied through the wizard that allows for table column edits.
o Change the picklisted column to a text field and incorporate JavaScript to create
a drop down on load and to ensure data integrity.
DISCUSSION
Keeping performance in mind during design would set the correct level of expectations with the
client. Understanding if the Web Form will perform a certain way due to requirement
complexities, data volume or both, will then initiate discussions around de-scoping requirements
or acting on the possible solutions earlier in the project lifecycle.
If a Web Form is deemed to be loading slowly, it’s worthwhile to engage a Solution Architect to
pinpoint which pieces of the client browser to web application server/database handshaking are
causing the latency.
4.9 DYNAMIC # OF ROW FORMS
PROBLEM
To implement insertions into the ICM model from Web Forms, row forms are configured within
the Web Form designer interface. One row form corresponds to a single insertion. There is no
out-of-the-box feature that will have the Web Form generate as many row forms as required
©2013 IBM Corporation Page 27
based on a variable. For example, the variable could be the number of subordinates for each
manager which could change from manager to manager.
SOLUTION
The first step is to add a single row form object in the Web Form.
The following code can then be leveraged to add more rows to the row form table in a dynamic
fashion. This is part of the JSHelper class as well.
Now that row forms have been added, the developer still has work to populate each cloned field
with new values. This topic will not be covered here but the JSHelper class does have functions
to set values.
DISCUSSION
To implement this solution, it is suggested that the developer has an understanding of how ICM
recognizes new data for insertion into the database. The following are some tips to dissecting
the above code and how it eventually makes it into the database.
/**
* The method copies the last row of the table that has been passed in and adds a new row to the same table.
* Requires an editable input field in the last row.
*
* @param tableName is the name of the table that contains the row to be copied. The jquery "#" hash is not required.
*/
addRow: function(tableName){
var lastRow = $j('#' + tableName + ' tr:last').prev(); //Retrieve the last row in the table.
var input_name_arr = lastRow.find('td :input').eq(0).attr('name').split('_'); //Split the name attribute of the first input field from lastRow.
var input_name_clone_arr = input_name_arr.slice(0); //Copy lastRow's name attribute into another array. This array will hold the new row's
name.
var currentSourceAndSequence = parseInt(input_name_arr[2]); //Retrieve the third number from lastRow's name, which is the row
sequence.
var nextRowSequence = currentSourceAndSequence + 1; //Increment the row sequence by 1.
input_name_clone_arr[2] = nextRowSequence; //Update the new row's name array to hold next row sequence.
input_name_clone_arr = input_name_clone_arr.slice(1,input_name_clone_arr.length - 1); //Trim the first and last elements. For example,
trim {edit,310232,1,0} to result in {310232,1}.
var nextSourceSequenceStr = input_name_clone_arr.join('_'); //Join the values of the new row's array using "_", for example "310232_1".
input_name_arr = input_name_arr.slice(1, input_name_arr.length - 1);
var curSourceSequenceStr = input_name_arr.join('_'); //Join the values for the last row's array. This string will be searched for in the new
row and replaced with nextSourceSequenceStr.
lastRow.after('<tr>' + lastRow.html () + '</tr>'); //Copy the last row and append it to the end of the table.
var lastRowAfterClone = $j('#' + tableName + ' tr:last').prev(); //Retrieve the newly added last row in the table.
var lastRowAfterCloneWithNewSeqHtml = lastRowAfterClone.html().replace(new RegExp(curSourceSequenceStr, 'g'),
nextSourceSequenceStr); //The copied row still has the old row sequence. Search and replace with the newly generated row sequence.
lastRowAfterClone.html(lastRowAfterCloneWithNewSeqHtml); //Replace the HTML of the last row with HTML that has the new row
sequence.
}
©2013 IBM Corporation Page 28
Create a new button that triggers the addRow function and unhide the row form object.
This way, the developer can trigger the function without submitting the Web Form and
they can visually see how the row form HTML gets cloned.
To go one step further, the developer can attempt to programmatically set values for the
copied rows. These values will be visible on the page.
Go into Developer Tools of your preferred browser, open the HTML element viewing tab
and select one of the input fields of the original row form. Take note of the name
attribute. Select the cloned input field from the copied row and ensure the name
attribute has been correctly incremented. The onchange function of each copied input
field needs to be correctly incremented as well.
ICM Web recognizes data inserts and updates through the changing of the name
attribute from the preloaded “cell_” to “edit_”. Under the Network tab of Developer
Tools, HTTP headers can be monitored when data is submitted. Anywhere an “edit_”
parameter appears, its corresponding value is getting sent to the database.
If this implementation requires any debugging, then make sure the row sequences are
correct for the name attribute and onchange function, the copied row forms have values
to submit, and the “edit_” parameters have correct values.
Take note that on version 8, there is a JavaScript submission error stating “canSubmit is not
defined”. Submissions are still successful and audit tracking is still maintained so for now, this
error can be ignored.
4.10 BE AWARE OF USER CONCURRENCY
PROBLEM
Coming soon…
SOLUTION
Coming soon…
DISCUSSION
Coming soon…
4.11 LEVERAGING WINDOW.NAME
PROBLEM
How can we get the Web Form to behave differently based on whether it is an initial page load
or a re-load after a submission? Window.name may be leveraged in Web Forms for
functionalities such as passing data and setting flags for page redirection (section 4.5).
©2013 IBM Corporation Page 29
SOLUTION
The usage of window.name in web forms is a workaround for the missing functionalities in Web
Forms, such as redirection after submission and passing data between pages. Since
window.name is a global parameter and can be retrieved directly within the window’s console, it
should be masked whenever possible. This means window.name should be reset to blank
(window.name = “”) after the value is retrieved by JavaScript during runtime. Where possible,
this should be done at the very beginning of the code such that the value is retrieved on page
load and the assigned variable should be encapsulated within the WebForm class. Section 4.5
illustrates this usage in the screenshot below.
DISCUSSION
In practice, passing large volumes of data using window.name should be avoided when possible
due its public accessibility and error-proneness when used across multiple pages. As a
workaround, Ajax calls can be utilized to retrieve data securely and efficiently from another page
(section 5.13).
4.12 DETERMINING YOUR CLIENT’S DATE FORMAT
PROBLEM
As a default, date objects are stored and displayed in the MM/DD/YYYY format when viewed in
SQL Server or the Admin Client. On Web Forms, the date returned onto the page is reformatted
according to the locale of the client’s browser. A method should be in place to convert date
values between the system and the client.
SOLUTION
In most cases, the built-in Date() can be used to convert a date string into a universal date
object that easily manipulated into different formats with the many functions of the Date object.
For example:
var d = new Date("2014/10/27");
Getting the current value of “d” returns:
Mon Oct 27 2014 00:00:00 GMT-0400 (Eastern Daylight Time)
The date object “d” can then be converted to the North American (MM/DD/YYYY) format by
using the various getters.
var dateString = (d.getMonth()+1) + "/" + d.getDate() + "/" + d.getFullYear();
©2013 IBM Corporation Page 30
Getting the value of “dateString” returns the following, which can then be used when submitting
the web form.
DISCUSSION
It is important to note that JavaScript cannot determine the browser’s locale, so this solution is
depending on the built-in Date() to convert various formats to a universal date object.
Depending on the client’s requirements, there are some cases where Date() fails to recognize
the input string, such as DD/MM/YYYY. In this case, hardcoding of a conversion is required,
instead of using Date().
4.13 BE AWARE OF THE 512 PARAMETER CEILING
PROBLEM
Web Forms fail to submit updates to records when there are a large number of updates. In one
of the investigations, 34 records submitted by the Web Form succeeded but with 439 records,
upon submission, the “An internal error has occurred. Please contact the system administrator
for assistance.” is displayed.
SOLUTION
When ICM Web logging was turned to DEBUG mode, the following error was captured.
[org.springframework.web.servlet.handler.SimpleMappingExceptionResolver] - Handler execution
resulted in exception java.lang.IllegalStateException: Parameter count exceeded allowed maximum: 512
This was resolved by setting the following property in the Tomcat catalina.properties file:
org.apache.tomcat.util.http.Parameters.MAX_COUNT=10000
DISCUSSION
This issue and solution applies to ICM Web deployments on Apache Tomcat. To date, issues
on other web application servers have not been observed.
©2013 IBM Corporation Page 31
JQUERY
5.1 PURPOSE
This section is collection of jQuery approaches to various scenarios gathered overtime to
manage multi browser consistency and/or just fix basic usability issues. This is not a
replacement to our standard template. Standard web form coding guideline template should be
a starting point for any best practice web form development. This is a set of alternative or
additional approaches in situations that might help when some template helper functions are not
sufficient.
The intended audience for this section is the IT Support team, form developers, starters,
JavaScript ninjaslooking for syntax remainders or anyone who wants to dive into jQuery and
apply it in everyday ICM Web Form development.
PROS: Majority of jQuery commands are universal selections or DOM elements that are multi-
browser compatible. jQuery code is usually shorter than pure JavaScript code.
CONS: jQuery selectors are strings. There is no elegant way of passing parameters except by
string concatenation.
©2013 IBM Corporation Page 32
5.2 TABLE TAGS AND INCLUSION OF CELLS
Take a look at what happens when <table> tags are placed in certain cells for use by the JavaScript.
Notice that all of the highlighted rows will not have same number of cells. Some of the selected cells are
empty columns. The table “ds_new” has 5 rows with different number of highlighted cells on each row: 5
7, 7, 7 and 2 cells for rows 1 ~ 5 respectively. This could lead to unwanted cells getting processed by the
JavaScript.
To avoid this, place a starting <table> tag right above the data source/row form, in the left-most column
and a closing <table> tag, right below the data source/row form, again in the left-most column. Do not
include empty columns to the left when creating the data source/row form and do not include extra cells
on top or below when placing the <table> tags.
5.3 HIDING COLUMNS
To hide the 4
th
column we can use the hide command:
$j("table#ds_new tbody tr td:nth-child(4)").hide()
To unhide an already hidden column we can use toggle:
$j("table#ds_new tbody tr td:nth-child(4)").toggle()
nth-child references the first cell starting with 1. Notice that 4
th
cell in first row is not right above 4
th
cells
in other rows, it is shifted to the right.
©2013 IBM Corporation Page 33
The hide operation can be done by using eq, lt or gt selectors, where references in these selectors
start from 0 (zero-index based).
©2013 IBM Corporation Page 34
This code will produce same result like above:
$j("table#ds_new tbody tr").each(function(){
$j("td:eq(3)",$j(this)).hide()
})
eq, lt or gt are useful if you need to hide a range of columns. When you need to combine conditions be
careful as the code bellow will execute sequentially vs. usual range gt(2) and lt(4):
$j("table#ds_new tbody tr").each(function(){
$j("td:gt(2):lt(4)",$j(this)).hide()
})
5.4 ENABLE EDITS
After programmatically changing some values in the table you will need this piece of code in order to
manage data to be saved in the ICM model:
$j("table#ds_new tbody tr:gt(2)").each(function(){
$j('td :input[name^=cell]',$j(this)).each(function(){
var edit_name =$j(this).attr('name').replace("cell","edit");
$j(this).attr("name",edit_name);
});
});
Note:
:input will select all input fields, including input, select and textarea.
You can subselect by any attribute using e.g. [name^=cell] that will select all cells where name starts with
"cell". This is just a sample how you can change attributes in jQuery. There is standard JavaScript helper
function for enabling edit functionality.
5.5 SWAPPING COLUMNS
Use insertAfter if you need to swap the sequence of columns, e.g. column 4 and 6:
$j("table#ds_new tbody tr").each(function(){
$j("td:nth-child(6)",$j(this)).insertAfter($j("td:nth-child(3)",$j(this)));
$j("td:nth-child(5)",$j(this)).insertAfter($j("td:nth-child(6)",$j(this)));
})
©2013 IBM Corporation Page 35
5.6 BREAKING A ROW FORM INTO TWO OR MORE ROWS
This approach has been used when traditional JavaScript looping and innerHTML manipulation wasn’t
cross-browser compatible.
Use after, append and insertAfter if you need to “break” a row form into multiple rows:
//break header row
//insert empty row
$j("table#ds_new tbody tr:nth-child(3)").after("<tr>");
//add emtpy cell to match above row
$j("table#ds_new tbody tr:nth-child(4)").append("<td></td>");
//move column labels
$j("table#ds_new tbody tr:nth-child(4)").append($j("table#ds_new tbody tr:nth-child(3) td:gt(3)"));
//break data row
$j("table#ds_new tbody tr:nth-child(5)").after("<tr>");
$j("table#ds_new tbody tr:nth-child(6)").append("<td></td>");
$j("table#ds_new tbody tr:nth-child(6)").append($j("table#ds_new tbody tr:nth-child(5) td:gt(3)"));
//swap rows
$j("table#ds_new tbody tr:nth-child(5)").insertAfter($j("table#ds_new tbody tr:nth-child(3)"))
5.7 IE8 AND NTH-CHILD
The use of the nth-child query has significant performance overhead on IE version 8 and older,
especially when enclosed in loops. As a workaround, the .find(“tr”).eq() and .find(“tr”).eq() functions can
be used for substantially better performance. For example, nth-child can be converted to use find(“tr”)
and find(“td”) as follows:
for (var i = 0; i < arr.length; i++) {
console.log($j.trim($j("#table tr:nth-child(“+ i +”) td:nth-child(3)").text()));
}
for (var i = 0; i < arr.length; i++) {
console.log($j.trim($j("#table tr").eq(i).find("td").eq(3).text()));
}
©2013 IBM Corporation Page 36
5.8 TRIM VS REGULAR EXPRESSIONS
Although the trim() function exists in majority of browsers for a while, it might not work in some contexts in
IE 8 and bellow. An alternative is to use regular expression’s replace(/^\s*|\s*$/g,'') code instead.
Override/Augment the standard function:
A second approach is to augment the trim() function, if is not defined in current browser version. It has
been observed that this is slower than direct replace call.
if(typeof String.prototype.trim !== 'function') {
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g, '');
}
};
5.9 DISABLING INPUT FIELDS IN THE ROW
$j("table#ds_new tbody tr:nth-child(4) :input").attr("disabled", true);
5.10 DISABLING INPUT FIELDS BASED ON VALUES IN ONE COLUMN
$j("table#ds_new tbody tr").each(function () {
var tmp_select = $j("td:nth-child(5) select", $j(this)).val();
if (tmp_select === 'FALSE' || tmp_select === 'TRUE') {
$j(":input", $j(this)).attr("disabled", "disabled");
}
});
5.11 POPULATING COLUMNS BASED ON SELECTED DROPDOWN
VALUES
$j("table#ds_new tbody tr").each(function () {
var tmp_status = $j("td:nth-child(5) select:not(:disabled)", $j(this)).val();
if (typeof tmp_status === 'string' && tmp_status !== "") {
$j("td:nth-child(6) select:not(:disabled)", $j(this)).val(wf1.webUser)
}
});
5.12 LOOKUPS WITHIN A TABLE BASED ON MULTIPLE CRITERIA
The usual approach is to store selected records as an array within the Web Form instance. This is an
example how grep can be used to search within array and return another array as result. In case of no
single matching member returned, AccRate_value_array.length will be equal to 0.
AccRate_value_array = $j.grep(webForm.AccRatesTable, function(el, i) {
return ((Number(el.RateMin) <= ATTValue)
&& (Number(el.RateMax.replace(',','')) > ATTValue)
&& (el.Component == ComponentValue || el.ComponentValue=='*')
&& (el.CompPlanID == CompPlanIDValue || el.ComponentPlanIDValue=='*') ) ;
});
©2013 IBM Corporation Page 37
5.13 AJAX VALIDATION AGAINST LARGE TABLES
Scenario: You have a table with thousands of customers and need to validate if user has entered a
correct CustomerID. An ajax call in this scenario is used as workaround. This approach assumes there is
a second Web Form with just one input text parameter, CustomerID that will retrieve a single record if a
value exists.
function validCustomer() {
var inputs = $j("table#ds_new tr:nth-child(5) td:nth-child(8) :input").val();
var current_url = window.location.href;
var n = current_url.indexOf("/webforms/");
var ajax_url = current_url.substring(0,n) + "/webforms/index.html?L_FormID=42&L__FV18=" +
inputs + "&";
var content_html; //store response html
$j.ajax({
url: ajax_url,
type: 'GET',
async: false,
success: function(data){
content_html = data;
},
error: function() {
alert("There was a problem with Ajax call");
}
});
var r_customer_name = $j("table tbody tr:last td:nth-child(2)",$j(content_html)).text();
return r_customer_name.replace(/^\s+|\s+$/g, '');
}
Note:
The URL to the second Web Form is driven by WebFormID and ElementID of the second Web Form.
This link can be retrieved from a dummy Presenter report. The returned result from the ajax call is a
string containing the HTML of the second Web Form. jQuery is used to parse the returned string out of
the HTML.