Thursday, December 11, 2008

JQuery AutoComplete: code/diff for new option afterNoMatch

Below please find a mod for adding an option to AutoComplete.

The option is 'afterNoMatch'. It specifies a function to call if the value provided does not match any value in the dropdown box. This has been mentioned as a problem, and I needed a solution. So, here it is.

If the autocomplete cannot return a value (it's not found by the JSON lookup), the callback is called. At this point, I reset the values of a div and a hidden field holding the ID of the thing I was looking for.

This may not be perfect, but it does get the job done.

First, how to call it:

<script type="text/javascript">

var autocompleteJSON = function(raw) {
var json = typeof(raw) === "array" ? raw : raw.resultSet;
var parsed = [];
for (var i=0; i <json.length; i++) {
var row =json[i];
parsed.push({
data: row,
value: row["orgName"] + ' [' + row["id"] + ']',
result: row["orgName"]
});
}
return parsed;
};

function afterNoMatch() {
document.forms[0].mcOrgID.value = 'nomatch';
locationDiv = document.getElementById('mcOrgLocationDiv')
locationDiv.innerHTML = "<b>Manually Entered Organization Name - No location.</b>";
return;
}

function formatCompanyName(row) {
ret = row["orgName"] + " (id: " + row["id"] + ") " + row["orgCity"] + ", " + row["orgState"]
document.forms[0].mcOrgID.value = row['id'];
return ret
}

</script>

<script>
$(document).ready(function(){
var data = "Core Selectors Attributes Traversing Manipulation CSS Events Effects Ajax Utilities".split(" ");
$("#mcOrgName").autocomplete('BrowseOrgsJSON.py')
.result(function(event, data, formatted) {
//alert("Got data back from server: name=" + data['orgName'] + ", id=" + data['id'] + ", city=" + data['orgCity'] + ", state=" + data['orgState'] + ", formatted=" + formatted);
$("#mcOrgLocationDiv").html('Location: ' + data['orgCity'] + ', ' + data['orgState'] + ' (Textura Organization id: ' + data['id'] + ')' );
document.forms[0].mcOrgID.value = data['id'];
});

$("#mcOrgName").setOptions({scrollHeight : 400 });
$("#mcOrgName").setOptions({queryArgument : "search" });
$("#mcOrgName").setOptions({formatItem : formatCompanyName });
// $("#mcOrgName").setOptions({autoFill : true }); CANNOT DO THIS WITH SUBSTRING SEARCH.
$("#mcOrgName").setOptions({mustMatch : false });
$("#mcOrgName").setOptions({dataType : "json" });
$("#mcOrgName").setOptions({parse : autocompleteJSON });
$("#mcOrgName").setOptions({selectFirst : false });
$("#mcOrgName").setOptions({extraParams : {'includeOffSystem': 'False'} });
$("#mcOrgName").setOptions({afterNoMatch : afterNoMatch });
});
</script>


Now, here's the code. I'll start off with the diff and then cut/paste the section the code is in case the code changes between now and the time you're reading this.

In jquery.autocomplete.js, the function hideResultsNow() is changed to be the following:


function hideResultsNow() {
var wasVisible = select.visible();
select.hide();
clearTimeout(timeout);
stopLoading();
if (options.mustMatch) {
// call search and run callback
$input.search(
function (result){
// if no value found, clear the input box
if( !result ) {
if (options.multiple) {
var words = trimWords($input.val()).slice(0, -1);
$input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
}
else
$input.val( "" );
}
}
);
}
else
{
// call search and run callback
$input.search(
function (result){
if( !result ) {
options.afterNoMatch();
}
}
);
}

if (wasVisible)
// position cursor at end of input field
$.Autocompleter.Selection(input, input.value.length, input.value.length);

};


and one option is added to the options section:


...
max: 100,
mustMatch: false,
afterNoMatch: function() { return; },
extraParams: {},
selectFirst: true,
...


Now for the technical diff:


Index: resources/js/jquery/autocomplete/jquery.autocomplete.js
==============================================================
307a308,319
> else
> {
> // call search and run callback
> $input.search(
> function (result){
> if( !result ) {
> options.afterNoMatch();
> }
> }
> );
> }
>
310a323
>
403a417
> afterNoMatch: function() { return; },

1 comment:

Unknown said...

I've updated this code slightly. I had a need to determine which field the autocomplete failed on from within the callback function. So, I now pass a parameter to the callback function. This code changed so it is now:

options.afterNoMatch($input);

and then in the callback, you can say:

function afterNoMatch(p1)
{
var fieldid = p1[0].id;
...