Introduction
Many JS frameworks provide custom confirm and alert message boxes. Message box creation implementation may differ from one framework to another, but there is one common part – user selection is always processed by a callback function, which makes source code too messy, especially when multiple confirm message boxes generated inside one javascript function.
This article provides an example of custom confirm and alert message boxes that don’t use callbacks and therefore don’t break execution flow.
Background
The idea is quite simple. Message box initialization function (VM.MsgBox.Start) stores caller function and all its arguments in a stack, and after the user made his selection message box stores the result and calls the above function again. VM.MsgBox.Start must be called at the beginning of each function generating confirm/alert message boxes.
One more function (VM.MsgBox.Clear) is required to clear message box stack. VM.MsgBox.Clear must be called from a function that calls the function generating confirm/alert message boxes.
Message box icon is defined by one of the following values:
VM.MsgBoxIcon = { Excl: 0, Info: 1, Ques: 2, Stop: 3, Custom: 4 }, where first four values are considered to apply to "system" icons.
Message box result is defined by one of the following values:
VM.DlgResult = { OK : 0, Cancel: 1, Retry: 2, Abort: 3, Ignore: 4, Yes: 5, No: 6, Custom: -1, Unknown: 99 }
The result returned by the first call to Confirm is always VM.DlgResult.Unknown.
VM.MsgBox.Confirm and VM.MsgBox.Alert are used to generate custom confirm and alert message boxes respectively.
Both functions take the same set of parameters:
id: message box id
msg: message to be displayed in the message box
icon: system message box icon
src: image source for a custom message box icon
fn: message box callback function used to set message box styles/colors.
iGap: margin in pixels between message box text and the icon
vGap: vertical margin between message box components (text, check boxes, progress bars)
Last four parameters are optional. If multiple confirm/alert message boxes are generated inside one javascript function each message box must have a unique id.
Using the code
This demo project contains a single page that provides a simple Employee Editor.
Page initialization function adds few records to the employee’s table, sets system message box icons and creates combo boxes for an employee’s date of birth, gender and position selection.
function initPage()
{
VM.SetLanguage('EN');
VM_AddEventHandler("mainDiv", VM_EVT_BRESIZE, "OnBodyResized");
var table = document.getElementById("employeeTbl");
VM.SetAttr(table, "selOnClk", "1");
VM.SetAttr(table, "clickFunc", "onRecSelected");
addEmployee("Mark", "Smith", "1968;01;15;00;00;00", 0, 2);
addEmployee("Stephany", "Brown", "1987;06;11;00;00;00", 1, 1);
addEmployee("Michael", "Stivenson", "1956;11;02;00;00;00", 0, 0);
g_tblAdjuster = VM.TblAdjuster.Create();
g_tblAdjuster.AddTable("employeeHdr", "employeeTbl", -1, true);
g_tblAdjuster.AdjustTable("employeeHdr", true);
VM.MsgBox.iconInfo = 'Images/mb_info.png';
VM.MsgBox.iconExcl = 'Images/mb_excl.png';
VM.MsgBox.iconQues = 'Images/mb_ques.png';
VM.MsgBox.iconStop = 'Images/mb_stop.png';
initCombos();
}
“Add”, “Modify” and “Delete” employee button click events are handled by onButtonClick function
function onButtonClick(m)
{
VM.MsgBox.Clear();
editEmployee(m);
}
editEmployee function generates “confirm-type” message boxes in the following situations
- The full name of a new or modified employee (a combination of the last and the first name) matches an existing employee’s full name.
- The selected date of birth is outside the allowed interval, making employee’s age either less that 18 or greater that 100 years.
- The employee is being deleted.
The “alert-type” message box is generated if the employee’s last or first name is empty.
function editEmployee(m)
{
VM.MsgBox.Start();
var v = {f: "", l: "", d: "", g: -1, p: -1};
var res = true;
if (m == 2)
{
res = g_custom ? Confirm('conf_delete', g_msg[0], VM.MsgBoxIcon.Ques) : confirm(g_msg[0]);
}
else
{
v.f = document.getElementById("f_name").value;
v.l = document.getElementById("l_name").value;
if (v.f == '' || v.l == '')
{
var n = (v.f == '') ? 4 : 5;
if (g_custom)
Alert(g_msg[n], VM.MsgBoxIcon.Excl);
else
alert(g_msg[n]);
res = false;
}
else if (employeeExists(m, v.f, v.l))
{
res = g_custom ? Confirm('conf_exists', g_msg[3], VM.MsgBoxIcon.Ques) : confirm(g_msg[3]);
}
if (res)
{
for (var i=0; i<3; i++)
{
var divID = (i == 2) ? "pos_combo" : (i == 1) ? "gend_combo" : "dob_combo";
var div = document.getElementById(divID);
var combo = div ? VM.FindCtrlByParentDiv(div, true) : null;
var list = combo ? combo.m_obj : null;
if (list)
{
if (i == 0)
v.d = list.GetValue();
else if (i == 1)
v.g = list.GetCurSel();
else
v.p = list.GetCurSel();
}
}
var resAge = validateDate(v.d);
if (resAge > 0)
{
res = g_custom ? Confirm('conf_age', g_msg[resAge], VM.MsgBoxIcon.Ques) :
confirm(g_msg[resAge]);
}
}
}
if (res)
{
if (m == 2)
deleteEmployee();
else if (m == 0)
addEmployee(v.f, v.l, v.d, v.g, v.p);
else
modifyEmployee(v.f, v.l, v.d, v.g, v.p);
if (m != 1)
{
g_tblAdjuster.AdjustTable("employeeHdr", false);
enableButtons();
}
}
}
Depending on the message box type selected by the user function will either generate system or custom message boxes.
Note: Script file (VMWebControls_min.js) containing message box base classes as well as few other classes of my widgets library used in this project are supplied in a packed format.