Zend Forms mit Ajax versenden


Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /var/www/clients/client1/web22/web/wp-content/plugins/wp-syntax/wp-syntax.php on line 383

Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /var/www/clients/client1/web22/web/wp-content/plugins/wp-syntax/wp-syntax.php on line 383

Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /var/www/clients/client1/web22/web/wp-content/plugins/wp-syntax/wp-syntax.php on line 383

Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /var/www/clients/client1/web22/web/wp-content/plugins/wp-syntax/wp-syntax.php on line 383

Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /var/www/clients/client1/web22/web/wp-content/plugins/wp-syntax/wp-syntax.php on line 383

Im Netz gibt es ja zahlreiche Artikel zu Zend Forms und wie man diese mit Ajax validiert. Eigentlich alle Treffe via Google, die ich gefunden habe, basieren auf die selbe Lösung und exemplarisch dafür möchte ich hier nur auf eine mögliche Seite, die sich diesem Thema annimmt, verweisen: Ajaxify your Zend Form, validation with jquery.

Da eigentlich alle Seiten die gleichen Codefragmente verwendet haben und man hier noch einen ausführlichen Webcast dazu bekommt, hat mir das Tutorial bei Zendcast zu diesem Thema am besten gefallen. Der Vorteil bei dieser Art der Validierung liegt auf der Hand, das Zend Framework nimmt einem jegliche Programmierung bei der eigentlichen Validierung ab und noch wichtiger, die Validierung an sich bleibt Server-Seitig. Leider fand ich nirgends einen Hinweis darauf, wie man die Form, nach erfolgreicher Validierung dann doch abschicken kann. Viele fragten auf einschlägigen Seiten nach, oft gab es aber nur die Antwort darauf, wie man ein automatisches Submit der Form bei erfolgreicher Validierung verhindert.

