Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass spring model attributes as parameters in Thymeleaf fragments

I have a simple CRUD thymeleaf based html page, where I have a list of workers and worker details. Now I want to create, edit or delete a worker. For this actions I use a twitter bootstrap modal dialog.

This works fine, but I have a lot of duplication there, so I want to create a th:fragment which contains the form fields which are the same in details view, create view and edit view. Just the spring model attribute is different.

<div th:fragment="workerForm(formId, formAction, worker)">
  <form th:id="${formId}" th:action="${formAction}" class="form-horizontal" method="post" role="form">
    <div class="form-group">
      <label for="inputGivenName" class="col-sm-2 control-label">Givenname</label>
      <div class="col-sm-10">
        <input id="inputGivenName" type="text" class="form-control" th:field="${worker.givenName}"/>
      </div>
    </div>
    <div class="form-group">
      <label for="inputName" class="col-sm-2 control-label">Name</label>
      <div class="col-sm-10">
        <input id="inputName" type="text" class="form-control" th:field="${worker.name}"/>        
      </div>
    </div>        
    <div class="form-group">
      <div class="col-sm-offset-2 col-sm-10">        
        <div class="checkbox">        
          <label>
          <input type="checkbox" th:field="${worker.active}"/> Active
          </label>
        </div>
      </div> 
    </div>                          
  </form>
</div>

Now I want to include this fragment in the modal dialog ...

<div class="modal-body">
  <div th:include="workerFragments :: workerForm(newWorkerForm, @{/worker/new}, ${newWorker})"></div>
</div>

Is it possible to pass in the model attribute newWorker as a paramter into the fragment and thymeleaf will use this instead of the ${worker}?

NewWorker is set in the spring action as:

....
model.addAttribute("newWorker", new WorkerDTO());
....

It is not possible with the above code. Here thymeleaf wants to resolve worker instead of the passed in newWorker. Should the parameter be in another format, or is it not possible for thymeleaf fragments to resolve this?

like image 938
Marc Avatar asked Apr 03 '14 09:04

Marc


People also ask

How do you pass data to Thymeleaf fragment?

There are three basic ways to include content from a fragment: insert – inserts content inside the tag. replace – replaces the current tag with the tag defining the fragment. include – this is deprecated but it may still appear in a legacy code.

How do you get the model attribute in Thymeleaf?

In Thymeleaf, these model attributes (or context variables in Thymeleaf jargon) can be accessed with the following syntax: ${attributeName} , where attributeName in our case is messages . This is a Spring EL expression.

How do I add a header and footer in Thymeleaf?

Creating a layout You can also notice, that header and footer are included using Standard Thymeleaf Layout System. Content of this task/list view will be decorated by the elements of task/layout view. Please note layout:decorate="~{task/layout}" attribute in <html> element.


2 Answers

I resolved a similar issue by passing the name of the field into the fragment instead of passing the attribute itself. So from your include, you would write something like:

<div class="modal-body">
  <div th:include="workerFragments :: workerForm(newWorkerForm, @{/worker/new}, 'newWorker')"></div>
</div>

And then with your fragment, you would have the same "worker" fragment variable, but you would have to use the preprocessor to evaluate the variable in the fragment and then you can use the form-backing syntax to use th:field. Your references in your fragment change from ${worker} to *{__${worker}__}

<div th:fragment="workerForm(formId, formAction, worker)">
  <form th:id="${formId}" th:action="${formAction}" class="form-horizontal" method="post" role="form">
    <div class="form-group">
      <label for="inputGivenName" class="col-sm-2 control-label">Givenname</label>
      <div class="col-sm-10">
        <input id="inputGivenName" type="text" class="form-control" th:field="*{__${worker}__.givenName}"/>
      </div>
    </div>
    <div class="form-group">
      <label for="inputName" class="col-sm-2 control-label">Name</label>
      <div class="col-sm-10">
        <input id="inputName" type="text" class="form-control" th:field="*{__${worker}__.name}"/>        
      </div>
    </div>        
    <div class="form-group">
      <div class="col-sm-offset-2 col-sm-10">        
        <div class="checkbox">        
          <label>
          <input type="checkbox" th:field="*{__${worker}__.active}"/> Active
          </label>
        </div>
      </div> 
    </div>                          
  </form>
</div>
like image 159
Jon Avatar answered Nov 24 '22 15:11

Jon


There is a with attribute where you can pass in parameters into your view so you're not dependent on the parent. For example,

If you are calling workerForm and you wanted to pass in a parameter called newWorker with the value of newWorkerValue, then you would do the following:

<div class="modal-body">
  <div th:include="workerFragments :: workerForm" th:with="newWorker=${newWorkerValue}"></div>
</div>

So within your workerForm template, you can reference newWorker. For additional information, check out 8.2 Parameterizable fragment signatures

like image 38
John F. Avatar answered Nov 24 '22 13:11

John F.