ZF-7671: Add 'background posting' functionallity to Zend_Dojo_Form

Description

This is a simple patch to allow background posting from dojo forms. Usage like this:

{{$this->postOnBackground = true; $this->postOnBackgroundOptions['successHandler'] = "console.log(data);"; }}

The patch can be found on http://dirkdokter.nl/ZF_Dojo_Form_patch1.txt

Comments

This would be better to do as a decorator, actually (and this is the approach I've taken in the past).

Such a decorator looks like this:


class My_Dojo_Decorator_FormCallback extends Zend_Form_Decorator_Abstract
{
    public function render($content)
    {
        $form = $this->getElement();
        if (!$form instanceof Zend_Dojo_Form) {
            return $content;
        }

        $successHandler = $this->getOption('successHandler');
        $errorHandler   = $this->getOption('errorHandler');

        if (empty($successHandler)) {
            return $content;
        }

        $script = $this->_renderHandler($successHandler, $errorHandler);

        $separator = $this->getSeparator();
        switch ($this->getPlacement()) {
            case 'PREPEND':
                return $script . $separator . $content;
            case 'APPEND':
            default:
                return $content . $separator . $script;
        }
    }

    protected function _renderHandler($successHandler, $errorHandler)
    {
        $args = array(
            'form'     => 'this.domNode',
            'handleAs' => 'text',
            'load'     => $successHandler,
        );
        if (!empty($errorHandler)) {
            $args['error'] = $errorHandler;
        }
        $xhrArgs = Zend_Json::encode($args);

        $content =<<
if (this.validate()) {
    dojo.xhrPost($xhrArgs);
}
return false;

EOQ;
        return $content;
    }
}

Once in place, you would attach it to your form as follows:


$form->addPrefixPath('My_Dojo_Decorator', 'My/Dojo/Decorator', 'decorator');
$form->setDecorators(array(
    'FormElements',
    array('HtmlTag', array('tag' => 'dl', 'class' => 'zend_form_dojo')),
    array('FormCallback', array(
        'successHandler' => 'formSuccess',
        'errorHandler'   => 'my.formErrors',
    ),
    'DijitForm',
));

This has the benefit of being use-at-will, as well as allowing developers to override it.

I'd be happy to add a decorator like this to the standard library; any additional functionality you can think of that it might need?

Thanks for your comments, your approach looks much better. I had a few more suggestions for the decorator:


class Zend_Dojo_AjaxForm extends Zend_Form_Decorator_Abstract
{
    private $possibleXhrArgs = array ('load','error','handle','headers','timeout','sync');
    public function render($content)
    {
        $form = $this->getElement();
        if (!$form instanceof Zend_Dojo_Form) {
            return $content;
        }

        if (!$this->getOption('load')) {   /// why is this here? Just to make sure that one always specifies a 'successHandler'?
            return $content;
        }
        
        //xhrPost will fail if no action is set, so we set it to . if it is not specified
        if (!$form->getAction()) {
            $form->setAction('.');
        } 

        $xhrPostArgs = array ( );
        // only keep valid xhrPost options
        foreach($this->getOptions() as $key => $value) {
            if (in_array($key,$this->possibleXhrArgs)) {
                $xhrPostArgs[$key] = $value;
            }
        }
        
        $script = $this->_renderHandler($xhrPostArgs);

        $separator = $this->getSeparator();
        switch ($this->getPlacement()) {
            case 'PREPEND':
                return $script . $separator . $content;
            case 'APPEND':
            default:
                return $content . $separator . $script;
        }
    }

    protected function _renderHandler($userArgs)
    {
        $standardArgs = array(
            'form'     => new Zend_Json_Expr('this.domNode'),
            'handleAs' => 'text',
        );
        
        if (is_array($userArgs))  {
            $args = array_merge($standardArgs,$userArgs);
        }
        else {
            $args = $standardArgs;
        }
        $xhrArgs = Zend_Json::encode($args,false,array('enableJsonExprFinder' => true));

        $content =<<
if (this.validate()) {
    dojo.xhrPost($xhrArgs);
}
return false;

EOQ;
        return $content;
    }
}

When users specify a function (e.g. for 'load' or for 'error'), they have to use ??Zend_Json_Expr?? to prevent the quotes around the JS functions. So setting the ??load?? function would go like this:


$form->setDecorators(array(
    'FormElements',
    array('HtmlTag', array('tag' => 'dl', 'class' => 'zend_form_dojo')),
    array('AjaxForm', array(
        'load' => new Zend_Json_Expr('alert("form submitted!")')
    )),
    'DijitForm'
));

Bulk change of all issues last updated before 1st January 2010 as "Won't Fix".

Feel free to re-open and provide a patch if you want to fix this issue.