Als erstes muss man ganz klassisch eine Form mit Hilfe von Zend_Form definieren.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Website_Form_Contact extends Zend_Form {
 
  public function init() {
  $this->setMethod('post');
 
  $surname = new Zend_Form_Element_Text('surname');
  $surname->setLabel('Name');
  $surname->setRequired(false);
  $surname->addFilter('StringTrim');
  $this->addElement($surname);
 
  $givenname = new Zend_Form_Element_Text('givenname');
  $givenname->setLabel('Vorname');
  $givenname->clearFilters();
  $givenname->setRequired(false);
  $givenname->addFilter('StringTrim');
  $this->addElement($givenname);
 
  $email = new Zend_Form_Element_Text('email');
  $email->setLabel('E-Mail');
  $email->setRequired(true);
  $email->addValidator('NotEmpty', false, array('messages' =>; 'Bitte geben Sie Ihre E-Mail Adresse an.'));
  $email->addFilter('StringTrim');
  $this->addElement($email);
}

Natürlich sollte hier mindestes ein Pflichtfeld vergeben sein, sonst gibt es nichts zu validieren und das Formular kann immer versendet werden. In diesem Beispiel ist es das E-Mail Feld $email->setRequired(true);. Jetzt benötigt man noch den Controller und die View, schließlich möchte man das Formular ja sehen und falls es valide ist, soll ja irgendwas mit der Eingabe geschehen.

Der Controller sieht vorerst so aus und macht erst einmal nichts weiter als das Formular anzuzeigen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class DefaultController extends Website_Controller_Action {
    public function contactAction () {
        $this->disableLayout();
 
        try {
            $request = $this->getRequest();
            $form = new Website_Form_Contact();
 
            $this->view->form = $form;
        } catch (Exception $e) {
            return $e->getMessage();
        }
    }
 
    public function validateformAction() {
        $this->_helper->viewRenderer->setNoRender();
        $this->disableLayout();
 
        $form = new Website_Form_Contact();
 
        if ($form->isValid($this->_getAllParams())) {
            if ($this->_getParam("send-mail") == "true") {
                // etwas machen, Datenbankeintrag erstellen oder E-Mail versenden.
            }
 
            $this->_helper->json(array('success' => 'true'));
        } else {
            $this->_helper->json($form->getMessages());
        }
    }
}

Die zugehörige View könnte dann zum Beispiel so aussehen:

1
2
3
4
5
6
7
8
9
10
<section class="contact-content">
    <form name="ContactForm" id="ContactForm" method="<?php echo $this->escape($this->form->getMethod()); ?>" action="<?php echo $this->escape($this->form->getAction()); ?>">
        <div>
            <?php echo $this->form->givenname . PHP_EOL; ?>
            <?php echo $this->form->surname . PHP_EOL; ?>
            <?php echo $this->form->email . PHP_EOL; ?>
            <?php echo $this->form->submit . PHP_EOL; ?>        
        </div>
    </form>
</section>

Oder einfacher (je nachdem, wie flexibel man beim Layout seien muss oder möchte):

1
2
3
<section class="contact-content">
    <?php echo $this->form . PHP_EOL; ?>
</section>

Als nächstes kommt dann noch, wie bei ZendCast vorgeführt die eigentliche Validierung via Ajax und dem Serverseitigen Mechanismus, der durch Zend Form zur Verfügung gestellt wird. Hierzu werden einige kurze Javascript Funktionen benötigt, die sich in der entsprechenden View befinden und schnell erstellt sind. Ferner werden die Pflichtfelder bereits bei der Eingabe überprüft (.blur()). Das ganze könnte dann ungefähr so aussehen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<script type="text/javascript">
    var success = false;
 
    $(function() {
        $("input").blur(function() {
            if ($(this).parent().prev().find('label').attr('class') == 'required') {
                var formElementId = ($(this).parent().prev().find('label').attr('for'));
                doValidation(formElementId);
            }
        });
        $('#ContactForm').submit(function () {
            doValidationAll();
            return false;
        });
    });
 
    function doValidationAll() {
        var url = 'validateform';
        var data = {};
 
        $("dt label").each(function () {
            data[$(this).parent().next().children().attr('name')] = $(this).parent().next().children().val();
        });
        data["send-mail"] = "true";
 
        $.post(url, data, function (resp) {
            if (resp.success) {
                // bei Erfolg dem User irgendein Feedback geben
            } else {
                for (key in resp) {
                    // Fehlermeldungen bei jedem Feld entfernen
                    $("#" + key).parent().find('.errors').remove();
 
                    if (resp[key] != null) {
                        // Fehlermeldung bei jedem nicht erfolgreich
                        // validiertem Feld hinzufügen.
                        $("#" + key).parent().append(getErrorHtml(resp[key], key));
                    }
                }
            }
        }, 'json');
    }
 
    function doValidation(id) {
        var url = 'validateform';
        var data = {};
 
        $("input").each(function () {
            data[$(this).attr('name')] = $(this).val();
        });
 
        $.post(url,data,function(resp) {
            $("#"+id).parent().find('.errors').remove();
 
            if (resp[id] != null) {
                $("#"+id).parent().append(getErrorHtml(resp[id], id));
            }
        }, 'json');
    }
 
    function getErrorHtml(formErrors, id) {
        var e = '<ul id="errors-'+id+'" class="errors">';
        for(errorKey in formErrors) {
            e += '<li style="color:#f90;">' + formErrors[errorKey] +'</li>';
        }
        e += '</ul>';
        return e;
    }
</script>

Es gibt, wie man sehen kann, zwei Funktionen für die Validierung. Zum einen, wie bei den ganzen anderen Tutorials die Funktion doValidation(). Hier wird jedes Feld direkt bei der Eingabe überprüft und sofort das entsprechende Feld mit einer Fehlermeldung markiert, bzw. diese Markierung wieder entfernt, sobald das Feld valide ist. Da man aber sicher nicht schon bei der Eingabe eines an sich validen Formulars dieses automatisch absenden möchte, da vielleicht die Felder, die nicht validiert werden, fertig ausgefüllt sind oder man seine Eingabe noch ändern möchte, habe ich eine zweite, angepasste Funktion (doValidationAll()) implementiert, die zum einen das valide Formular absendet und zum anderen alle Felder gleichzeitig beim drücken des Submit Buttons validiert und entsprechende Fehlermeldungen positioniert. Gleichzeitig ist dieser Teil auch dafür zuständig, alle Daten des validen Formulars an den Controller weiter zu reichen, um dann hier die Daten zu verarbeiten.

Man könnte das ganze sicher noch vereinfachen und vor allem bei Erfolg einen leeren JSON-String zurück geben und anschließend auf einen leeren String testen und so ein paar Zeilen sparen. Sicher könnte man auch aus zwei Controllern nur einen machen, aber das sind dann Feinheiten für das Refactoring.

Jedenfalls hat mit genau dieser Teil bei meiner Suche im Netz gefehlt. Vielleicht hilft es ja Jemandem.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert