I have a form where the user can add as much as he want of Table object that also can contains as much as he want of Columns object (like building tables in SQL).. I've tried the code bellow but nothing works and the form dosnt appear anymore when I've tried to bind the two lists.
Controller
@ModelAttribute("page")
public Page getTable() {
TableColumn column = new TableColumn();
List<TableColumn> columns = new ArrayList<>();
columns.add(column);
Table table = new Table();
table.setColumns(columns);
List<Table> tables = new ArrayList<>();
tables.add(table);
Page page = new Page();
page.setTables(tables);
return page;
}
@GetMapping("/scriptsqlgenerator")
public String viewForm(@ModelAttribute("page") Page page) {
return "ScriptSqlNext";
}
@PostMapping("/scriptsqlgenerator")
public String generateScript(@ModelAttribute("page") Page page) {
page.tables.forEach((t) ->{
System.out.println(t.getName());
t.getColumns().forEach((c) -> {
System.out.println(c.getName());
System.out.println(c.getType());
System.out.println(c.getIndex());
System.out.println(c.getNotnull());
});
});
}
HTML
<form th:object="${page}" class="list-group" th:action="@{/filegenerated}" method="get">
<a class="list-group-item list-group-item-action" data-toggle="collapse" data-target="#target1"> Create Table </a>
<div id="target1" class="collapse" style="margin: 30px;">
<div id="tablelist">
<div class="form-inline itemtable" th:each="table, itemStat :${page.tables}">
<div class="form-group mb-2 d-none">
<input th:field="*{tables[__${itemStat.index}__].id}" type="text" class="form-control">
</div>
<div class="form-group mb-2">
<input th:field="*{tables[__${itemStat.index}__].name}" type="text" class="form-control" placeholder="Table name">
</div>
<input type="button" class="btn btn-danger mb-2 ml-2" onclick="addRow()" value="Add column">
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th scope="col" class="d-none">Id</th>
<th scope="col">Column Name</th>
<th scope="col">Type</th>
<th scope="col">Index</th>
<th scope="col">Null</th>
</tr>
</thead>
<tbody id="columnlist">
<tr class="item" th:each="column,status :
${table.columns}">
<td><input th:field="*{tables[__${itemStat.index}__].columns[__${status.index}__].name}" type="text" class="form-control" required></td>
<td><select th:field="*{tables[__${itemStat.index}__].columns[__${status.index}__].type}" id="inputState" class="form-control" required>
<option value="" selected
disabled>Choose</option>
<option th:value="${type}">int</option>
<option th:value="${type}">varchar</option>
</select>
</td>
<td><select th:field="*{tables[__${itemStat.index}__].columns[__${status.index}__].index}" id="inputState" class="form-control" required>
<option value="" selected
disabled>Choose</option>
<option th:value="${index}">on</option>
<option th:value="${index}">off</option>
</select>
</td>
<td><select th:field="*{tables[__${itemStat.index}__].columns[__${status.index}__].notnull}" id="inputState" class="form-control" required>
<option value="" selected
disabled>Choose</option>
<option th:value="${notnull}">on</option>
<option th:value="${notnull}">off</option>
</select>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<button class="btn btn-danger mb-2 text-center" type="button" id="addTable" style="margin-top: 30px;">Add table</button>
</div>
<div class="text-center">
<button type="submit" class="btn btn-outline-danger btn-lg" style="margin-
top: 50px;">Generate File</button>
</div>
</form>
For the JS part I was using some codes to implement the addRow()
method which will add more Columns to the Table and addTable()
method that would add another Table object, but nothing was working for my case
This is my view is looking like: *PLEASE CAN ANYONE HELP ME TO SOLVE THAT .. I REALLY NEED IT .... *
Your approach is okay. But you need to fix a few things.
In the getTable
method, you are setting empty lists for tables
and columns
. So there is nothing to iterate over in the view layer to show the form. Change to:
@ModelAttribute("page")
public Page getTable() {
Column column = new Column();
List<Column> columns = new ArrayList<>();
columns.add(column);
Table table = new Table();
table.setColumns(columns);
List<Table> tables = new ArrayList<>();
tables.add(table);
Page page = new Page();
page.setTables(tables);
return page;
}
Add missing }
for th:field="*{tables[__${i.index}__].name"
and close this input
tag.
NOTE:
I am not sure how you wanted to handle the three select
inputs. I tested omitting them, meaning, keeping only Column
id
and name
in the form, data bind without any issue in that case.
Also I didn't check your JS
, as you have mentioned that you haven't tested it yet.
Suggestions:
I see you are returning a view name from your POST
handler. Take a look at the following article on Wikipedia.