How to edit a list of child entities in Spring 3 MVC - spring

How would I edit an entity with child rows in Spring 3 MVC?
I'd like a form like:
<forms:form>
<p>Parent name <forms:input path="model.name" type="text" /></p>
<p>Children:
<ul>
<s:foreach in="${model.children}" var="${child} varStatus="row">
<li>
name: <forms:input path="model.children[${row.index}].name" />
<button name="?">delete</button>
</li>
</s:foreach>
</ul>
</p>
<p><button name="?">add child</button></p>
</forms:form>
I'm having a lot of trouble getting this to work in Spring 3.
I would love to be able to:
edit child properties inline on the parent's form, with validation etc.
delete children inline on the parent's form
add children inline on the parent's form

Have you checked out jqGrid?
If you want DIY, then have a nested loop and create the crud links in the inner loop.
An HTML table might be appropriate for presentation.
Here is part of the "child" loop.
<tbody style="background: #ccc">
<c:forEach items="${parent.children}" var="work">
<tr>
<td>${work.id}</td>
<td>${work.title}</td>
<spring:url var="editWorkUrl" value="/work/edit/${work.id}" />
<spring:url var="deleteWorkUrl" value="/work/delete/${work.id}" />
<td>Edit
</td>
<td>Delete
</td>
</tr>
</c:forEach>
</tbody>

Related

Passing computed string to x-teleport in alpine.js

I want to append an element to a specific element when the user clicks the button. The scenario goes like this. Is there another way to deal with that kind of problem?
<table>
<tbody>
<tr>
<td>
One
<button>delete</button>
<button x-on:click="edit(passIdToFunc)">edit</button>
</td>
</tr>
<tr id="one" style="display: hidden"></tr>
<!-- append x-teleport dom node to here when current value is id = one -->
<tr>Two</tr>
<tr id="two" style="display: hidden"></tr>
<tr>Three</tr>
<tr id="three" style="display: hidden"></tr>
...
</tbody>
</table>
<!--
For the initial render, or if there is no table data,
I would like to append it to somewhere else with display none.
-->
<template x-teleport="computedString">
...
</template>
This looks like the wrong usage for x-teleport, though it's not clear from the example where you are teleporting to. You can just use x-show to toggle display:none if that's what you're looking for.

How to filter data in Thymeleaf table

I'm a new Thymeleaf developer (Spring-Boot 2.1.5 environment).
I want to implement filtering over a list from an Input. When I enter the name of the client in the input it appears on a table (without submit button).
<form th:action="#{/clientslistbypage}" method="get" th:object="${Clients}" class="form-inline" >
<input type="text" name="client" th:value="${client}" id="clientSearch" >
<!-- <input type="submit" name="clients" th:value="Search">-->
</form>
I tried the Projection and Collection function but I do not know how to dynamically assign the input value to the Collection formula.(${Clients.?[firstName >='here i want to insert the value of the Searche Input']})
<tr th:each = "c: ${Clients.?[firstName >='']}" >
<td th:text = "${c.id}"></td>
<td th:text = "${c.firstName}"></td>
<td th:text = "${c.LAST_NAME} "></td>
</tr>
I tried DANDELION but unfortunately, do not run under Spring-Boot 2.1.5.
any proposal, tutorial, or example is welcome

Why "checked" attribute doesn't apply to my Thymeleaf's checkboxes?

I was working with Spring and Thymeleaf when I've encountered the following problem: I need a Form object, which has a list of items (Item) as attribute; I'm using an html form to print the Name of the Item, and to generate a checkbox for each Item (any checkbox's value is the corresponding item's id).
The form works correctly, sending to the Controller a list of item's ids corresponding to the checked checkboxes.
However, now, I'm trying to check some checkbox upon the occurrence of a condition (if itemIds, which is a list, contains the current item's id). For that I'm using:
th:checked="${#lists.contains(itemIds, item.id)}"/>
But it doesn't work (checkbox are all unchecked).
I tried also with a "dummy test":
th:checked="${1 == 1 ? 'checked' : ''}"/>
But, again, all the checkbox remain unchecked; the "checked" attribute is ignored as you can see in this example of the rendered HTML:
<input type="checkbox" value="12" class="chkCheckBox" id="ids1" name="ids">
What am I doing wrong? What am I missing here?
form.html
<form th:action="#{${uriBase}+'/new/' + ${date}}"
method="POST" th:object="${form}">
<div class="table-responsive">
<table class="table">
<thead class=" text-primary">
<tr>
<th>Name</th>
<th><input type="checkbox" th:id="checkAll"/>Check</th>
</tr>
</thead>
<tbody>
<tr th:each="item : ${items}">
<td th:text="${item.name}"></td>
<td>
<input type="checkbox" th:field="*{ids}"
th:value="${item.id}" th:class="chkCheckBox"
th:checked="${#lists.contains(itemIds, item.id)}"/>
</td>
</tr>
</tbody>
</table>
<button type="submit" class="btn btn-primary pull-right">Submit</button>
<div class="clearfix"></div>
</div>
</form>
Form class
public class Form implements Serializable {
private List<Long> ids;
//getter and setter
}
Thank you in advance.
I have been struggling with this as well. If you use the th:field it will override the checked and value options, as Xaltotun mentions, because it is trying to get the value and checked option from the field/form.
If you change it to th:name it should work how you want...
But this forum seems to be helpful for doing it with th:feild.
As far as I understand there are 2 issues in your post:
The dummy example is incorrect.
th:checked="${1 == 1 ? 'checked' : ''}"
In fact the value must true or false not 'checked'. If you try with
th:checked="${1 == 1}"/>
It will work.
If you set th:field="*{ids}" then the checkbox should be trying to get the value from the field item.ids and will not use the "th:checked" or "th:value" properties. Does the item has the field ids?

