Nested inputs and `required_with` validation rule


#1

Hi

I’ve read indicative documentation but couldn’t find a validation rule which works like this

'members.*.name': 'required_with:members.*.family'

the above rule says, the key is required along side value field inside the same nested object

so I extended my validator and created this tiny method:

static async requiredWithFn(data, field, message, args, get) {
	
    const value = get(data, field);
	// if (!value) return; "

	// split field by "."
	const field_parts = field.split(".");

    // because we only need first index of args
    // split args[0] by "."
	const arg_parts = args[0].split(".");

	let index = 0;
	// loop through field and find .[number]. inside it , example: members.0.name
	for(let field_part of field_parts) {

		// find .[number].
		if(/^\d+$/.test(field_part)) {

			// if index is number ( .*. ) then replace the number with related * in args array
			// from this ==> [ 'members' . '0' . 'name' ] ['members' . '*' . 'family' ]
			// to this   ==> [ 'members' . '0' . 'name' ] ['members' . '0' . 'family' ]
			arg_parts[index] = field_part;
		}
		index++;
	}

	// then search inside data ( request ) and tries to find args key , example  ['members' . '0' . 'family' ]
	let exists = true;
	for (let i = 0; i < arg_parts.length; i++) {
		if (!data || !data.hasOwnProperty(arg_parts[i]) || data[arg_parts[i]].toString().trim() === '') {
			exists = false;
		}
		data = data[arg_parts[i]];
	}

	// if args not found or value of the field is empty then throw message
	if(!(exists && value))
		throw message;
}

and use it like other validation rules

'members.*.name': 'required_with:members.*.family'
const members = [
    { name: '', family: 'Doe' }, // throw message
    { family: 'Doe' }, // throw message
    { name: 'John', family: 'Doe' }, // ok
    { name: 'Jane' } // throw message
]

I don’t know if something like this exists in AdonisJS validations but if not

  • I hope this helps others
  • And also a better version of this method can be included into AdonisJS

#2

I played with it a bit and improved it so that args part can now be multiple fields.

'members.*.name': 'required_with:members.*.family,members.*.age',


// means
// fields name,family,age should exist together inside
// any object of members array otherwise rule will fail

the above rule tests:

const members = [
    { name: '', family: 'Doe', age: 1 }, // throw error message
    { family: 'Doe' }, // throw error message
    { name: 'John', family: 'Doe' }, //  throw error message
    { name: 'Jane' }, // throw error message

    
    { name: 'John', family: 'Doe', age: 25 } // OK
]

here is the new method:

static async requiredWithFn(data, field, message, args, get) {
	const value = get(data, field)
	// if (!value) return;

	const field_parts = field.split(".");

	// outer loop index
	let index = 0;

	// loop through field and find .[number]. inside it , example: name.0.family
	for(let field_part of field_parts) {

		// find .[number].
		if(/^\d+$/.test(field_part)) {

			// inner index
			let innerIndex = 0;

			// loop through args
			for(let arg of args) {

				// split each arg by "."
				let arg_parts = arg.split(".");

				// replace .*. with .[field_index].
				arg_parts[index] = field_part;

				// replace the result of above line into args object
				args[innerIndex] = arg_parts.join(".");
				innerIndex++;
			}
		}
		index++;
	}

	/*
		the above code turns
		args : [ "members.*.family", "members.*.age" ]
		into
		args: [ "members.0.family", "members.0.age" ] or 1 or 2 ....
	 */

	// loop through each args
	let success = true;
	for(let arg of args) {
		// if value is not available then success fails.
		if(! get(data, arg) ) {
			success = false;
            break;
        }
	}

	// if any of args not exist or the value of the field itself not exists then throw message
	if( !(value && success) )
		throw message;

}

If you don’t know how to extend validator then make sure reading Extending Validator