Form and input entity binding

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Form and input entity binding

migueldeblas
I have two entities:

@Entity
class Item {
  @Id
  private Long id;

  private String name;

  @ManyToOne()
  @JoinColumn()
  private Storage storage;
};

@Entity
class Storage {
   @Id
   private Long id;

   private String name;
};

I have a formatter for each class, I put the StorageFormatter pseudocode:
class BFormatter<T extends Storage> implements Formatter<T>{
   T parse(String id) --> return service.getById((Long) id);
   String print(T obj) --> return obj.getName();
}

I have a form for Item class where a <input> must appear (I have seen many examples of <select> but it must be an input) where the related object of Storage class is shown if it exists or empty if not.

<form th:object="${item}" action=....>
<input th:field="¿¿*{storage.name}???" th:value="¿¿¿*{storage.id}???" onclick="....." /> <--- PROBLEM
</form>

This does not work. It fails with a binding error when saving the form. Because the parse function of the formatter does not get the id, get the name.
In the case of select/option you can specify the value="id" and the text="name" but in <input> I don't see that you can.

This form is used to show the detail of the Item object, in that form there is a "edit" button that shows the same form to edit the object. In this case, if we want to change the storage field of the Item object we click on the input and a modal/window should appear where you can search and select an object (there are many) from the list of Storage objects.

Thank you
Reply | Threaded
Open this post in threaded view
|

Re: Form and input entity binding

Reiju
This is approximate solution!!!

1. Controller (u can obtain storages list with js and ajax requests. I used the easiest way - pass list as attribute):
@GetMapping("/addItem")
public String addItemForm(Model model) {
        Item item = new Item();
        item.setStorage(new Storage());
        model.addAttribute("item", item);
        model.addAttribute("storageList", storageService.findAll());
        return "itemFormPage";
}

@PostMapping("/addItem")
public String addItem(@ModelAttribute("item") Item item) {
        //some logic...
        return "resultPage";
}

2. Item form (u need no formatters or converters - save id in hidden field)
<form th:object="${item}" th:action="${'/addItem'}" method="post">
    <div class="form-group">
        <label for="itemName">Name</label>
        <input id="itemName" th:field="*{name}" type="text"/>
    </div>

    <input id="storageId" th:field="*{storage.id}" type="hidden"/>
    <div class="form-group">
        <label for="storageName">StorageName</label>
        <input id="storageName" th:field="*{storage.name}" type="text"/>
    </div>

    <button type="submit">Submit</button>
</form>

3. Modal (i used bootstrap)
<div class="modal fade" id="modal" tabindex="-1" role="dialog" aria-hidden="true">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-body">
                <table class="table table-hover">
                    <thead>
                        <tr>
                            <th>ID</th>
                            <th>NAME</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr th:each="s : ${storageList}" class="storage" th:attr="data-s-id=${s.id}, data-s-name=${s.name}">
                            <td th:text="${s.id}"></td>
                            <td th:text="${s.name}"></td>
                        </tr>
                    </tbody>
                </table>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
            </div>
        </div>
    </div>
</div>

4. JS
<script>
    $(document).ready(function () {
        $('#storageName').on('focus', function () {
            $('#modal').modal('show');
        });

        $('.storage').on('click', function () {
            let id = $(this).attr('data-s-id');
            let name = $(this).attr('data-s-name');

            $('#storageId').val(id);
            $('#storageName').val(name);
        });
    });
</script>