简体   繁体   中英

Parsley.js Dynamic messages in custom validator

I'm using a custom validator to check for date of birth, so far it has almost nothing, but I'm trying to add a dynamic message depending on the error and it's not working for me it displays the container with a blank message, any ideas?

Here's the piece of code the custom validator:

window.Parsley.addValidator('age', {
            validate: function(value, id){
                switch(id){
                    case 'main':
                        var day = $('#birthdate_day').val();
                        var month = $('#birthdate_month').val();
                        var year = $('#birthdate_year').val();
                        if(!day || !month || !year){

                            window.Parsley.addMessage('en', 'age','Error1 ');

                            return false;
                        } else {
                            window.Parsley.addMessage('en', 'age','Error 2');
                        }
                    break;
                }
                return true;
            },
            messages: {
                en: 'Default error',
            }
        });

Another thing I've tried is setting the data-parsley-age-message="error" during the execution of the validation, but it only shows the error the second time the validation is ran.

Thanks in advance.

EDIT1:

 window.Parsley.addValidator('age', {
            validate: function(value, id){
                $('.birthdate_container').find('ul').remove();
                switch(id){
                    case 'main':
                        var day = $('#birthdate_day').val();
                        var month = $('#birthdate_month').val();
                        var year = $('#birthdate_year').val();
                        if(!day || !month || !year){
                            return $.Deferred().reject("One of them is blank");
                        } else if(day > 2 || month > 2 || year < 2016){
                            return $.Deferred().reject("Else test of another message");
                        } else {
                            return true;
                        }
                    break;
                }
                return true;
            },
        });

A little cleaner solution (don't mind the else, it's there just for testing) but can't still make it work becasue I don't know how I can update the classes of the 3 elements on returning true.

EDIT 2:

