2017-04-11 7 views
0

Ich habe eine Elternklasse, die zweimal in der ParentForm-Backing-Klasse als Mutter und Vater instanziiert wird. Das Webformular erwartet, dass ein Vor- und Nachname für jedes Parent als NotNull validiert wird. Ich habe speziell ein Thymeleaf Fragment für die „Mutter“ Instanz, aber ich will für beide Eltern Instanzen das Fragment generic machen:Referenzobjekt, das an Thymeleaf-Fragment übergeben wurde

<div class="form-group" th:fragment="name"> 
    <div class="form-row clearfix"> 
     <div th:classappend="${#fields.hasErrors('mother.firstName') or #fields.hasErrors('mother.lastName')} ? has-error : ''"> 
      <label class="control-label col-xs-12" th:classappend="${#fields.hasErrors('mother.firstName') or #fields.hasErrors('mother.lastName')} ? has-error : ''">What is the mother's name?</label> 
     </div> 
     <div class="col-sm-11 col-sm-offset-1 col-xs-12"> 
      <div class="form-row form-group"> 
       <div th:classappend="${#fields.hasErrors('mother.firstName')} ? has-error : ''" class="col-xs-12 col-sm-6"> 
        <div class="input-group"> 
         <label th:for="mother.firstName" class="control-label">First&nbsp;</label> 
         <input type="text" th:field="*{mother.firstName}" th:value="*{mother.firstName}" class="form-control"/> 
        </div> 
       </div> 
       <div th:classappend="${#fields.hasErrors('mother.lastName')} ? has-error : ''" class="col-xs-12 col-sm-6"> 
        <div class="input-group"> 
         <label th:for="mother.lastName" class="control-label">Last&nbsp;</label> 
         <input type="text" th:field="*{mother.lastName}" th:value="*{mother.lastName}" class="form-control"/> 
        </div> 
       </div> 
      </div> 
     </div> 
    </div> 
    <div th:if="${#fields.hasErrors('mother.firstName') or #fields.hasErrors('mother.lastName')}" class="form-row clearfix has-error"> 
     <div class="help-block small"> 
      <ul> 
       <li th:each="err : ${#fields.errors('mother.firstName')}" th:text="${err}"></li> 
       <li th:each="err : ${#fields.errors('mother.lastName')}" th:text="${err}"></li> 
      </ul> 
     </div> 
    </div> 
</div> 

Die Parent-Klasse hat Vor- und den Nachnamen zusammen mit den Getter/Setter mit Standard-Namenskonvention . Das alles funktioniert wie erwartet - Validierung, Anzeige, Bindung.

Also versuche ich das Fragment generisch zu machen, indem ich die Signatur in etwas wie th: fragment = "name (parent, parentType)" ändere und die "mother" -Instanzen durch solche "parent" -Instanzen ersetze:

<div class="form-group" th:fragment="name(parent, parentType)"> 
    <div class="form-row clearfix"> 
     <div th:classappend="${#fields.hasErrors('parent.firstName') or #fields.hasErrors('parent.lastName')} ? has-error : ''"> 
      <label class="control-label col-xs-12" th:classappend="${#fields.hasErrors('parent.firstName') or #fields.hasErrors('parent.lastName')} ? has-error : ''" th:text="|What is the ${parentType}'s name?|"></label> 
     </div> 
     <div class="col-sm-11 col-sm-offset-1 col-xs-12"> 
      <div class="form-row form-group"> 
       <div th:classappend="${#fields.hasErrors('parent.firstName')} ? has-error : ''" class="col-xs-12 col-sm-6"> 
        <div class="input-group"> 
         <label th:for="parent.firstName" class="control-label">First&nbsp;</label> 
         <input type="text" th:field="*{parent.firstName}" th:value="*{parent.firstName}" class="form-control"/> 
        </div> 
       </div> 
       <div th:classappend="${#fields.hasErrors('parent.lastName')} ? has-error : ''" class="col-xs-12 col-sm-6"> 
        <div class="input-group"> 
         <label th:for="parent.lastName" class="control-label">Last&nbsp;</label> 
         <input type="text" th:field="*{parent.lastName}" th:value="*{parent.lastName}" class="form-control"/> 
        </div> 
       </div> 
      </div> 
     </div> 
    </div> 
    <div th:if="${#fields.hasErrors('parent.firstName') or #fields.hasErrors('parent.lastName')}" class="form-row clearfix has-error"> 
     <div class="help-block small"> 
      <ul> 
       <li th:each="err : ${#fields.errors('parent.firstName')}" th:text="${err}"></li> 
       <li th:each="err : ${#fields.errors('parent.lastName')}" th:text="${err}"></li> 
      </ul> 
     </div> 
    </div> 
