FormValidation v0.8.1 is released, supports Bootstrap 4 alpha 3

promise validator

Use jQuery's Deferred to validate field's value

Validators

This validator is available from v0.6.2.

Options

* — Required option

Option HTML attribute Type Description
message data-fv-promise-message String The error message. The dynamic message is supported
promise* data-fv-promise-promise String|Function The callback returns promise instance
When setting options via HTML attributes, remember to enable the validator by setting data-fv-promise="true".
The message option can be updated on the fly via the updateMessage() method

The promise option must be a function or the name of function which has the following syntax:

function(value, validator, $field) {
    // value is the value of field
    // validator is the instance of plugin
    // $field is the field element

    var dfd = new $.Deferred();

    // Do something ...

    // Resolve when particular task is done
    dfd.resolve({
        valid: true, // or false,   // Required
        message: 'Other message',   // Optional
        key: value                  // You can attach more data to reuse later
    });

    // You can reject if there's error
    dfd.reject({
        message: 'Other message',   // Optional
        key: value                  // You can attach more data to reuse later
    });

    return dfd.promise();
}

The validator is ignored if it resolves { valid: null }

dfd.resolve({ valid: null });

If the validation process takes time, it's recommended to use the tips introduced in the Getting notified while field is being validated example to improve the user experience of the application.

Look at this example if you want to attach more data to the returned value and reuse them later

Example

The following form asks user to upload an avatar which both width and height must be less than 300px.

Use the file validator if you want to validate size of an image

They can be determined using Deferred as seen in the following snippet:

var dfd = new $.Deferred(),
    img = new Image();

img.onload = function() {
    // Get the width and height after the image is loaded completely
    var w = this.width,
        h = this.height;

    dfd.resolve({
        valid: (w <= 300 && h <= 300),
        message: 'The avatar width and height must be less than 300 px',
        source: img.src,    // We will use it later to show the preview
        width: w,
        height: h
    });
};

img.onerror = function() {
    // Called when the image isn't loaded successfully
    // For example, the user doesn't choose an image
    dfd.reject({
        message: 'Please choose an image'
    });
};
<style type="text/css">
.preview {
    display: none;
    width: 200px;
    height: 200px;
    border: 1px solid #d5d5d5;
    margin-top: 10px;
}
.preview img {
    max-width: 100%;
    height: auto;
}
</style>

<form id="profileForm" class="form-horizontal">
    <div class="form-group">
        <label class="col-xs-3 control-label">Avatar</label>
        <div class="col-xs-6">
            <input type="file" name="avatar" />

            <div id="avatarPreview" class="preview"></div>
        </div>
    </div>

    <div class="form-group">
        <div class="col-xs-9 col-xs-offset-3">
            <button type="submit" class="btn btn-primary">Submit</button>
        </div>
    </div>
</form>

<script>
$(document).ready(function() {
    $('#profileForm')
        .formValidation({
            framework: 'bootstrap',
            icon: {
                valid: 'glyphicon glyphicon-ok',
                invalid: 'glyphicon glyphicon-remove',
                validating: 'glyphicon glyphicon-refresh'
            },
            fields: {
                avatar: {
                    validators: {
                        notEmpty: {
                            message: 'The avatar is required and can\'t be empty'
                        },
                        promise: {
                            promise: function(value, validator, $field) {
                                var dfd   = new $.Deferred(),
                                    files = $field.get(0).files;

                                if (!files.length || typeof FileReader === 'undefined') {
                                    dfd.resolve({ valid: true });
                                    return dfd.promise();
                                }

                                var img = new Image();
                                img.onload = function() {
                                    var w = this.width,
                                        h = this.height;

                                    dfd.resolve({
                                        valid: (w <= 300 && h <= 300),
                                        message: 'The avatar width and height must be less than 300 px',
                                        source: img.src,    // We will use it later to show the preview
                                        width: w,
                                        height: h
                                    });
                                };
                                img.onerror = function() {
                                    dfd.reject({
                                        message: 'Please choose an image'
                                    });
                                };

                                var reader = new FileReader();
                                reader.readAsDataURL(files[0]);
                                reader.onloadend = function(e) {
                                    img.src = e.target.result;
                                };

                                return dfd.promise();
                            }
                        }
                    }
                }
            }
        })
        .on('err.validator.fv', function(e, data) {
            if (data.field === 'avatar' && data.validator === 'promise') {
                // Hide the preview
                $('#avatarPreview').html('').hide();
            }
        })
        .on('success.validator.fv', function(e, data) {
            if (data.field === 'avatar' && data.validator === 'promise' && data.result.source) {
                $('#avatarPreview')
                    .html('')
                    .append($('<img/>').attr('src', data.result.source))
                    .show();
            }
        });
});
</script>
<style type="text/css">
.preview {
    display: none;
    width: 200px;
    height: 200px;
    border: 1px solid #d5d5d5;
    margin-top: 10px;
}
.preview img {
    max-width: 100%;
    height: auto;
}
</style>

<form id="profileForm" class="form-horizontal"
    data-fv-framework="bootstrap"
    data-fv-icon-valid="glyphicon glyphicon-ok"
    data-fv-icon-invalid="glyphicon glyphicon-remove"
    data-fv-icon-validating="glyphicon glyphicon-refresh">

    <div class="form-group">
        <label class="col-xs-3 control-label">Avatar</label>
        <div class="col-xs-6">
            <input type="file" name="avatar"
                data-fv-promise="true"
                data-fv-promise-promise="validateImageSize" />

            <div id="avatarPreview" class="preview"></div>
        </div>
    </div>

    <div class="form-group">
        <div class="col-xs-9 col-xs-offset-3">
            <button type="submit" class="btn btn-primary">Submit</button>
        </div>
    </div>
</form>

<script>
function validateImageSize(value, validator, $field) {
    var dfd   = new $.Deferred(),
        files = $field.get(0).files;

    if (!files.length || typeof FileReader === 'undefined') {
        dfd.resolve({ valid: true });
        return dfd.promise();
    }

    var img = new Image();
    img.onload = function() {
        var w = this.width,
            h = this.height;

        dfd.resolve({
            valid: (w <= 300 && h <= 300),
            message: 'The avatar width and height must be less than 300 px',
            source: img.src,    // We will use it later to show the preview
            width: w,
            height: h
        });
    };
    img.onerror = function() {
        dfd.reject({
            message: 'Please choose an image'
        });
    };

    var reader = new FileReader();
    reader.readAsDataURL(files[0]);
    reader.onloadend = function(e) {
        img.src = e.target.result;
    };

    return dfd.promise();
}

$(document).ready(function() {
    $('#profileForm')
        .formValidation()
        .on('err.validator.fv', function(e, data) {
            if (data.field === 'avatar' && data.validator === 'promise') {
                // Hide the preview
                $('#avatarPreview').html('').hide();
            }
        })
        .on('success.validator.fv', function(e, data) {
            if (data.field === 'avatar' && data.validator === 'promise' && data.result.source) {
                $('#avatarPreview')
                    .html('')
                    .append($('<img/>').attr('src', data.result.source))
                    .show();
            }
        });
});
</script>

Related validators

The following validators might be useful to you: