blitzar icon indicating copy to clipboard operation
blitzar copied to clipboard

Cancel Original Data State (oldData) Update From Built-In Save Action

Open TimTraylor opened this issue 2 years ago • 6 comments

Hi Luca & team,

Nice work on all of this!

I'm wondering if there is a way to stop the automatic updating of the oldData to the formData from the built-in 'Save' action. As an example, I'm passing in a form-level validation function along with the schema, and I execute this additional function before saving to the back-end. If that validation fails I'll exit the function (defined on the Save button) without saving, the idea being that they need to continue to edit the form.

While I can force the form back into edit mode, at that point it has already made the 'oldData' equal to the 'formData', so if you click 'Cancel' after that it doesn't change it back to the original.

Is there any way to cancel the default behavior and keep them in edit without having the oldData get updated?

Thanks! Tim

TimTraylor avatar Mar 22 '22 21:03 TimTraylor

This should be the case when using the built in validation system. Or is using this not an option for you?

Can you show me some code so I can think about the best solution?

mesqueeb avatar Mar 22 '22 23:03 mesqueeb

I was trying to address cross-field validation. So things like "If 'ACH' is chosen as a payment method, then checking account and transit routing numbers are required". Or generically, "If the value of 'foo' is A, B, or C then the value entered for 'bar' must be between 5 and 10'. Those types of things.

So, what's being returned from an API call would look something like this (most schema fields removed for brevity):

const apiResult = {
    schema: [ 
    {
      id: "accountNumber",
      component: "input",
      label: "Account number",
      required: true,
      dynamicProps: ['error'],
      error: (val) => (val != null && val.length == 10 ? null : 'Must be 10 characters'),
    },
   {
      id: "transitRouting",
      component: "input",
      label: "Transit Routing",
      dynamicProps: ['disabled'],
      disabled: (val, { formData }) => formData.paymentType != 'ach',
    },
  ...],
   validationFunctions: [
      function() {
        if (formData.value.paymentType == 'ach') {
            if (!formData.value.transitRouting) {
                toaster.show('Transit routing is required for ACH.');
                return false;
            }
            if (!Number(formData.value.transitRouting) || 
                formData.value.transitRouting.length != 9) {
                toaster.show('Transit routing must be numeric and 9 digits.');
                return false;
            }
        }
        return true;
      },
    ]
  };

And then the built-in save action button calls a function like this:

function onSave(payload){
  
  let passedValidation = true;

  apiResult.validationFunctions.forEach(    
      function(func) {
        if (!func())
        {
          passedValidation = false;
          mode.value='edit';
          return;
        }
    }
  );
  
  if (!passedValidation){
    return;
  }

  toaster.show(`Would save the payload:` + JSON.stringify(payload, null, 2));
  clearForm();
  forceRemount.value++;
}

I'm doing a POC here, hence the showing of the error with toasters. The real thing would appropriately display the error on the page, styled as the built-in Blitzar errors are.

I think you can see though that I'm using the built-in field-level validation for the values of the individual items, but then I'm also trying to implement a form-level process that can address cross-field validation.

Thanks, Tim

TimTraylor avatar Mar 23 '22 12:03 TimTraylor

@TimTraylor can you add me on discord: Luca Ban [Mesqueeb]#4774

mesqueeb avatar Apr 05 '22 08:04 mesqueeb

@TimTraylor I tried to show you an example using dynamicProps for the error that would achieve something similar to what you showed me:

{
  id: "transitRouting",
  component: "input",
  label: "Transit Routing",
  dynamicProps: ['disabled', 'error'],
  disabled: (val, { formData }) => formData.paymentType != 'ach',
  error: (val, { formData }) => {
    return formData.paymentType === 'ach' && !formData.transitRouting
      ? 'Transit routing is required for ACH.'
      : null
  }
},

just one example, but I can imagine that this way of writing your validation functions should be usable for the other things you wanted to achieve as well?

mesqueeb avatar Apr 05 '22 08:04 mesqueeb

Thanks Luca, that was just a simple use case of cross-field validation at the form level, but the idea was needing something to execute at the form level before allowing a submit to be 'successful'. If you have any complex multi-field validation, trying to attach that to just one of the fields can be difficult.

I could certainly do it without using the built-in action buttons, but I really liked their ease of use.

Thanks for replying - I appreciate the response!

TimTraylor avatar Apr 08 '22 13:04 TimTraylor

I can introduce a form level error prop that in checked when clicking the save action button.

mesqueeb avatar Apr 09 '22 03:04 mesqueeb