0

what is the correct way to add an optional validation object in vuelidate?

Given a validation shape of:

validations: {
    vehicles: {
        $each: {
            type: {
                required
            },
            engine: {
                required: requiredIf((vehicle) => vehicle.type == 'car'),

                size: {
                    required
                },

                power: {
                    required
                }
            }
        }
    }
}

My expectation was that for a vehicle of type bike I would not need to provide a size and power as their parent engine is not required. However the validation is returning invalid.

sweetroll
  • 176
  • 2
  • 10
  • Can you include more of your implementation? Or at least what your model looks like? – LHM Feb 17 '20 at 18:14

2 Answers2

3

What you could do instead of asking for each subfield of engine to be required is to ask every engine to have both size and power, so that for everytime there is an engine it must have those keys. Add this together with the requiredIf and you have the following: Every vehicle must have a type, if it is a car then an engine is required and every engine must have a power and size.

The following snippet shows it working.

Vue.use(vuelidate.default);
let { required, requiredIf, helpers } = validators;
const contains = (param) =>
  (value) => !helpers.req(value) ||
    param.reduce((accum, curr) => accum && curr in value, true);
var app = new Vue({
  el: '#app',
  data: () => ({
    vehicles: [
      {
        type: 'car',
        engine: {
          size: 5,
          power: 2.5,
        }
      },
      {
        type: 'bike',
      }
    ]
  }),
  validations: {
    vehicles: {
      $each: {
        type: { required },
        engine: {
          required: requiredIf((value) => value.type === 'car'),
          contains: contains(['size', 'power']),
        }
      }
    }
  },
  created() {
    console.log(this.$v.$invalid);
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuelidate@0.7.5/dist/vuelidate.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuelidate@0.7.5/dist/validators.min.js"></script>
<div id="app"></div>
Bernardo Duarte
  • 4,074
  • 4
  • 19
  • 34
  • I think the downside to this solution is it removes validation rules for `size` and `power`. – tony19 Feb 18 '20 at 02:37
  • @tony19 no it doesn't. All you have to do is to add them, the only thing you can't do is to put required. I haven't included any because the OP hasn't. – Bernardo Duarte Feb 18 '20 at 02:38
  • Yes, it does remove the rules for those two fields. You can confirm by looking at `$v` at runtime and seeing that there are no rules for `size` and `power`. The rules would be used to display errors to the user. If you try adding the rules, you'll end up with the same problem in the original question. – tony19 Feb 18 '20 at 02:46
  • @tony19 So if I add a `size: { minValue: minValue(0) }` it won't work? – Bernardo Duarte Feb 18 '20 at 02:50
  • That seems to work in that it correctly raises an error if the field is missing. I suppose that could be a suitable replacement for `required` in this case. I think that rule should be added to your answer so that it covers the functionality originally shown in the question. – tony19 Feb 18 '20 at 02:59
  • @tony19 Agreed, but the OP hasn't placed any other validation except for required, so there is no true replacement. We need the OP's say on this. – Bernardo Duarte Feb 18 '20 at 03:06
  • Ok, fair enough. – tony19 Feb 18 '20 at 03:07
  • My actual data is a little more complex than the example I gave. Not only would there be other validation rules for size and power, they also each have nested objects of there own. I might be better off validating each vehicle type separately in their respective child components to reduce the complexity of the vueliate config. – sweetroll Feb 18 '20 at 15:19
  • @sweetroll Can you share your schema so we can have a look? – Bernardo Duarte Feb 18 '20 at 16:28
1

I went through a similar situation recently and resolved using 'parentVm', as documented at https://vuelidate.js.org/#sub-accessing-component.

You should try this:

...

engine: {
  required: requiredIf((parentVm) => {return parentVm.type === 'car'}),
  size: {between: between(yourMinValue, yourMaxValue)},
  power: {between: between(yourMinValue, yourMaxValue)},
} 
...
高鵬翔
  • 1,997
  • 2
  • 8
  • 21