How to deal with Zend_Form validation errors on a form called via AJAX?

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

How to deal with Zend_Form validation errors on a form called via AJAX?

Bill Chmura-2

Okay, well the subject was a tough one to come up with so here is a
better description:

I have a Zend_Form...  When you call the controller it renders the zend
form on the page and gives it to you.

You complete the zend form and JS packages it up and sends an Ajax request

The ajax request takes the data, creates the form, and validates, etc
that way and sends the data back

Which then gets the data back and makes a pretty table.

So my question is, how do I pass back the validation errors via the AJAX
response?

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?
Reply | Threaded
Open this post in threaded view
|

Re: How to deal with Zend_Form validation errors on a form called via AJAX?

umpirsky
Here is how I solved this in mz prev project

class Umpirsky_AjaxForm extends Umpirsky_Form {
/**
     * Render form and add ajax behaviour.
     *
     * @param  Zend_View_Interface $view
     * @return string
     */
    public function render(Zend_View_Interface $view = null) {
$this->getView()->jQuery()->addOnLoad(sprintf('%s("#%s").uiForm();',
   ZendX_JQuery_View_Helper_JQuery::getJQueryHandler(),
   $this->getAttrib('id')
));

return parent::render($view);
    }
}

uiForm is simple jQuery plugin

jQuery.fn.uiForm = function() {
var self = this;
this.ajaxForm({
dataType: 'json',
     success: function(response) {
     var errorContainer = self.find('.form-errors');
     var successContainer = self.find('.success-box');
     if (response.valid) {
     // Remove error
     errorContainer.remove();
     self.find('[id$="_wrapper"]').removeClass('element-error');
    
     // Add success
     if (successContainer.size() > 0) {
     successContainer.replaceWith(response.html);
     } else {
     self.prepend(response.html);    
     }
    
     // Clear fields
     self.clearForm();
     } else {
     // Remove success
     successContainer.remove();
    
     // Form errors
     if (errorContainer.size() > 0) {
     errorContainer.replaceWith(response.html);
     } else {
     self.prepend(response.html);
     }
    
     // Higlight elements
for (name in response.errors) {
if ($.isEmptyObject(response.errors[name])) {
$('#' + name + '_wrapper').removeClass('element-error');
} else {
$('#' + name + '_wrapper').addClass('element-error');
}
}    
     }
     }
});
}

project specific, but you can use it as an example.

If form is not valid

$this->view->html = $form->renderFormErrors();
$this->view->errors = $form->getErrors();

plugin uses this thigs for generating markup.

Form action is set to be handled via ajaxContext, so you can add target action json context.

Regards,
Saša Stamenković


On Fri, Apr 2, 2010 at 4:24 PM, Bill Chmura <[hidden email]> wrote:

Okay, well the subject was a tough one to come up with so here is a better description:

I have a Zend_Form...  When you call the controller it renders the zend form on the page and gives it to you.

You complete the zend form and JS packages it up and sends an Ajax request

The ajax request takes the data, creates the form, and validates, etc that way and sends the data back

Which then gets the data back and makes a pretty table.

So my question is, how do I pass back the validation errors via the AJAX response?

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?

Reply | Threaded
Open this post in threaded view
|

Re: How to deal with Zend_Form validation errors on a form called via AJAX?

David Mintz

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/


Reply | Threaded
Open this post in threaded view
|

Re: How to deal with Zend_Form validation errors on a form called via AJAX?

Ulugbek Tursumatov
In reply to this post by Bill Chmura-2
take look at the line 2106 IN Zend_Form
 /**
     * Process submitted AJAX data
     *
     * Checks if provided $data is valid, via {@link isValidPartial()}. If so,
     * it returns JSON-encoded boolean true. If not, it returns JSON-encoded
     * error messages (as returned by {@link getMessages()}).
     *
     * @param  array $data
     * @return string JSON-encoded boolean true or error messages
     */
    public function processAjax(array $data)
    {
        require_once 'Zend/Json.php';
        if ($this->isValidPartial($data)) {
            return Zend_Json::encode(true);
        }
        $messages = $this->getMessages();
        return Zend_Json::encode($messages);
    }

On Fri, Apr 2, 2010 at 8:09 PM, Bill Chmura <[hidden email]> wrote:

>
> Okay, well the subject was a tough one to come up with so here is a better
> description:
>
> I have a Zend_Form...  When you call the controller it renders the zend form
> on the page and gives it to you.
>
> You complete the zend form and JS packages it up and sends an Ajax request
>
> The ajax request takes the data, creates the form, and validates, etc that
> way and sends the data back
>
> Which then gets the data back and makes a pretty table.
>
> So my question is, how do I pass back the validation errors via the AJAX
> response?
>
> 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?
>
>