Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Twitter Bootstrap typeahead and jQuery Validate

I would like to have validation on a text input field with Twitter Bootstrap typeahead. So I tried implementing it as follows. The validation on the name field works correctly. If you start typing in it and clear the field again, validation kicks in. On the location field however, which has data-provide="typeahead" on it, this does not happen. Validation does kick in when you click the submit button however.

I tried debugging it, but as far as I can see both Bootstrap and jQuery Validate register their event handlers correctly. Even stranger, the typeahead is installed before validate. So one would expect typeahead to be broken. But it isn't...

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.1.0/css/bootstrap-combined.min.css" />
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js"></script>
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.10.0/jquery.validate.js"></script>
<script type="text/javascript" src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.1.0/js/bootstrap.js"></script>
<script type="text/javascript">
$(function() {
    $('[data-provide="typeahead"]').each(function() {
        var url = $(this).attr('data-url');
        $(this).typeahead({
            source : function(query, process) {
                return $.get(url, {
                    name : query
                }, function(data) {
                    var json = JSON.parse(data);
                    return process(json.locations);
                });
            },
            items : 5
        });
    });
    $('#settings-form').validate({
        rules: {
            name: {
                required: true
            },
            location: {
                required: true
            }
        },
        highlight: function(label) {
            var controlGroup = $(label).closest('.control-group');
            controlGroup.addClass('error');
            var buttons = controlGroup.find('button');
            buttons.addClass('btn-danger');
            buttons.attr('disabled', 'disabled');
        },
        success: function(label) {
            var controlGroup = $(label).closest('.control-group');
            controlGroup.removeClass('error');
            var buttons = controlGroup.find('button');
            buttons.removeClass('btn-danger');
            buttons.removeAttr('disabled');
        },
        errorPlacement: function(error, element) {
            error.appendTo(element.closest('.control-group'));
        }
    });
});
</script>
<style type="text/css">
body {
    margin: 20px;
}
label.error {
    margin-left: 160px;
    margin-bottom: 0;
}
</style>
</head>
<body>
    <form id="settings-form" class="form-horizontal" action="#" method="GET">
        <fieldset>
            <div class="control-group">
                <label class="control-label" for="name">Name</label>
                <div class="controls">
                    <input type="text" id="name" name="name" autocomplete="off" />
                </div>
            </div>
            <div class="control-group">
                <label class="control-label" for="location">Location</label>
                <div class="controls">
                    <input type="text" id="location" name="location" autocomplete="off" data-provide="typeahead" data-url="locations.json" />
                </div>
            </div>
        </fieldset>
        <div class="control-group">
            <div class="controls">
                <button class="btn" data-dismiss="modal">Cancel</button>
                <button class="btn btn-primary" type="submit">Save changes</button>
            </div>
        </div>
    </form>
</body>
</html>

locations.json:

{
    "locations": [
        "Berlin",
        "London",
        "Madrid",
        "New York",
        "Paris"
    ]
}
like image 767
Stijn Van Bael Avatar asked Oct 25 '12 14:10

Stijn Van Bael


1 Answers

Yes - it is because Twitter Bootstrap Typeahead hides events from the validator by e.stopPropagation() in function Typeahead.prototype.keyup()

Add a keyup-handler to #location to invoke validation "manually", for it to work:

<input type="text" id="location" name="location" autocomplete="off" 
 data-provide="typeahead" onkeyup="$(this).validate();" data-url="locations.json" />

It doesnt change the behaviour / validation settings, simply just ensuring validation is called at all..

like image 149
davidkonrad Avatar answered Oct 29 '22 15:10

davidkonrad