2010年4月2日星期五

Re: [fw-mvc] How to deal with Zend_Form validation errors on a form called via AJAX?


My thoughts currently are:

1) Screw the ajax, force a full page refresh each time

2) Render and pass the whole form back inside the response

3) Send back a validation error listing and parse it out in the client


#2 seems easiest, but I feel strange about it for some reason.

Anyone else tackle this before?



Interesting question, which anyone who ajaxifies a form has to answer. Umpirsky gave you a good solution. My two cents is: I have been using #3:  sending back a JSON data structure that (maybe) contains a validationErrors object for the client to iterate through and display the errors. I also made a jQuery plugin for the sake of DRY. It's really primitive so I am a little embarrassed to show it, but... it's appended.

I too am using the ajaxContext/ target action json context, so on the controller side, simply

if ($form->isValid($this->getRequest()->getPost())) {
        // process
} else {
      $this->view->assign(array('validationErrors' => $form->getMessages()));
}



//////////////////////////// (crude) jQuery plugin
(function($) {

    $.fn.ajaxFormPost = function(options) {
       
        var form = $(this)[0];
       
        // we have to be a FORM element
        if (! 'FORM' == form.nodeName.toUpperCase()) {
            alert("Error: $(this)[0] has to be a FORM element.");
            return this;
        }
         
        var data = $(form).serialize()+'&format=json';
        var submitButton = $(form).find("input[type=submit]");
        var submitButtonText = submitButton.val();
       
        var xhr = $.ajax(
        {
            type       : 'POST',
            url        : $(form).attr('action'),
            data       : data,
            dataType   : 'json',
            beforeSend : function(xhr) {
                // clear any validation errors
                $(".validationError").text('');
                submitButton.val("Processing...");
            },
            success    : function (data, textStatus) {

                if (typeof(data.errorMessage) == 'string') {
                    if (typeof options.onError == 'function') {
                        return onError(data);
                    } else {

                        if ($('#errorMessage').length) {

                            return $('#errorMessage').text(data.errorMessage);
                        } else {

                            return $(form).prepend(
                                $("<div>")
                                .attr({
                                    'class' : 'validationError',
                                    id : 'errorMessage'
                                })
                                .css({
                                    backgroundColor : 'yellow',
                                    width:'50%',
                                    padding:'.5em',
                                    fontSize : '110%'
                                })
                                .text(data.errorMessage)
                                );
                        }
                    }
                }
                if (data.validationErrors) {
                    $.each(data.validationErrors, function(k,v){
                        var field = k;    var errors = v;
                        $.each(errors,function(k,message) {
                            // if the error div does not exist, create it
                            if (! $('#error_'+field).length ) {
                                $('#'+field).before(
                                    $('<div/>').attr({
                                        id : "error_"+field ,
                                        className:'validationError'
                                    }).text(message)
                                    );
                            } else {
                                $('#error_'+field).text(message);
                            }
                            return false; // once through is enough (max 1 error per form field)
                        });
                    });
                } else {
                    if (typeof options.afterSuccess == 'function') {
                        options.afterSuccess(data);
                    }
                }
            },
            // TO DO set this up as a global ajax thing? or as optional callback?
            error  : function(xhr,textStatus) {
                alert('Sorry, a "'+ textStatus  +'" error prevented us from completing your request. We have logged the event and will address it in due course.'+"\n\nIn the meantime you are encouraged to report this problem to the site administrator, describing what you were trying to do when this happened.");
            },
            complete : function(xhr,textStatus) {
                submitButton.val(submitButtonText);
            }
        }
        );
        return this;
    }
})(jQuery);


--
Support real health care reform:
http://phimg.org/

--
David Mintz
http://davidmintz.org/


没有评论: