To start, does the table always have 4 rows, or does it have the add button so users can add rows up to a maximum of 4?
The reason I ask is that it will have a significant impact on what code will work. You can use custom validators to check for duplicates, but if users can add rows manually then you will need code that can assign that validator each time a new row is added.
The "Unique" validator and related code would be as follows (outside of the document ready event), just replace "myTable" with a CSS class you assign to the table, and "myField" with a CSS class you assign to that specific column of the table.
window.Parsley.addValidator('uniqueselection', {
validateString: function(value, requirement, field) {
var valueList = field.$element.closest('.cf-table').find('.myField').find('select').map(
function() {return $(this).val().trim(); }).get();
return _.filter(valueList, function(v) { return v == value }).length == 1;
},
messages: {
en: 'Duplicate selection.',
}
});
To assign the validator,
function assignValidator(){
$('.myTable .myColumn select').attr('data-parsley-uniqueselection','');
}
If you have a fixed number of rows, you don't really need it as a standalone function, you can just add that line of code to the end of the document ready event.
If you don't have a fixed number of rows, then you would use the following to assign the validator again each time a new row is added.
$(document).ready(function(){
$('.myTable .cf-table-add-row').on('click',function(){
assignValidator();
});
});
For good measure, I also add a function that validates other rows when one changes, but this isn't necessary because it will revalidate when you submit; the reason I do it is that if you get an error on multiple fields and change one, the other error won't go away until that field is revalidated.
Here is everything all together, but my obligatory disclaimer is that I plucked this all out of my existing forms and stripped it down to the bare bones, so there may be typos.
EDIT: Updated line 6 to ensure the delete row event would always work properly.
$(document).ready(function(){
// assign validator to initial rows
assignValidator();
// re-validate when a row is added or removed
$('.myTable').on('click','.cf-table-add-row, .cf-table-delete',function(){
assignValidator();
});
});
function assignValidator(){
// add unique validator
$('.myTable .myField select').attr('data-parsley-uniqueselection','');
// trigger validation on all rows when a row changes
$('.myTable .myField select').off('change',validateSelection).on('change',validateSelection);
}
function validateSelection(){
// revalidate the column if the value is not empty
$('.myTable .myField').each(function(e){
if($(this).val() != ''){
$(this).parsley().validate();
}
});
}
window.Parsley.addValidator('uniqueselection', {
validateString: function(value, requirement, field) {
// return a list of all column values
var valueList = field.$element.closest('.cf-table').find('.myField select').map(
function() {return $(this).val().trim(); }).get();
// return the result of a filter for more than 1 match for the current field value
return _.filter(valueList, function(v) { return v == value }).length == 1;
},
messages: {
en: 'Duplicate selection.',
}
});