[Frage] Fluid-Formular - per Ajax versendet - kann in der Action nicht gespeichert werden

  • 0 x
    10 Beiträge
    0 Hilfreiche Beiträge
    28. 01. 2014, 16:11

    Hallo Leute, ich brauche dringend Hilfe.
    Bin schon seit 2 zwei Tagen nach einer Lösung am suchen. Hab schon Kopfschmerzen :/

    Ich schreibe ein Verwaltungstool, das unter Anderem Firmendaten verwalten soll.
    Es soll alles per AJAX erledigt werden.

    im Template habe ich zunächst nur Buttons, die per viewhelper generiert wurden (nicht AJAX).
    Wenn mann auf einen der Buttons klickt, wird das erste mal ein AJAX-Call ausgeführt. Hier wird dann anhand des Button-Values die entsprechende Action im AjaxController angesteuert, die dann was passendes zurück gibt. So weit so gut.

    [b]Hier schonmal die AJAX-Geschichte:[/b]

    1. var ajaxRequestUrl = "{f:uri.page(pageType:settings.ajaxPageType)}";
    2. var requestParameter = {
    3. tx_crm_ajax : {
    4. controller : 'Ajax',
    5. company_id : "{company.uid}", // hier steht die UID der Firma, zuvor an FLUID weitergegeben
    6. location : location.href
    7. }
    8. };

    die Action wird dynamisch anhand des Button-Values festgelegt (requestParameter.tx_crm_ajax.action = ...)

    1. function getData(){
    2. $.post(
    3. ajaxRequestUrl,
    4. requestParameter,
    5. function (jsonData) {
    6. currentObject = jsonData.object;
    7. $('.formContent').empty().append(jsonData.html);
    8. },
    9. "json");
    10. }

    Eine der Actions greift auf ein Repository zu und bekommt Firmendaten zurück. Diese werden dann im JSON-Format an die AJAX-Funktion (im Template) weitergereicht, wo die Daten dann aufgebaut werden. Funktioniert auch.
    Dann kann der Benutzer auf einen Edit-Button klicken, um den Datensatz zu bearbeiten. Es wird ein Formular generiert in dem in einen gegebenen f:form Rahmen per JS die nötigen Eingabefelder hineingeladen werden.
    1. <f:form class="form" action="" controller="Ajax" enctype="multipart/form-data">
    2. <div class="formContent"></div>
    3. </f:form>

    Wenn ich jetzt das Formular abschicke, kommt es zwar in der Action an, dort bekomme ich dann aber weder ein Objekt vom Reopsitory, noch kann ich mit eigenen Methoden die Daten aus dem Formular speichern.

    1. public function saveStammdatenAction() {
    2.  
    3. // hier kommen anscheinend alle Daten an
    4. $requestArguments = $this->request->getArguments();
    5.  
    6. // da die Formularinhalte sonst ein String sind
    7. parse_str($requestArguments['form'], $form);
    8.  
    9. // Eigene Repository-Methode (nur ein Versuch aus Verzweiflung -.-)
    10. $this->companyRepository->updateCompany(1, $form['name'], $form['supplement'], $form['legalform']);
    11.  
    12.  
    13. /* hier ist das Problem! Ich bekomme ein leeres Objekt
    14. $company = $this->companyRepository->findOneByUid($form['uid']);
    15.  
    16. $company->setName($_POST['name']);
    17. $company->setLegalform($_POST['legalform']);
    18. $company->setDate($_POST['date']);
    19. $company->setSupplement($_POST['supplement']);
    20.  
    21. $this->companyRepository->update($company);
    22.  
    23.   return json_encode($company);
    24. */
    25.  
    26. return json_encode($requestArguments);
    27.  
    28. }

    Der AJAX-Aufruf dafür sieht folgendermaßen aus:
    1. function setData(action){
    2. requestParameter.tx_crm_ajax.form = $('.form').serialize();
    3.  
    4. $.post(
    5. ajaxRequestUrl,
    6. requestParameter,
    7. function (jsonData) {
    8. console.log(jsonData)
    9. },
    10. "json");
    11. }

    Ich hab das Forum abgesucht. und auch die Google Links sind alle lila. Ich hoffe sehr, dass einer von euch mir weiterhelfen kann.

  • Hilfreichster Beitrag

  • freshman17 freshman1...
    Sternenflotten-Admiral
    1 x
    218 Beiträge
    2 Hilfreiche Beiträge
    29. 01. 2014, 13:25 - Hilfreichster Beitrag

    Arbeite doch direkt mit Objekten und nicht mit einzelnen Argumenten. Beispiel:

    User will Daten ändern, also gib im die Company als Formular zurück (Template -> Company.html). In diesem bindest du das Objekt

    1. <f:form id="myform" action="saveStammdaten" name="compay" object="{compay}" additionalParams="{type: 1234}">
    2. <f:form.textfield property="foo"/>
    3. </f:form>

    Beim Click auf edit

    1. var form = $('#myform');
    2. $.ajax({
    3. url: $(form).attr('action'),
    4. data: $(form).serialize(),
    5. // z.b. datatype: "json",
    6. type: "POST",
    7. success: function(data) {
    8. // was auch immer
    9. }
    10. });

    in deinem Controller

    1. public function saveStammdatenAction(\MYVENDOR\WvMyExt\Domain\Model\Company $company) {
    2. // wird nicht mehr benötigt
    3. // $requestArguments = $this->request->getArguments();
    4. }

    Sollte deine TYPO3 >= 6.0 sein und es kommt ein Fehler wegen "Registrierung von Argumenten o.ä" dann einfach in der setup.txt den rewrittenPropertyMapper = 0 explizit deaktivieren


  • freshman17 freshman1...
    Sternenflotten-Admiral
    1 x
    218 Beiträge
    2 Hilfreiche Beiträge
    29. 01. 2014, 13:25

    Arbeite doch direkt mit Objekten und nicht mit einzelnen Argumenten. Beispiel:

    User will Daten ändern, also gib im die Company als Formular zurück (Template -> Company.html). In diesem bindest du das Objekt

    1. <f:form id="myform" action="saveStammdaten" name="compay" object="{compay}" additionalParams="{type: 1234}">
    2. <f:form.textfield property="foo"/>
    3. </f:form>

    Beim Click auf edit

    1. var form = $('#myform');
    2. $.ajax({
    3. url: $(form).attr('action'),
    4. data: $(form).serialize(),
    5. // z.b. datatype: "json",
    6. type: "POST",
    7. success: function(data) {
    8. // was auch immer
    9. }
    10. });

    in deinem Controller

    1. public function saveStammdatenAction(\MYVENDOR\WvMyExt\Domain\Model\Company $company) {
    2. // wird nicht mehr benötigt
    3. // $requestArguments = $this->request->getArguments();
    4. }

    Sollte deine TYPO3 >= 6.0 sein und es kommt ein Fehler wegen "Registrierung von Argumenten o.ä" dann einfach in der setup.txt den rewrittenPropertyMapper = 0 explizit deaktivieren

  • 0 x
    10 Beiträge
    0 Hilfreiche Beiträge
    29. 01. 2014, 19:54

    vielen Dank für die rasche Reaktion. Sobald ich morgen im Büro bin, werde ich es so mal ausprobieren.
    Aber ist es nicht so, dass um Übergabewerte an die Action zu übergeben, das Formular ganz regulär abschicken müsste?
    So wie ich das sehe, versendet dein Ajax-Request, sowie meiner einfach nur die Formularinhalte per POST?
    Jedenfalls danke schonmal. Ich werde morgen mal den Stand der dinge posten.

  • freshman17 freshman1...
    Sternenflotten-Admiral
    0 x
    218 Beiträge
    2 Hilfreiche Beiträge
    30. 01. 2014, 00:19

    In dem Beispiel wird doch das ganze Formular verschickt, sprich wie gehabt (deswegen benötigt man auch keine @dontverifyrequesthash Annotation in der Action). Das einzige was oben nicht beschrieben ist, ist der pagetype für AJAX (<f:form ... additionalParams="{type: 1234}">...), denke aber denn hast du sowieso schon definiert.

    Aber ist es nicht so, dass um Übergabewerte an die Action zu übergeben, das Formular ganz regulär abschicken müsste?

    Nein, Parameter kannst du immer an eine Action übergeben. Hier ein Beispiel mit GET:

    1. /**
    2. * Foo action
    3. *
    4. * @param string $data
    5. * @return void
    6. */
    7. public function fooAction( $data = NULL ) {
    8. if ($data !== NULL) {}
    9. }

    Aufrufe:
    example.com/mypage/controller/action/foo (mit RealUrl optiemiert)
    example.com/mypage/?tx_foo[action]=bar&tx_foo[controller]=baz&tx_foo[data]=foo

    Das selbe funktioniert mit AJAX, nur den type definieren und anhängen.
    example.com/mypage/?type=1234&tx_foo[action]=bar&tx_foo[controller]=baz&tx_foo[data]=foo

  • 0 x
    10 Beiträge
    0 Hilfreiche Beiträge
    30. 01. 2014, 10:01

    Leider hat das nicht funktioniert.
    Die Exception in der Antwort lautet:
    "PHP Catchable Fatal Error: Argument 1 passed to Van\Crm\Controller\AjaxController::saveStammdatenAction() must be an instance of Van\Crm\Domain\Model\Company, none given in .../AjaxController.php line 53"

    Die Action sieht folgendermaßen aus:

    1. /**
    2.  * action saveStammdaten
    3.  *
    4.  * @param \Van\Crm\Domain\Model\Company $company
    5.  * @return \string JSON
    6.  */
    7. public function saveStammdatenAction(\Van\Crm\Domain\Model\Company $company) {

    Außerdem müssen auf dieser einen Oberfläche die unterschiedlichsten Objekte verwaltet werden. Da muss es doch eine Möglichkeit geben die ganzen Formulare und deren Objekte nicht Hardgecoded in das Template schreiben zu müssen.
    Deswegen habe ich einen "Formular-Rahmen" mit den minimalsten Parametern im Template, der Rest soll dann Dynamisch anhand des geklickten Buttons ergänzt werden.

  • freshman17 freshman1...
    Sternenflotten-Admiral
    0 x
    218 Beiträge
    2 Hilfreiche Beiträge
    30. 01. 2014, 10:13

    Also das da keine Instanz übergeben wird könnte am folgendem liegen:

    die Action die das Formular erstellt muß sowas haben:

    1. $this->view->assign('company', $this->companyRepository->findByUid($uid));

    und dann das Object an das Formual binden
    1. <f:form method="post" action="saveStammdaten" name="company" object="{company}"></f:form>

  • 0 x
    10 Beiträge
    0 Hilfreiche Beiträge
    30. 01. 2014, 10:27

    im CompanyController habe ich eine goToCompanyAction

    1. /**
    2.  * goToCompany action for this controller.
    3.  *
    4.  * @param int $uid The uid of the company.
    5.  * @return void
    6.  */
    7. public function goToCompanyAction($uid){
    8. // \TYPO3\CMS\Core\Utility\DebugUtility::debug($uid);
    9. // so war es eben (eigene Methode)
    10. // $company = $this->companyRepository->getCompany($uid);
    11.  
    12. $company = $this->companyRepository->findByUid($uid);
    13. $buttons = array(
    14. // [ajaxAction] => [buttonValue]
    15. 'ajaxStammdaten' => 'Stammdaten verwalten',
    16. 'ajaxInteresse' => 'Interesse',
    17. 'ajaxAngebot' => 'Angebot',
    18. 'ajaxReporting' => 'Reporting',
    19. 'ajaxVertrag' => 'Vertrag',
    20. 'ajaxDateien' => 'Dateien',
    21. 'ajaxRechnungsliste' => 'Rechnungsliste',
    22. );
    23.  
    24. $values = array('company' => $company, 'buttons' => $buttons);
    25. $this->view->assignMultiple($values); // ist vielleicht hier das Problem?
    26. }

    hier sieht man auch, wie die Buttons aufgebaut werden und wieviele Objekte man hier mitgeben müsste :/

    Ps. nach der Änderung wird zumindest ein Objekt statt eines Arrays im Debugger angezeigt.

    1. Van\Crm\Domain\Model\Company prototype persistent entity (uid=4, pid=0)
    2. name => 'Fantasiefirma' (13 chars)
    3. supplement => '' (0 chars)
    4. legalform => '' (0 chars)
    5. date => DateTimeprototypeobject (2013-12-10T16:25:42+01:00, 1386689142)
    6. uid => 4 (integer)
    7. _localizedUid => 4 (integer)modified
    8. _languageUid => NULL
    9. pid => 0 (integer)

    Aber die Exception ist immernoch die selbe.

  • freshman17 freshman1...
    Sternenflotten-Admiral
    0 x
    218 Beiträge
    2 Hilfreiche Beiträge
    30. 01. 2014, 10:50

    Ne, assignMultiple macht das selbe nur in einer Schleife. Ich denke, der mag paar Felder im Formular nicht. Kannst du diese auf ein Minimum reduzieren? Zum Beispiel

    1. <f:form method="post" action="saveStammdaten" name="company" object="{company}">
    2. <f:form.textfield property="name" />
    3. <f:form.submit name="mySubmit" value="Submit" />
    4. </f:form>

    Zum debuggen würde ich das ganze ohne AJAX testen.

    PS: welche TYPO3 Version, rewrittenPropertyMapper an oder aus?

  • 0 x
    10 Beiträge
    0 Hilfreiche Beiträge
    30. 01. 2014, 11:17

    Ich habe mal alle Felder rausgenommen, keine Änderung.
    Ohne Ajax läuft alles.

    T3 ist 6.1.6
    rewrittenPropertyMapper ist aus

  • 0 x
    10 Beiträge
    0 Hilfreiche Beiträge
    30. 01. 2014, 11:30

    Ich habe mal das Template mit dem Ajax-Call auf das Nötigste reduziert:

    1. <f:layout name="detailLayout" />
    2.  
    3. <f:section name="subnavi">
    4.  
    5.  
    6. </f:section>
    7.  
    8. <f:section name="content">
    9.  
    10. <f:debug>{company}</f:debug>
    11.  
    12.  
    13. <f:form class="form" id="stammdaten" name="company" object="{company}" action="saveStammdaten" controller="Ajax" additionalParams="{type: 666}" enctype="multipart/form-data">
    14. <div class="formContent"></div>
    15. <f:form.textfield name="name" value="{company.name}" />
    16. <f:form.submit name="submit" value="speichern" />
    17. </f:form>
    18.  
    19. <!--
    20. <f:form class="form" id="stammdaten" name="company" object="{company}" action="saveStammdaten" controller="Company" enctype="multipart/form-data">
    21. <f:form.textfield name="name" value="{company.name}" />
    22. <f:form.submit name="submit" value="speichern" />
    23. </f:form>
    24. -->
    25.  
    26.  
    27.  
    28.  
    29.  
    30.  
    31.  
    32. <script type="text/javascript">
    33.  
    34.  
    35. $(document).ready(function () {
    36.  
    37. $('.form').bind('submit', function() {
    38. // var form = $(this);
    39.  
    40. var form = $('#stammdaten');
    41.  
    42. $.ajax({
    43. url: $(form).attr('action'),
    44. data: $(form).serialize(),
    45. datatype: "json",
    46. type: "POST",
    47. success: function(data) {
    48. console.log(data);
    49. }
    50. });
    51.  
    52.  
    53. return false;
    54. });
    55.  
    56.  
    57. });
    58.  
    59. </script>
    60. </f:section>

    der Firebug sagt:
    An error occurred while trying to call Van\Crm\Controller\AjaxController->saveStammdatenAction().
    Error: Required property 'company' does not exist.