The Zurich release has arrived! Interested in new features and functionalities? Click here for more

onSubmit script g_modal popup saving form when popup appears

Khalnayak
Tera Guru

Hello,

I have the following onSubmit client script, and it presents a modal popup for end users when conditions are met.

This is for native Ui and agent workspace.

Works fine in native, it prompts the user with modal and only submits form when user selects yes.

Whereas in workspace, when the modal popup appears the form saves at the same time.

How can I prevent the form from saving in workspace until the modal has not been actioned, i.e. yes/no selected.

here is my script for HR cases:

function onSubmit() {

    var subjectPersonValue = g_form.getValue('subject_person');
    var openedForValue = g_form.getValue('opened_for');
    var openedFor = g_form.getControl('opened_for');



    var url = top.location.href;
    if (url.indexOf('workspace') <= -1) { // if using native UI run this code

        if (openedFor.changed) {
            if (subjectPersonValue == openedForValue) {

                if (g_scratchpad._action_confirmed) {
                    return true;
                }
					// Render GlideModal window
                var dialog = new GlideModal('glide_modal_confirm', false, 400);
                dialog.setTitle(new GwtMessage().getMessage('Opened for Changed to Subject Person'));
                dialog.setPreference('body', new GwtMessage().format("You have set the Opened For to the Subject Person, which will grant them access to view the Case - are you sure?"));
                dialog.setPreference('focusTrap', true);
                dialog.setPreference('onPromptComplete', doComplete);
                dialog.setPreference('onPromptCancel', doCancel);

                dialog.render();

                return false;

                function doComplete() {
                    g_scratchpad._action_confirmed = true;
                    gsftSubmit(null, g_form.getFormElement(), g_form.getActionName());
                }

                function doCancel() {

                }

            }
        }
    } else if (url.indexOf('workspace') > -1) { // if using workspace run this code

        if (g_scratchpad.openedFor != g_form.getValue('opened_for')) { // If opened for value has changed

            if (subjectPersonValue == openedForValue) {
				// Render Modal window
                var msg = "You have set the Opened For to the Subject Person, which will grant them access to view the Case - are you sure?";
                g_modal.confirm(getMessage("Opened for Changed to Subject Person"), msg, function(confirmed) {

                    if (confirmed) {
                        g_form.save();
                    }
                });
            }


        }

    }


}
18 REPLIES 18

In my test instance I have the exact two Client Scripts on sn_hr_core_case table, one onChange of Opened for the other onSubmit and when I change Opened for to be the same as Subject person and I hit "Save", I get:

find_real_file.png

Here's the onSubmit:

find_real_file.png

And here's the onChange:

find_real_file.png

Thank you Janos, I didnt select all for the on change client script. It is now working.

The only other thing that I had in my previous code which I should have updated when I posted this question was, I need to first check for the following condition

 

  if (subjectPersonValue != openedForValue || subjectPersonValue != openedByValue) { //Subject person does not have access to view case

this if statement checks if the subject person currently has access to the case, if the subject person is not the same as opened for or opened by then that means they do not have access and only then the code should run and display the modal confirm box.

 

Can you help me add this code and ensure this logic works in both native UI and workspace please?

That kinda' changes the whole logic of the solution. You need to compare stuff as was when the form has been loaded with stuff as is in the form. For that to be possible, I would create a display Business Rule on sn_hr_core_case to cache the opened by, opened for and subject person information on the scratchpad:

(function executeRule (current) {
	['opened_by',
	 'opened_for',
	 'subject_person'].forEach(cacheOn(g_scratchpad, current));

	function cacheOn (scratchpad, core_case) {
		return function cache (fieldName) {
			scratchpad['u_' + fieldName] = getElementData(core_case[fieldName]);
		};
	}

	function getElementData (element) {
		return element.nil() ? { 'displayValue': '', 'uniqueValue': '', } : { 'displayValue': element.getDisplayValue(), 'uniqueValue': '' + element, };
	}
})(current);

To account for cases where this field might not be on the form. Tip: give the Business Rule a condition like gs.isInteractive() to make it pass an instance scan.

Next I would modify the Client Script to simplify the cached information on the data object:

		var data = {
			'actionName': g_form.getActionName(),
			'actionConfirmed': g_scratchpad.u_actionConfirmed,
			'messages': {
				'Opened for Changed to Subject Person': '',
				'You have set the Opened For to the Subject Person, which will grant them access to view the Case - are you sure?': '',
			},
			'opened_by': g_form.getValue('opened_by'),
			'opened_for': g_form.getValue('opened_for'),
			'subject_person': g_form.getValue('subject_person'),
			'whenTranslated': showConfirmModal,
		};

Once that is done, it can be used in the function that decides whether the warning process should be launched, or not (in function confirmationIsNeeded()😞

	function confirmationIsNeeded (data) {
		return !subjectPersonHadAccess(data) && subjectPersonWillHaveAccess(data);
	}

	function subjectPersonHadAccess (data) {
		return subjectPersonWasOpenerOrOpenedFor(data) && subjectPersonHasNotChanged(data);
	}

	function subjectPersonWasOpenerOrOpenedFor (data) {
		return !~[g_scratchpad.u_opened_by.uniqueValue,
				  g_scratchpad.u_opened_for.uniqueValue].indexOf(data.subject_person);
	}

	function subjectPersonHasNotChanged (data) {
		return g_scratchpad.u_opened_for.uniqueValue == data.subject_person;
	}

	function subjectPersonWillHaveAccess (data) {
		return [g_scratchpad.u_opened_by.uniqueValue,
				loadedOrCurrentValue(g_scratchpad.u_opened_for.uniqueValue, data.opened_for)].some(data.subject_person);
	}

	function loadedOrCurrentValue (loaded, current) {
		return current || loaded;
	}

So basically expand the original function into a bunch more. That will render the line below not necessary:

data.opened_for_isSameAs_subject_person = data.opened_for == data.subject_person;

So the final script would look as below:

function onSubmit () {
	var data = getData(g_form, g_scratchpad);

	return !confirmationIsNeeded(data) || queryConfirmation(data);

	function getData (g_form, g_scratchpad) {
		var data = {
			'actionName': g_form.getActionName(),
			'actionConfirmed': g_scratchpad.u_actionConfirmed,
			'messages': {
				'Opened for Changed to Subject Person': '',
				'You have set the Opened For to the Subject Person, which will grant them access to view the Case - are you sure?': '',
			},
			'opened_for': g_form.getValue('opened_for'),
			'subject_person': g_form.getValue('subject_person'),
			'whenTranslated': showConfirmModal,
		};

		data.translationCount = Object.keys(data.messages).length;

		jslog(JSON.stringify(data, null, '\t'), 'onSubmit_:getData', new Date().toISOString());

		return data;
	}

	function confirmationIsNeeded (data) {
		var output = !subjectPersonHadAccess(data) && subjectPersonWillHaveAccess(data)

		jslog(output, 'onSubmit_:confirmationIsNeeded', new Date().toISOString());

		return output;
	}

	function subjectPersonHadAccess (data) {
		var output = subjectPersonWasOpenerOrOpenedFor(data) && subjectPersonHasNotChanged(data);

		jslog(output, 'onSubmit_:subjectPersonHadAccess', new Date().toISOString());

		return output;
	}

	function subjectPersonWasOpenerOrOpenedFor (data) {
		var output = !~[g_scratchpad.u_opened_by.uniqueValue,
				  g_scratchpad.u_opened_for.uniqueValue].indexOf(data.subject_person);

		jslog(output, 'onSubmit_:subjectPersonWasOpenerOrOpenedFor', new Date().toISOString());

		return output;
	}

	function subjectPersonHasNotChanged (data) {
		var output = g_scratchpad.u_opened_for.uniqueValue == data.subject_person;

		jslog(output, 'onSubmit_:subjectPersonHasNotChanged', new Date().toISOString());

		return output;
	}

	function subjectPersonWillHaveAccess (data) {
		var output = [g_scratchpad.u_opened_by.uniqueValue,
				loadedOrCurrentValue(g_scratchpad.u_opened_for.uniqueValue, data.opened_for)].some(isSameAs(data.subject_person));

		jslog(output, 'onSubmit_:subjectPersonWillHaveAccess', new Date().toISOString());

		return output;
	}

	function isSameAs (comparee) {
		return function isSame (compared) {
			var output = compared == comparee;

			jslog(output, 'onSubmit_:isSameAs:isSame', new Date().toISOString());

			return output;
		};
	}

	function loadedOrCurrentValue (loaded, current) {
		var output = current || loaded;

		jslog(output, 'onSubmit_:loadedOrCurrentValue', new Date().toISOString());

		return output;
	}

	function queryConfirmation (data) {
		var output = data.actionConfirmed || translateAndConfirm(data)

		jslog(output, 'onSubmit_:queryConfirmation', new Date().toISOString());

		return output;
	}

	function translateAndConfirm (data) {
		var output = Object.keys(data.messages).reduce(translateMessage(data), false);

		jslog(output, 'onSubmit_:translateAndConfirm', new Date().toISOString());

		return output;
	}

	function translateMessage (data) {
		return function translate (sum, key) {
			getMessage(key, setTranslatedMessage(data, key));
			return sum;
		};
	}

	function setTranslatedMessage (data, key) {
		return function setMessage (message) {
			data.messages[key] = message;
			data.translationCount--;
			var output = data.translationCount > 0 || data.whenTranslated(data);

			jslog(output, 'onSubmit_:setTranslatedMessage:setMessage', new Date().toISOString());

			return output;
		};
	}

	function showConfirmModal (data) {
		var output = runningInWSEnvironment() ? openWSModalAndAbort(data) : openUI16ModalAndAbort(data);

		jslog(output, 'onSubmit_:showConfirmModal', new Date().toISOString());

		return output;
	}

	function runningInWSEnvironment () {
		var output = typeof g_aw != 'undefined';

		jslog(output, 'onSubmit_:runningInWSEnvironment', new Date().toISOString());

		return output;
	}

	function openWSModalAndAbort (data) {
		return g_modal.confirm(data.messages['Opened for Changed to Subject Person'],
			data.messages['You have set the Opened For to the Subject Person, which will grant them access to view the Case - are you sure?'],
			onWSModalResult(data));
	}

	function onWSModalResult (data) {
		return function onWSModalResult (acceptedOrDismissed) {
			var output = acceptedOrDismissed ? doComplete(data)() : doCancel();

			jslog(output, 'onSubmit_:onWSModalResult', new Date().toISOString());

			return output;
		};
	}

	function openUI16ModalAndAbort (data) {
		var dialog = new GlideModal('glide_modal_confirm', false, 400);

		dialog.setTitle(data.messages['Opened for Changed to Subject Person']);

		dialog.setPreference('body', data.messages['You have set the Opened For to the Subject Person, which will grant them access to view the Case - are you sure?']);
		dialog.setPreference('focusTrap', true);
		dialog.setPreference('onPromptComplete', doComplete(data));
		dialog.setPreference('onPromptCancel', doCancel(data));

		dialog.render();

		return false;
	}

	function doCancel (data) {
		return function () {
			return getMessage('The record has not been saved', addInfoMessageTo(g_form));
		};
	}

	function doComplete (data) {
		return function () {
			g_scratchpad.u_actionConfirmed = true;
			return runningInWSEnvironment() ? g_form.save(data.actionName) : gsftSubmit(null, g_form.getFormElement(), data.actionName);
		};
	}

	function addInfoMessageTo (form) {
		return function addInfoMessage (message) {
			return form.addInfoMessage(message);
		};
	}
}

Hopefully I got the business requirements right.

You can safely remove all jslog statements, if you want to.