Angular 2 doesn't update my view after I add or edit item

I've finally made my app in angular 2. Everything is solved, except one thing. When I add item into my table or edited it, I can't see the change until I refresh page or click for example next page button (I have implemented pagination). I included:
<script src="node_modules/systemjs/dist/system-polyfills.js"></script>
<script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
in this order. My method for adding item is very simple:
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(departments => this.department = departments.json());
this.getAll();}
Whhen I add item, and put breakpoint on get method, It is called correctly and I get right information from my DB, but I don't know why view isn't refreshed then. Do you have any idea why is it happened? Thanks for suggestions!
EDIT: department is just department: Department, where Department is interface with properties (departmentNo, departmentName, departmentLocation). The view for adding item looks like:
<form [ngFormModel]="myForm"
(ngSubmit)="addDepartment(newItem); showAddView=false" [hidden]="!showAddView" align="center">
<div>
<label for="editAbrv">Department name:</label><br>
<input type="text" [(ngModel)]="newItem.departmentName" [ngFormControl]="myForm.controls['departmentName']" >
<div *ngIf="myForm.controls['departmentName'].hasError('required')" class="ui error message"><b style="color:red;">Name is required</b></div>
</div>
<br/>
<div>
<label for="editAbrv">Department Location:</label><br>
<input type="text" [(ngModel)]="newItem.departmentLocation" [ngFormControl]="myForm.controls['departmentLocation']" >
<div *ngIf="myForm.controls['departmentLocation'].hasError('required')" class="ui error message"><b style="color:red;">Location is required</b></div>
</div>
<br/>
<div>
<button type="submit" [disabled]="!myForm.valid" class="ui button">Add item</button>
<button><a href="javascript:void(0);" (click)="showHide($event)" >
Cancel
</a></button>
</div>
</form>
and my department table is:
<table align="center">
<thead>
<tr>
<td>#</td>
<td><strong>Department</strong></td>
<td><strong>Department Location</strong></td>
<td><strong>Edit</strong></td>
<td><strong>Delete</strong></td>
</tr>
</thead>
<tbody>
<tr *ngFor="#department of departments | searchString:filter.value ; #i = index">
<td>{{i + 1}}.</td>
<td> {{department.departmentName}}</td>
<td>{{department.departmentLocation}}</td>
<td>
<button class="btnEdit" (click)="showEdit(department)">Edit</button>
</td>
<td>
<button class="btnDelete" (click)="deleteDepartment(department)" >Delete</button>
</td>
</tr>
</tbody>
</table>
With this code, you don't wait for the response of the addDepartment request and execute the getAll request directly.
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(departments => this.department = departments.json());
this.getAll();
}
You should move the call to getAll within the callback registered in subscribe. At this moment, the addDepartment is actually done and you can reload the list...
The code could be refactored like this (it's a guess since I haven't the content of addDepartment and getAll methods):
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(addedDepartment => {
this.department = this.getAll();
});
}
This issue occurs because of the way you're using departmant and how change detection works. When you use *ngFor="#department of departments", angular change detection looks for a object reference on departments array. When you update/change one of the items in this array object reference to the array itself doesn't change, so angular doesn't run change detection.
You have few options:
1) change reference of the array by replacing it with new array with updated values
2) tell angular explicitly to run change detection (which I think is easier in your case):
constructor(private _cdRef: ChangeDetectorRef) {...}
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(departments => this.department = departments.json());
this.getAll();
this._cdRef.markForCheck();
}

Binding multiple objects in a Spring form

I have problems with getting my JSP view right. What I intend to do is to send a List that contains questions and each question object is a text field and a List with alternatives.
My intention is to be able to edit multiple questions (both to be able to edit the text/name of the question and edit the containing alternatives).
My backing object is now sending an List question.
Here is my JSP which are failing with invalid property of bean class.
<form:form commandName="question">
<form:errors path="*">
<fieldset class="stdframe">
<legend>Question</legend>
</fieldset>
</form:errors>
<div class="stdframe">
<c:forEach var="q" items = "${question}" varStatus = "s">
<p><b>Question:</b></p>
<p><form:input size="67" path="${q.text}"/></p>
<br/>
${q.text}
<ul>
<c:forEach var="alternative" items = "${q.alternatives}" varStatus = "t">
${alternative.text}
<li><form:input path = "${alternative[$t.index].text}" /></li>
</c:forEach>
</ul>
<br/>
</c:forEach>
<input type="submit" class="submit" value="Save" />
<input type="button" class="button" onClick="back()" value="Back"/>
</div>
</form:form>
I have tried both ${q.text} and ${q[$s.index].text}. When I just print ${q.text} it shows the correct text for the question object. Same goes for alternative.
What can I do to correctly bind the form to the objects?
In addition when I store an object which contains a list of other object, will the list be stored itself in the database?
You may need to wrap your List in a simple object with the List as a field:
class MyListWrapper { List questions; } // etc.
If you use that as your command/form object, you should be able to do something like this in the JSP:
<form:form commandName="wrapper">
// ...
<c:forEach var="q" items = "${wrapper.questions}" varStatus = "s">
<p><b>Question:</b></p>
<p><form:input size="67" path="questions[${s.index}].text"/></p>
// ...
<c:forEach var="alternative" items = "${q.alternatives}" varStatus = "t">
${alternative.text}
<li><form:input path = "questions[${s.index}].alternatives[${t.index}].text" /></li>

Resources