</div> 

Wo „Eltern“ ist die Instanz des Objekts und „parent“ ist einfach der String-Wert für den Grundtyp (zB „Mutter“ oder „Vater“) für die Anzeige.

<div th:replace="fragments/survey/mother::name(*{mother}, 'mother')"></div> 

Die Fehler, die ich bekomme, wenn ich es auf diese Weise versuchen:

Caused by: org.attoparser.ParseException: Exception evaluating SpringEL expression: "#fields.hasErrors('parent.firstName') or #fields.hasErrors('parent.lastName')" (template: "fragments/survey/mother" - line 7, col 18) 
Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "#fields.hasErrors('parent.firstName') or #fields.hasErrors('parent.lastName')" (template: "fragments/survey/mother" - line 7, col 18) 

Wie kann ich das Feld in dem # fields.hasErrors() -Methode in allgemeiner Weise verweisen?

Caused by: org.springframework.beans.NotReadablePropertyException: Invalid property 'parent' of bean class [g.s.m.ParentForm]: Bean property 'parent' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter? 

Offensichtlich sind die Bean-Eigenschaften „Mutter“ genannt und „Vater“, so wie bekomme ich dieses generische Fragment zu „Mutter“ zu binden und „Vater“ und nicht als „Eltern?“

Antwort

1

Also, zuerst muss man das wie th:field und #fields.hasErrors() für Sachen realisieren, das Zeichenfolge Ergebnis des vollständigen Pfad zu dem Trägerobjekt übereinstimmen muss (und nicht auf eine lokale Variable wie parent). Sie können *{parent.firstName} nicht verwenden, da ParentForm keine getParent(). GetFirstName() hat. Um dies zu tun, müssen Sie preprocessing

verwenden Anstatt das Objekt an das Fragment übergeben, alles, was Sie brauchen, ist der Objektname. (. In Ihrem Fall, da parent bereits Mutter oder der Vater hat, werde ich sie in den Beispielen verwendet werden) Nachdem Sie diese Änderungen vorgenommen haben, Ihre Felder sollten wie folgt aussehen:

<div th:classappend="${#fields.hasErrors(parentType + '.firstName')} ? has-error : ''" class="col-xs-12 col-sm-6"> 
    <div class="input-group"> 
     <label th:for="${parentType + '.firstName'}" class="control-label">First&nbsp;</label> 
     <input type="text" th:field="*{__${parentType}__.firstName}" class="form-control"/> 
    </div> 
</div> 
<div th:classappend="${#fields.hasErrors(parentType + '.lastName')} ? has-error : ''" class="col-xs-12 col-sm-6"> 
    <div class="input-group"> 
     <label th:for="${parentType + '.lastName'}" class="control-label">Last&nbsp;</label> 
     <input type="text" th:field="*{__${parentType}__.firstName}" class="form-control"/> 
    </div> 
</div> 

Auch eine Bemerkung am Rande. .. Wenn Sie th:field verwenden, müssen Sie th:value nicht verwenden. th:field macht das für Sie.

+0

Brilliant! Vielen Dank für Ihre verständliche Erläuterung und Korrektur meines Beispielcodes. Ich war hin und her mit der '__ $ {} __' -Syntax, konnte aber die '# fields.hasErrors()' nicht herausfinden. Ich schätze auch den Tipp auf 'th: value' und' th: field' Verwendung –

Verwandte Themen