Hi Sheldon,
There are a variety of issues with the code you found on StackOverflow. Put simply, it's designed for static tables where the entire table gets generated on the server and then is served to the client, whereas Laserfiche Forms has dynamic tables where users can add more rows to the table. Every row that is added gets a "fresh" dropdown field, whose values will not be initially disabled like you would want it to.
This is also why the code you have works only for the first row. When you do:
$('select').change()
The change event handler gets attached only to the dropdown fields that are currently on the form. New dropdown fields, i.e. those added by the user, don't get the event handler attached.
JQuery provides a mechanism to attach event handlers to dynamic elements using a method called delegation. The trick is to attach the handler to a static parent element. For example, if your table id is q5, you can do this:
$('#q5').on('change', 'select', function() {
...
});
Since the table itself is static, it delegates the event to its children elements, even if those elements are added dynamically.
The reason your entire dropdown field is getting disabled is because of this line:
tr.find('.stockCode option').attr("disabled","");
If you want to enable a field, you need to explicitly set the disabled attribute to false:
tr.find('.stockCode option').attr("disabled","false");
Lastly, the reason your lookup doesn't work is because, as per W3C's HTML form specification, disabled fields don't get their values submitted. This prevents lookups from being performed. There are various workarounds for this, but for Laserfiche Forms, the easiest is to add a short (i.e. 10 ms) delay before disabling the field:
setTimeout(function() {
$("select option").filter(function() {
return $.inArray($(this).val(),arr)>-1;
}).attr("disabled",true);
}, 10);
In any case, even with the above changes, that code snippet won't work well:
- Dropdown fields in newly added rows have all values initially enabled, allowing the user to select them.
- Removing a table row does not enable that row's selection in other rows' dropdowns.
I wrote an alternative. See below:
$(document).ready(function() {
var masterList = [];
var selectedList = [];
//this function taken from http://stackoverflow.com/questions/7837456/comparing-two-arrays-in-javascript
Array.prototype.equals = function (array) {
// if the other array is a falsy value, return
if (!array)
return false;
// compare lengths - can save a lot of time
if (this.length != array.length)
return false;
for (var i = 0, l=this.length; i < l; i++) {
// Check if we have nested arrays
if (this[i] instanceof Array && array[i] instanceof Array) {
// recurse into the nested arrays
if (!this[i].equals(array[i]))
return false;
}
else if (this[i] != array[i]) {
// Warning - two different object instances will never be equal: {x:20} != {x:20}
return false;
}
}
return true;
}
function createMasterList() {
masterList = [];
$('#Field16\\(1\\)').children('option').each(function() {
masterList.push($(this).val());
});
masterList.shift(); //remove blank value
}
createMasterList(); //used to check if all dropdown values have been selected
function updateSelectedList() {
selectedList = [];
var selectedValue;
$('.stockCode').each(function() {
selectedValue = $(this).find('option:selected').text();
if (selectedValue != "" && $.inArray(selectedValue, selectedList) == "-1") {
selectedList.push(selectedValue);
}
});
}
//disable the dropdown items that have already been selected
function disableAlreadySelected() {
$('option').each(function() {
if ($.inArray(this.value, selectedList) != "-1") {
$(this).attr("disabled", true);
} else {
$(this).attr("disabled", false);
}
});
}
//If all values have been selected, don't let the user add more rows
function hideAddButtonIfDone() {
masterList.sort();
selectedList.sort();
if (masterList.equals(selectedList)) {
console.log("lists equal, hiding add button");
$('#q5 .cf-table-add-row').hide();
}
else {
console.log("lists not equal, showing add button");
$('#q5 .cf-table-add-row').show();
}
}
$('#q5').on('change', '.stockCode', function() {
setTimeout(function() {
updateSelectedList();
disableAlreadySelected();
hideAddButtonIfDone();
}, 10);
});
//when a new table row is added, disable the dropdown options that have already been selected
$('#q5 .cf-table-add-row').on('click', disableAlreadySelected);
//when a table row is removed, update all dropdowns (the removed row's dropdown option will be re-enabled
//in remaining dropdowns
$('#q5').on('DOMNodeRemoved', '.kx-repeatable > tr', function() {
updateSelectedList();
disableAlreadySelected();
hideAddButtonIfDone();
});
});
Paste that into your form's JavaScript section and:
- Change #q5 on lines 69, 73, 77, 86 and 90 to the id of your table
- Change #Field16\\(1\\) on line 33 to the id of the very first dropdown on the form (the one that's there when the form loads). You'll need to escape the parentheses using two backslashes.
That should do the trick.