Asking fields to be unique

Sometime the user need to fill multiple fields in form, also each of them must be unique. Any of them has to be different to the remaining. You might think of using the different validator which requires two fields to be different to each other, such as an username and password shouldn't be the same. In our case, the different validator isn't useful because the number of fields for doing comparison are unknown.
The form in this example asks user to provide some email addresses. User is also required to fill at least one email address. Each of them, if present, must be unique. This kind of form can be seen in a lot of forms nowadays.
The approach illustrated in this example is that:
That are straight forward steps. The next sections show the implementation in details.

Checking duplicate items in array

In order to check whether an array contains duplicated items or not, we can use a simple implementation:
const hasDuplicatedItems = function (inputArray) {
const obj = {};
const numItems = inputArray.length;
const duplicateRemoved = [];
for (const i in inputArray) {
obj[inputArray[i]] = 0;
}
for (const i in obj) {
duplicateRemoved.push(obj[i]);
}
return duplicateRemoved.length === numItems;
};
Since the array of email addresses might consist of empty item, we need to adjust the code above a little bit to ensure that the array has at least one not-empty item and doesn't contain any duplicated items:
// Assume that emailElements is the list of email elements
let notEmptyCount = 0;
const obj = {};
const duplicateRemoved = [];
for (const i in emailElements) {
const v = emailElements[i].value;
if (v !== '') {
obj[v] = 0;
notEmptyCount++;
}
}
for (const i in obj) {
duplicateRemoved.push(obj[i]);
}
if (duplicateRemoved.length === 0) {
// All the items are empty
} else if (duplicateRemoved.length !== notEmptyCount) {
// The list of emails have duplicated items
}

Using the same names

The example code below demonstrates the implementation when all email fields use the same names, email[], for example.
const form = document.getElementById('demoForm');
const fv = FormValidation.formValidation(
document.getElementById('demoForm'),
{
fields: {
'email[]': {
validators: {
emailAddress: {
message: 'The value is not a valid email address'
},
callback: {
callback: function(input) {
...
if (duplicateRemoved.length === 0) {
return {
valid: false,
message: 'You must fill at least one email address',
};
} else if (duplicateRemoved.length !== notEmptyCount) {
return {
valid: false,
message: 'The email address must be unique',
};
}
// Set all fields as valid
fv.updateFieldStatus('email[]', 'Valid', 'callback');
return {
valid: true,
};
}
},
}
}
},
plugins: {
...
},
}
);
Using the same names

Using different names

What if the email fields have different names? How we can set the validator rules for them?
In this case, we can use a same CSS class for all email fields:
<input type="text" class="js-user-email" name="user.email[0]" />
<input type="text" class="js-user-email" name="user.email[1]" />
<input type="text" class="js-user-email" name="user.email[2]" />
<input type="text" class="js-user-email" name="user.email[3]" />
and then use the selector option to apply the same set of validation rules for them:
const form = document.getElementById('demoForm');
const fv = FormValidation.formValidation(
document.getElementById('demoForm'),
{
fields: {
'email[]': {
// All email fields have .js-user-email class
selector: '.js-user-email',
validators: {
...
}
}
},
plugins: {
...
},
}
);
Using different names

See also