Just using jQuery to handle the classes work, however, since I need to remove the ul (otherwise the messages will stack and I don't want that), whenever there's an error triggered AFTER another error is in there, it simply erases it.

window.Parsley.addValidator('age', {
            validate: function(value, id){
                $('.birthdate_container').find('ul').remove();
                switch(id){
                    case 'main':
                        var day = $('#birthdate_day').val();
                        var month = $('#birthdate_month').val();
                        var year = $('#birthdate_year').val();
                        if(!day || !month || !year){
                            $('.birthdate_container').find('.parsley-success').removeClass('parsley-success').addClass('parsley-error');
                            return $.Deferred().reject("Un campo es blanco");
                        } else if(day > 2 || month > 2 || year < 2016){
                            $('.birthdate_container').find('.parsley-success').removeClass('parsley-success').addClass('parsley-error');
                            return $.Deferred().reject("dia > 2 o mes > 2 o años < 2016");
                        } else {
                            $('.birthdate_container').find('.parsley-error').removeClass('parsley-error').addClass('parsley-success');
                            return true;
                        }
                    break;
                }
                return true;
            },
        });

It's not well documented, but you can return an error message from your validator by returning a rejected promise. Check this example .

After too much tinkering with it, I think I got it, I have to reset all the previous parsley so it could rewrite the message if needed, even if it's the same one

window.Parsley.addValidator('age', {
            validate: function(value, id){
                switch(id){
                    case 'main':
                        var container = $('.birthdate_container');
                        container.find('ul').remove();
                        var day = $('#birthdate_day');
                        day.parsley().reset();
                        var month = $('#birthdate_month');
                        month.parsley().reset();
                        var year = $('#birthdate_year');
                        year.parsley().reset();

                        if(day.val() === '' || month.val() === '' || year.val() === ''){
                            container.find('.dropdown').removeClass('parsley-success').addClass('parsley-error');
                            return $.Deferred().reject("Un campo es blanco");
                        } else if(day.val() > 2 || month.val() > 2 || year.val() < 2016){
                            container.find('.dropdown').removeClass('parsley-success').addClass('parsley-error');
                            return $.Deferred().reject("dia > 2 o mes > 2 o años < 2016");
                        } else {
                            container.find('.dropdown').removeClass('parsley-error').addClass('parsley-success');
                            return true;
                        }
                    break;
                }
                return true;
            }
        });

PD: Again, the second else is just there to test that you can throw a different message; the validation itself is irrelevant.

My final work:

window.Parsley.addValidator('age', {
            validate: function(value, id, instance){
                var container = instance.$element.closest('.form-item');
                container.find('ul').remove();
                var msg = '';
                var day = container.find('select').filter(function() {return this.id.match(/\w*birthdate_day/);});
                var month = container.find('select').filter(function() {return this.id.match(/\w*birthdate_month/);});
                var year = container.find('select').filter(function() {return this.id.match(/\w*birthdate_year/);});
                day.parsley().reset();
                month.parsley().reset();
                year.parsley().reset();
                var helpContainer = '<ul class="parsley-errors-list filled"><li class="parsley-age"></li></ul>';

                if(value === ''){
                    container.find('select').parent().addClass('parsley-error');
                    msg = "This field is required";

                }
                /* Take several notes here
                1) I wrap my select in a div, for stylying purposes, so I check the default placeholder, when something is selected
                    this placeholder is changed with the value of the select (this is not shown here, it's done elsewhere)
                2) I use DD - MM - YYYY as placeholders, if any of these place holders are already showing in the div,
                    then I don't validate them because they are still 'clean'
                3) If the user clicks the submit button though, I set a js variable with this action and then validate the value anyways
                    because I don't allow blank dates, however, I can't use the parsley-required feature as it messes up my validation
                */
                else if(obj.action !== 'submit' && (day.parent().attr('data-placeholder') === 'DD' ||
                    month.parent().attr('data-placeholder') === 'MM' ||
                    year.parent().attr('data-placeholder') === 'YYYY'))
                {
                    container.find('select').parent().removeClass('parsley-error')
                    container.find('select').filter(function(){ return this.value}).parent().addClass('parsley-success');
                    return true;
                }
                else if(day.val() === '' || month.val() === '' || year.val() === '') {
                    container.find('select').parent().addClass('parsley-error');
                    msg = "This field is required";
                }
                /*
                I have another validation process past this point that uses a different error, but I'll point out the very basic
                which is just make some other validation and fill the message you want to display.

                Let's assume you want the person not to be underage and you control that in your form somehow
                */
                else if (!underageAllowed){
                    var bdate =  String("00" + day.val()).slice(-2) + "/" + String("00" + month.val()).slice(-2) + "/" + year.val();
                    var tdate = moment(); // Today
                    bdate = moment(bdate,'DD/MM/YYYY');
                    var age = tdate.diff(bdate, 'years');
                    if(age < 18){
                        container.find('select').parent().addClass('parsley-error');
                        msg = "Only people with over 18 years old are allower";
                    }
                }                   

                if(msg !== ''){
                    if(obj.action === 'submit'){
                        container.append(helpContainer);
                        container.find('.parsley-age').html(msg)
                    }
                    return $.Deferred().reject(msg);
                } else {
                    container.find('select').filter(function(){ return this.value}).parent().addClass('parsley-success');
                    return true;
                }
            },
        });

I then assign the validator to every field that has "birthdate_" as an id (birthdate_day, birthdate_month and birthdate_year)

    $("[id^='birthdate_']").attr('data-parsley-age','true')
            .attr('data-parsley-trigger', "change")
            .attr('data-parsley-validate-if-empty', "true");

Proper errorContainer for each of the fields

$('#main_form').parsley({
            errorsContainer: function(el){
                if(el.$element.is('[data-parsley-age]'))
                    return el.$element.closest('.form-item');
            },

And finally how I have my html layout

<div class="form-item">
<label>Date of birth</label>
<div class="dropdown" data-placeholder="DD">
    <select id="birthdate_day" name="birthdate_day">
        <option value="">-</option> //If user selects this, the validation throws error for all the fields
        //Options 1 through 31
    </select>
</div>
<div class="dropdown" data-placeholder="MM">
    <select id="birthdate_month" name="birthdate_month">
        <option value="">-</option>  //If user selects this, the validation throws error for all the fields
        //Options 1 through 12
    </select>
</div>
<div class="dropdown" data-placeholder="YYY">
    <select id="birthdate_year" name="birthdate_year">
        <option value="">-</option> //If user selects this, the validation throws error for all the fields
        //Options 1 through 12
    </select>
</div>

Hope this helps out anyone, it took me some time to come up with all this.

If you ONLY want to deal with dynamic messages, do not include a message text in your messages object, then in your validation method:

instance.addError('en', {message: 'Hello World'});

It's as simple as that. Just read the annotated source code and it will unveil a whole host of simple features.

EDIT: actually I just noticed you do need something or it throws it's own error message, so you can fix that with something like:

messages: {
    en: '...'
}

I just tested and that works fine

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM