• 1

Read this first!

We do not monitor these forums. The forum is provided to exchange information and experience with other users ONLY. Forum responses are not guaranteed.

However, please submit a ticket if you have an active subscription and wish to receive support. Our ticketing system is the only way of getting in touch with RSJoomla! and receiving the official RSJoomla! Customer Support.

For more information, the Support Policy is located here.

Thank you!

TOPIC: How to implement "Save as draft" Form + Directory

How to implement "Save as draft" Form + Directory 3 hours 10 minutes ago #44252

  • info4313
  • info4313's Avatar
  • OFFLINE
  • Fresh Boarder
  • Posts: 3
  • Thank you received: 2
How to implement a "Save as draft" button that bypasses validation — Form + Directory

Context

This guide explains how to add a "Save as draft" button to an RSForm! Pro form and its Directory, allowing users to save incomplete submissions without triggering validation errors. The "Send definitively" button keeps full validation.

PART 1 — The Form (creation)

Step 1 — Add a hidden field

Add a Hidden field to your form named is_draft with default value 0.

Step 2 — Add a Button field (not a Submit Button)

Add a component of type Button (not Submit Button) named btn_save.

In Additional Attributes:
type="button" class="uk-button uk-button-secondary"

Label: Save as draft

Step 3 — Scripts called on form process (ScriptProcess)

This script runs during form processing — it clears $invalid when saving as draft, keeping only the fields you always require:
$isDraft = $_POST['form']['is_draft'] ?? '0';
 
if ($isDraft === '1') {
    $invalid = array();
 
    // Fields that are always required even for draft
    $alwaysRequired = array('field1', 'field2', 'field3');
    foreach ($alwaysRequired as $fieldName) {
        $val = isset($_POST['form'][$fieldName]) ? trim($_POST['form'][$fieldName]) : '';
        if ($val === '') {
            $invalid[] = RSFormProHelper::getComponentId($fieldName);
        }
    }
}

Step 4 — User Email Script and Admin Email Script

Block emails when saving as draft:
// UserEmailScript
$d = JFactory::getApplication()->input->get('form', array(), 'array');
if ($d['is_draft'] == '1') { $userEmail['to'] = ''; }
 
// AdminEmailScript
$d = JFactory::getApplication()->input->get('form', array(), 'array');
if ($d['is_draft'] == '1') { $adminEmail['to'] = ''; }

Step 5 — ScriptProcess2 (optional — custom thank you message for draft)
$d = JFactory::getApplication()->input->get('form', array(), 'array');
if ($d['is_draft'] == '1') {
    $thankYouMessage = '<h2>Draft saved</h2><p>Your draft has been saved without sending emails.</p>';
}

Step 6 — CSS and Javascript tab of the form

Add this JavaScript. It intercepts the btn_save click, sets is_draft=1, bypasses client-side AJAX validation, and submits.
Note: Replace rsform_error_YOUR_FORM_ID with your actual form ID, e.g. rsform_error_6.
<script type="text/javascript">
window.addEventListener('load', function () {
 
    var btnSave = document.getElementById('btn_save');
    if (btnSave) {
        btnSave.addEventListener('click', function (e) {
            e.preventDefault();
            e.stopImmediatePropagation();
 
            var form = document.getElementById('userForm');
            var draftField = document.querySelector('[name="form[is_draft]"]');
            if (!form || !draftField) return;
 
            draftField.value = '1';
 
            form.querySelectorAll('.rsform-error').forEach(function (el) { el.classList.remove('rsform-error'); });
            form.querySelectorAll('.formError').forEach(function (el) { el.classList.remove('formError'); el.classList.add('formNoError'); });
            form.querySelectorAll('[aria-invalid="true"]').forEach(function (el) { el.removeAttribute('aria-invalid'); el.removeAttribute('aria-describedby'); });
            var errDiv = document.getElementById('rsform_error_YOUR_FORM_ID');
            if (errDiv) errDiv.style.display = 'none';
 
            form.querySelectorAll('input[type="file"]').forEach(function (input) {
                input.removeAttribute('data-rsfp-required');
                input.removeAttribute('data-rsfp-minfiles');
            });
            form.querySelectorAll('[aria-required="true"]').forEach(function (f) {
                f.setAttribute('aria-required', 'false');
            });
 
            var originalDisplay = RSFormPro.Ajax.displayValidationErrors;
            RSFormPro.Ajax.displayValidationErrors = function() { return; };
 
            try {
                RSFormPro.Ajax.validate(form);
            } catch(err) {}
 
            setTimeout(function () {
                RSFormPro.Ajax.displayValidationErrors = originalDisplay;
                form.querySelectorAll('input[type="file"]').forEach(function (input) {
                    input.setAttribute('data-rsfp-required', 'true');
                    input.setAttribute('data-rsfp-minfiles', '1');
                });
                form.querySelectorAll('[aria-required="false"]').forEach(function (f) {
                    f.setAttribute('aria-required', 'true');
                });
            }, 2000);
        }, true);
    }
});
</script>

PART 2 — The Directory (editing existing submissions)

Step 1 — Scripts called on Edit Layout

This script handles the "Save as draft" button (data-directory-task="apply"). It bypasses directory-edit.min.js validation and injects is_draft=1 before submitting:
$doc = JFactory::getDocument();
$js = "
document.addEventListener('DOMContentLoaded', function() {
 
    var btnApply = document.querySelector('[data-directory-task=\"apply\"]');
    if (btnApply) {
        btnApply.addEventListener('click', function(e) {
            e.stopImmediatePropagation();
            e.preventDefault();
 
            var form = document.getElementById('directoryEditForm');
            if (!form) return;
 
            var taskField = form.querySelector('[name=\"task\"]');
            if (taskField) taskField.value = 'apply';
 
            var existing = form.querySelector('[name=\"form[is_draft]\"]');
            if (existing) {
                existing.value = '1';
            } else {
                var input = document.createElement('input');
                input.type = 'hidden';
                input.name = 'form[is_draft]';
                input.value = '1';
                form.appendChild(input);
            }
 
            form.submit();
 
        }, true);
    }
});
";
$doc->addScriptDeclaration($js);

Step 2 — Scripts called when submission is updated

Clear the validation array when saving as draft:
$isDraft = $_POST['form']['is_draft'] ?? '0';
 
if ($isDraft === '1') {
    $validation = array();
}

Step 3 — Script called before directory emails are sent

Block emails when saving as draft:
$app = JFactory::getApplication();
$task = $app->input->get('task');
if ($task == 'submissions.apply' || $task == 'apply') {
    $directoryEmail['to'] = '';
    $directoryEmail['_no_p_run'] = 1;
}

Key differences between Form and Directory
.FormDirectory
Validation variable$invalid$validation
Script locationScriptProcessScripts called when submission is updated
Button typeButton field (type="button")data-directory-task="apply"
JS approachBypass RSFormPro.Ajax.validatestopImmediatePropagation() + form.submit()
Critical note confirmed by RSJoomla support: In the Directory context, the variable to clear is $validation, NOT $invalid. This is the key difference that is not documented anywhere.
The administrator has disabled public write access.
  • 1

Read this first!

We do not monitor these forums. The forum is provided to exchange information and experience with other users ONLY. Forum responses are not guaranteed.

However, please submit a ticket if you have an active subscription and wish to receive support. Our ticketing system is the only way of getting in touch with RSJoomla! and receiving the official RSJoomla! Customer Support.

For more information, the Support Policy is located here.

Thank you!