gbegerow
gbegerow

Reputation: 133

Force valid input only with typeahead.js

I have some textboxes with twitters typeahead.js (not the old bootstrap typeahead) for autocompleting business data from custom REST servcies. How can I force the textboxes to either have a valid selection or no text at all? I want to validate the form before submission but I have no access on the dataset typeahead got from the server.

I tried to hook into the closed event but it seems there is no access to the dataset to validate. In the moment I see only 2 possible solutions:

  1. Hook into selected and autocompleted event and store the last valid value in an additional hidden textbox and validate the texbox against those value.

  2. Or validate the input against the server with additional rest calls (which I try to prevent)

Anyone a better solution?

Upvotes: 1

Views: 5774

Answers (3)

Marco
Marco

Reputation: 3641

Stumbled over it while looking for the an solution... with newer typeahead use it that way:

$('#professionsTypeahead').typeahead(null, {
    name: 'professions',
    displayKey: 'name',
    source: engine.ttAdapter()
}).blur(function(){
    match = false
    for (var i = Object.keys(engine.index.datums).length - 1; i >= 0; i--) {
       obj = jQuery.parseJSON(Object.keys(endine.index.datums)[i]);
       if($(this).val() == obj.name){
            match = true;
        }
    }; 
    if(!match){
        alert("Invalid Selection")
    }  
});

Upvotes: 0

Martin Currah
Martin Currah

Reputation: 517

I found this post whilst searching for something similar myself. I am trying to make sure a user has a valid selection based on the auto complete data provided which typeahead prefetches. Here is my code. It works for browser validating.

var engine = new Bloodhound({
    datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    limit: 10,
    prefetch: {
        url: '/data/professions.json',
        filter: function(list) {
            return $.map(list, function(professions) { return { name: professions }; });
        }
    }
});

// kicks off the loading/processing of `local` and `prefetch`
engine.initialize();

$('#professionsTypeahead').typeahead(null, {
    name: 'professions',
    displayKey: 'name',
    source: engine.ttAdapter()
}).blur(function(){
    match = false
    for (var i = engine.index.datums.length - 1; i >= 0; i--) {
        if($(this).val() == engine.index.datums[i].name){
            match = true;
        }
    }; 
    if(!match){
        alert("Invalid Selection")
    }  
});

On the .blur function you can check against the dataset to see if there is a match, if not you could handle it however you pleased. such as clearing the text box etc

Upvotes: 2

gbegerow
gbegerow

Reputation: 133

Got it to work with a derivate of the first solution. Not bulletproofed but works ok. Alternatives are welcome.

See this jsfiddle for a sample: http://jsfiddle.net/gbegerow/HAw5V/7/

window.gbegerow.validValues = window.gbegerow.validValues || {};

function updateValues(el, item) {
   window.gbegerow.validValues[el.currentTarget.id] = item.value;
}

$('#inputCountries').typeahead({
    name: 'countries',
    local: ['Belgium', 'France', 'Germany','United Kingdom', 'United States']
}) .on('typeahead:selected', function(el, item) {
    updateValues(el, item);
})
.on('typeahead:autocompleted', function(el, item) {
    updateValues(el, item);
});

$('#validate').click(function(){
    for( id in window.gbegerow.validValues ) {
        var val =  window.gbegerow.validValues[id];
        var current = $('#'+id).val();
        var valid = val === current;

        if (!valid) { alert('invalid input: '+ id); }
    }
});

with this html:

<input id="inputCountries" type="text" placeholder="Countries" />
<button id="validate">Validate</button>

Upvotes: 1

Related Questions