I am new to Java and I'm currently working on a project with springboot and thymeleaf template engineer. I am having issues making an HTTP POST request with nested Set Collection.
My Java Classes are
User Class
import java.util.Set;
public class User {
private String name;
private String school;
private String bestSubject;
private Set<Work> work;
*//constructors, getters and setters*
}
Work Class
public class Work {
private String companyName;
private String faxNumber;
private String location;
*//constructors, getters and setters*
}
Controller
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
#Controller
public class UserController {
#Autowired
private UserService userService;
#GetMapping(value = "/user-register")
public String showUser(Model model) {
User users = new User();
model.addAttribute("users", userService.getUsersList());
return "userPage";
}
#PostMapping(value = "/user-details")
public String createUser(#ModelAttribute("users") User user){
System.out.println(user);
return "userResult";
}
}
Views
userPage.html
<form action="#" th:action="#{/user-details}" method="post" th:object="${users}">
<div class="row">
<div class="col-4">
<label for="name" class="col-form-label">Full Name:</label>
<input type="text" id="name" th:field="*{name}" class="form-control">
</div>
<div class="col-4">
<label for="school" class="col-form-label">School:</label>
<input type="text" id="school" th:field="*{school}" class="form-control">
</div>
<div class="col-4">
<label for="bestSubject" class="col-form-label">Best Subject:</label>
<input type="text" id="bestSubject" th:field="*{bestSubject}" class="form-control">
</div>
</div>
<!--BUTTON TO ADD AND DELETE FIELDS-->
<div class="row mt-4 mb-1">
<div class="col d-flex justify-content-between">
<div onclick="createField()" class="btn btn-primary float-start">Create row</div>
<div onclick="deleteField()" class="btn btn-danger float-end">Delete row</div>
</div>
</div>
<!--FIELDS LABEL-->
<div class="row">
<div class="col-4">
<label for="companyName" class="col-form-label">Company Name:</label>
</div>
<div class="col-4">
<label for="faxNumber" class="col-form-label">Fax Number:</label>
</div>
<div class="col-4">
<label for="location" class="col-form-label">Location:</label>
</div>
</div>
<table class="table table-borderless mt-0" id="userTable">
<tbody id="tableBody">
<tr th:each="user : ${users.work}">
<td>
<input type="text" id="companyName" th:field="*{user.companyName}" class="form-control">
</td>
<td>
<input type="text" id="faxNumber" th:field="*{user.faxNumber}" class="form-control">
</td>
<td>
<input type="text" id="location" th:field="*{user.location}" class="form-control">
</td>
</tr>
</tbody>
</table>
<button type="submit" class="btn btn-warning">
SUBMIT
</button>
</form>
UserResult.html
<p>Full Name: <span th:text="${users.name}"></span></p>
<p>University: <span th:text="${users.school}"></span></p>
<p>Best Subject: <span th:text="${users.bestSubject}"></span></p>
<table class="table table-striped .table-hover mt-1">
<thead>
<tr>
<th scope="col">Company Name</th>
<th scope="col">Fax Number</th>
<th scope="col">Address</th>
</tr>
</thead>
<tbody>
<tr th:each="user : ${users.work}">
<td th:text="${user.companyName}">
</td>
<td th:text="${user.faxNumber}">
</td>
<td th:text="${user.location}">
</td>
</tr>
</tbody>
</table>
My QUESTION IS
I keep getting User{name='...', school='...', bestSubject='...', work { **'null**' }}
Instead of
{
name: '...'
school: '...'
work: {
company_name: '...',
fax_number: '...',
location: '...'
}
}
How do I ensure my Set collection returns the inputed data from the fields instead of null datatype?
Related
I use an angular+springboot web application in which an object ( for this example- clinic object ) fetched from springboot in angular is not modified, and then is sent back to springboot, and some of its prperties's values for no apparent reason just become null, and others ( a boolean property get value of false, and integer properties get value of 0 ) get default values.
This is a table in which clinic objects are desplayed, and from which a modal to update a clinic is opened.
<table class="table">
<thead>
<tr>
<th scope="col" style="text-align:right;"></th>
<th scope="col" style="text-align:right;">State</th>
<th scope="col" style="text-align:right;">Foundation Year</th>
<th scope="col" style="text-align:right;">Supervisor</th>
<th scope="col" style="text-align:right;">Clinic Name</th>
</tr>
</thead>
<tbody>
<tr [ngClass]="{'not-active-clinic':!clinic.active}" *ngFor="let clinic of clinics">
<td style="text-align:right;">
<button class="btn-primary mr-1" (click)="openEditModal(editModal,clinic)"><i
class="fa fa-edit"></i></button>
<!--Edit Modal -->
<ng-template #editModal let-modal>
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">Clinic Edit</h4>
<button style="margin-left: 0;" type="button" class="close" aria-label="Close"
(click)="modal.dismiss('Cross click')">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<form dir="rtl">
<div class="row">
<div class="col-3">
<label>
Clinic Name: </label>
</div>
<div class="col-9">
<input style="width: 100%;" type="text" name="clinicName"
[(ngModel)]="edittedClinic.clinicName">
</div>
</div>
<div class="row">
<div class="col-3">
<label>
Supervisor</label>
</div>
<div class="col-9">
<select (change)="onChange()" style="width: 100%;"
name="clinicalSupervisorId"
[(ngModel)]="edittedClinic.clinicalSupervisorId">
<option *ngFor="let s of supervisors" [value]="s.id">
{{s.firstName+' '+s.lastName}}
</option>
</select>
</div>
</div>
<div class="row">
<div class="col-3">
<label>
description:</label>
</div>
<div class="col-9">
<textarea style="width: 100%;height:350px"
[(ngModel)]="edittedClinic.description" name="description">
</textarea>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-dark"
(click)="modal.close('Save click');onEdit(clinic)">Edit</button>
</div>
</ng-template>
<button class="btn btn-sm btn-danger btn-delete-account"
(click)="openDeleteModal(deleteModal)">
<span class="spinner-border spinner-border-sm"><i
class="fa fa-trash-alt"></i></span>
</button>
<!--Delete Modal -->
</td>
<td style="text-align:right;">
<button (click)="onChangeClinicState(clinic)">
{{clinic.active?"Add To Archive":"Restore"}}</button>
</td>
<td style="text-align:right;">{{clinic.yearFounded}}</td>
<td style="text-align:right;">{{clinic.clinicalSupervisorId}}</td>
<td style="text-align:right;">{{clinic.clinicName}}</td>
</tr>
</tbody>
</table>
This the method in angular to fetch the edited object to send it to service in which there is the http call to send the clinic object to springboot:
onEdit(clinicToEdit:Clinic)
{
this.dashboardService.updateClinicDetails(this.edittedClinic).subscribe(
data=>{
clinicToEdit=Object.create(this.edittedClinic);
},
err=>{
}
)
}
This is the method in the service to send the http put call
updateClinicDetails(clinic:Clinic)
{
return this.http.put(BASE_URL +`/api/v1/clinic/${clinic.clinicName}`,clinic);
}
This is the API method in springboot to get the clinic object sent from angular.
#PutMapping(path = "{clinicName}")
public int updateClinicById(#PathVariable("clinicName") String clinicName, #RequestBody Clinic clinicToUpdate)
{
return clinicService.updateClinic(clinicName, clinicToUpdate);
}
This is the constructor of clinic object invoked in order to fetch the JSON sent to springboot from angular.
public Clinic(#JsonProperty("clinicName") String clinicName,
#JsonProperty("clinicalSupervisorId") int clinicalSupervisorId,
#JsonProperty("description") String description, #JsonProperty("yearFounded") int yearFounded,
#JsonProperty("active") boolean active)
{
this.clinicName = clinicName;
this.clinicalSupervisorId = clinicalSupervisorId;
this.yearFounded = yearFounded;
this.description = description;
this.active = active;
}
Now, the thing is when modified, those mentioned properties don't contain null values, or their default values, What is the explanation to this, and what's the best way to solve it?
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" type="text/css" media="all" th:href="#{/css/bootstrap.min.css}">
<title>Home</title>
</head>
<body class="p-3 mb-2 bg-light text-black">
<div class="container">
<div id="logoutDiv">
<h1 th:text="${'Welcome ' + name}">Name</h1>
<form action="#" th:action="#{/logout}"method="POST">
<button type="submit" class="btn btn-secondary float-right">Logout</button>
</form>
</div>
<div id="contentDiv" style="clear: right;">
<nav style="clear: right;">
<div class="nav nav-tabs" id="nav-tab" role="tablist">
<a class="nav-item nav-link active" id="nav-files-tab" data-toggle="tab" href="#nav-files" role="tab" aria-controls="nav-files" aria-selected="true">Files</a>
<a class="nav-item nav-link" id="nav-notes-tab" data-toggle="tab" href="#nav-notes" role="tab" aria-controls="nav-notes" aria-selected="false">Notes</a>
<a class="nav-item nav-link" id="nav-credentials-tab" data-toggle="tab" href="#nav-credentials" role="tab" aria-controls="nav-credentials" aria-selected="false">Credentials</a>
</div>
</nav>Upload<
<div class="tab-content" id="nav-tabContent">
<div class="tab-pane fade show active" id="nav-files" role="tabpanel" aria-labelledby="nav-files-tab">
<p th:text="${message}" th:if="${message ne null}" class="alert alert-primary"></p>
<form action="#" enctype="multipart/form-data" th:action="#{'/file/uploadFile'}" th:method="POST" >
<div class="container">
<div class="row" style="margin: 1em;">
<div class="col-sm-2">
<label for="fileUpload">Upload a New File:</label>
</div>
<div class="col-sm-6">
<input type="file" class="form-control-file" id="fileUpload" name="fileUpload">
</div>
<div class="col-sm-4">
<button type="submit" class="btn btn-dark">/button>
</div>
</div>
</div>
</form>
<div class="table-responsive">
<table class="table table-striped" id="fileTable">
<thead>
<tr>
<th style="width: 20%" scope="col"></th>
<th style="width: 80%" scope="col">File Name</th>
</tr>
</thead>
<tbody>
<tr th:each="file : ${files}">
<td>
<a target="_blank" class="btn btn-success" th:href="#{/file/{filename}(fileName = ${file.filename})}">View</a>
<a class="btn btn-danger" th:href="#{/file/delete{filename}(filename = ${file.filename})}" >Delete</a>
</td>
<th scope="row" th:text="${file.filename}" ></th>
</tr>
</tbody>
</table>
</div>
</div>
<div class="tab-pane fade" id="nav-notes" role="tabpanel" aria-labelledby="nav-notes-tab">
<button style="margin: 0.25em;" type="button" class="btn btn-info float-right" onclick="showNoteModal()">
+ Add a New Note
</button>
<div class="table-responsive">
<table class="table table-striped" id="userTable">
<thead>
<tr>
<th style="width: 20%" scope="col"></th>
<th style="width: 20%" scope="col">Title</th>
<th style="width: 60%" scope="col">Description</th>
</tr>
</thead>
<tbody>
<tr th:each="note : ${notes}">
<td>
<button id="edit-note" type="button" class="btn btn-success"
th:attr="data-id=${note.getNoteId},
data-title=${note.getNoteTitle},
data-description=${note.getNoteDescription}"
onclick="showNoteModal (this.getAttribute('data-id'),this.getAttribute('data-title'),this.getAttribute('data-description'))">Edit/View</button>
<a id="delete-note" class="btn btn-danger" th:href="#{/note/delete/{noteId}(noteId = ${note.getNoteId()})}">Delete</a>
</td>
<th id="notetitle" scope="row" th:text="${note.getNoteTitle()}">Example Title</th>
<td id="notedescription" th:text="${note.getNoteDescription()}">Example Description </td>
</tr>
</tbody>
</table>
</div>
<div class="modal fade" id="noteModal" tabindex="-1" role="dialog" aria-labelledby="noteModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="noteModalLabel">Note</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
-Here is the error that I get-
<form action="#" method="POST" th:action="#{/note/add}" th:object="${Notes}">
<input type="hidden" name="noteId" id="note-id">
<div class="form-group">
<label for="note-title" class="col-form-label">Title</label>
<input type="text" name= "noteTitle" class="form-control" id="note-title" maxlength="20" required th:field="*{noteTitle}">
</div>
<div class="form-group">
<label for="note-description" class="col-form-label">Description</label>
<textarea class="form-control" name="noteDescription" id="note-description" rows="5" maxlength="1000" required th:field="*{noteDescription}"></textarea>
</div>
<button id="noteSubmit" type="submit" class="d-none"></button>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" onclick="$('#noteSubmit').click();">Save changes</button>
</div>
</div>
</div>
</div>
</div>
<div class="tab-pane fade" id="nav-credentials" role="tabpanel" aria-labelledby="nav-credentials-tab">
<button style="margin: 0.25em;" type="button" class="btn btn-info float-right" onclick="showCredentialModal()">
+ Add a New Credential
</button>
<div class="table-responsive">
<table class="table table-striped" th:object="${credentials}" id="credentialTable">
<thead>
<tr>
<th style="width: 20%" scope="col"></th>
<th style="width: 35%" scope="col">URL</th>
<th style="width: 20%" scope="col">Username</th>
<th style="width: 25%" scope="col">Password</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<button type="button" class="btn btn-success">Edit</button>
<a class="btn btn-danger">Delete</a>
</td>
<th scope="row">Example Credential URL</th>
<td>Example Credential Username</td>
<td>Example Credential Password</td>
</tr>
</tbody>
</table>
</div>
<div class="modal fade" id="credentialModal" tabindex="-1" role="dialog" aria-labelledby="credentialModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="credentialModalLabel">Credential</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<form action="#" method="POST">
<input type="hidden" name="credentialId" id="credential-id">
<div class="form-group">
<label for="note-title" class="col-form-label">URL</label>
<input type="text" name= "url" class="form-control" id="credential-url" maxlength="100" required>
</div>
<div class="form-group">
<label for="note-title" class="col-form-label">Username</label>
<input type="text" name= "username" class="form-control" id="credential-username" maxlength="30" required>
</div>
<div class="form-group">
<label for="note-title" class="col-form-label">Password</label>
<input type="text" name= "password" class="form-control" id="credential-password" maxlength="30" required>
</div>
<button id="credentialSubmit" type="submit" class="d-none"></button>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" onclick="$('#credentialSubmit').click();">Save changes</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script th:src="#{/js/jquery-slim.min.js}"></script>
<script th:src="#{/js/popper.min.js}"></script>
<script th:src="#{/js/bootstrap.min.js}"></script>
<!--For opening the note modal-->
<script type="text/javascript">
// For opening the note modal
function showNoteModal(noteId, noteTitle, noteDescription) {
$('#note-id').val(noteId ? noteId : '');
$('#note-title').val(noteTitle ? noteTitle : '');
$('#note-description').val(noteDescription ? noteDescription : '');
$('#noteModal').modal('show');
}
// For opening the credentials modal
function showCredentialModal(credentialId, url, username, password) {
$('#credential-id').val(credentialId ? credentialId : '');
$('#credential-url').val(url ? url : '');
$('#credential-username').val(username ? username : '');
$('#credential-password').val(password ? password : '');
$('#credentialModal').modal('show');
}
</script>
</body>
</html>
-I get an error when trying to parse the Note Form into my Note Controller. I try to parse my model object Notes in the form in my HTML home form into the Controller but it can not except the fields from the form. My first error is this:
Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Error during execution of processor 'org.thymeleaf.spring5.processor.SpringInputGeneralFieldTagProcessor' (template: "home" - line 109, col 148), Line 109 is the fields from the form
I also get a second error: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'Notes' available as request attribute-
--- Note Controller ---
#Controller
#RequestMapping("note")
public class NoteController {
private NoteService noteServices;
private UserService userService;
public NoteController(NoteService noteServices, UserService userService) {
this.noteServices = noteServices;
this.userService = userService;
}
// Add an new note
#PostMapping("add")
public String addNote(#ModelAttribute(value="Notes")Notes Notes, Authentication authentication, Model model) throws IOException {
String userName = authentication.getName();
User user = userService.getUser(userName);
Integer userid = user.getId();
if(Notes.getNoteId() == null){
noteServices.addNote(Notes,userid);
}else{
noteServices.editNote(Notes);
}
return "result";
}
#GetMapping("/delete/{noteId:.+}")
public String deleteNote(#PathVariable Integer noteId, Authentication authentication, RedirectAttributes redirectAttributes){
noteServices.deleteNote(noteId);
redirectAttributes.addFlashAttribute("deleteNoteSuccess","Note deleted successfully.");
return "redirect:/result";
}
private Integer getUserId(Authentication authentication) {
String userName = authentication.getName();
User user = userService.getUser(userName);
return user.getId();
}
}
---
--- POJO Model ---
public class Notes {
private Integer noteId;
private String noteTitle;
private String noteDescription;
private Integer userId;
public Notes(String noteTitle, String noteDescription, Integer userId) {
this.noteTitle = noteTitle;
this.noteDescription = noteDescription;
this.userId = userId;
}
public Integer getNoteId() {
return noteId;
}
public void setNoteId(Integer noteId) {
this.noteId = noteId;
}
public String getNoteTitle() {
return noteTitle;
}
public void setNoteTitle(String noteTitle) {
this.noteTitle = noteTitle;
}
public String getNoteDescription() {
return noteDescription;
}
public void setNoteDescription(String noteDescription) {
this.noteDescription = noteDescription;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
}
Need some advice how should I retrieve a list of exhibits.
In my html template below, I only put one record of exhibit. If i were to put additional rows/records of exhibit, how do i go about mapping them to the controller.
HTML Template
<h3>Exhibit Details</h3>
<div class="table-responsive">
<table id="exhibitTable"
class="table table-bordered table-hover table-striped">
<thead>
<tr>
<th>Exhibit Type</th>
<th>Description</th>
<th>Marking</th>
<th>Remarks</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="form-group col-md-3">
<div class="cols-sm-10">
<select class="form-control selectpicker cols-md-3"
th:value="${exhibit.exhibitType}" id="exhibitType"
name="exhibitType" roleId="exhibitType">
<option value="">Select Type</option>
<option>Desktop</option>
<option>Laptop</option>
<option>Mobile Device</option>
<option>Portable Storage</option>
<option>Server</option>
<option>Video System</option>
<option>Save As</option>
<option>Others</option>
</select>
</div>
</div>
</td>
<td>
<div class="form-group col-md-3">
<input type="text" name="exhibitDescription"
id="exhibitDescription"
th:value="${exhibit.exhibitDescription}" />
</div>
</td>
<td>
<div class="form-group col-md-3">
<input type="text" name="exhibitMarking" id="exhibitMarking"
th:value="${exhibit.exhibitMarking}" />
</div>
</td>
<td><div class="form-group col-md-3">
<input type="text" name="exhibitRemarks" id="exhibitRemarks"
th:value="${exhibit.exhibitRemarks}" />
</div></td>
</tr>
</tbody>
</table>
</div>
Controller
#RequestMapping(value = "/register", method = RequestMethod.POST)
public String registerIncidentPost(#ModelAttribute("incident") Incident incident,
#ModelAttribute("exhibit") Exhibit exhibit, Principal principal) throws Exception {
long year = Calendar.getInstance().get(Calendar.YEAR);
incident.setIncidentYear(year + "");
Long refNo = incidentService.findMaxRefNoCurrentYear(year + "");
if (refNo == null)
refNo = (long) 1;
else
refNo += 1;
incident.setIncidentRefNo(refNo);
incident.setIncidentStatus(Incident.INCIDENT_REGISTERED);
incident.setIncidentOpeningTimestamp(new Date());
User user = userService.findByUsername(principal.getName());
incident.setIncidentCreatedBy(user);
incidentService.createIncident(incident);
exhibitService.createExhibit(exhibit);
return "redirect:/incident";
}
I've attempted to add the following to my template
<tr data-th-each="exhibit:${exhibitList}">
and the following to my controller
#ModelAttribute("exhibitList") ArrayList<Exhibit> exhibitList
but did not work.
Thanks in advance.
I can only assume this is vb.net since you didn't specify. You need to pass in the complete dataset to the page. Each item in the dataset will be one pre-loaded instance of the model. Then you can do a for each loop on the page itself and generate the html dynamically. Hope this helps.
I have a table of generating the dynamic checkboxes as below:
<div style="background: #fff;">
<div class="modal-body">
<table class="table no-margin">
<thead>
<tr>
<th>Select</th>
<th>Group Name</th>
<th>Contacts</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="checkbox checkbox-styled">
<label>
<input type="checkbox" class="datacontact" onchange="SelectContacts(this);" data-listid='1' data-grpname='Newsletter' />
</label>
</div>
</td>
<td>Newsletter</td>
<td>0</td>
</tr>
<tr>
<td>
<div class="checkbox checkbox-styled">
<label>
<input type="checkbox" class="datacontact" onchange="SelectContacts(this);" data-listid='2' data-grpname='Website Leads Buyer' />
</label>
</div>
</td>
<td>Website Leads Buyer</td>
<td>0</td>
</tr>
<tr>
<td>
<div class="checkbox checkbox-styled">
<label>
<input type="checkbox" class="datacontact" onchange="SelectContacts(this);" data-listid='3' data-grpname='Website Leads Seller' />
</label>
</div>
</td>
<td>Website Leads Seller</td>
<td>2</td>
</tr>
<tr>
<td>
<div class="checkbox checkbox-styled">
<label>
<input type="checkbox" class="datacontact" onchange="SelectContacts(this);" data-listid='4' data-grpname='Website Leads Investor' />
</label>
</div>
</td>
<td>Website Leads Investor</td>
<td>0</td>
</tr>
<tr>
<td>
<div class="checkbox checkbox-styled">
<label>
<input type="checkbox" class="datacontact" onchange="SelectContacts(this);" data-listid='5' data-grpname='Website Leads' />
</label>
</div>
</td>
<td>Website Leads</td>
<td>0</td>
</tr>
<tr>
<td>
<div class="checkbox checkbox-styled">
<label>
<input type="checkbox" class="datacontact" onchange="SelectContacts(this);" data-listid='7980' data-grpname='NewGroup1' />
</label>
</div>
</td>
<td>NewGroup1</td>
<td>0</td>
</tr>
<tr>
<td>
<div class="checkbox checkbox-styled">
<label>
<input type="checkbox" class="datacontact" onchange="SelectContacts(this);" data-listid='7996' data-grpname='My Group' />
</label>
</div>
</td>
<td>My Group</td>
<td>0</td>
</tr>
<tr>
<td>
<div class="checkbox checkbox-styled">
<label>
<input type="checkbox" class="datacontact" onchange="SelectContacts(this);" data-listid='9136' data-grpname='Email Functionality ' />
</label>
</div>
</td>
<td>Email Functionality </td>
<td>0</td>
</tr>
</tbody>
</table>
</div>
<div class="modal-footer">
<button type="button" data-dismiss="modal" class="btn btn-flat btn-default-dark ink-reaction">OK</button>
<button type="button" data-dismiss="modal" class="btn btn-flat btn-default-dark ink-reaction">Cancel</button>
</div>
</div>
</div>
</div>
</div>
And through the below mentiond code, I have getting value of the checkbox called "Website Leads Seller"
package TestScripts;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.WebElement;
//import com.sun.xml.internal.bind.v2.schemagen.xmlschema.List;
public class EmailClient_VerifyEmail {
public static void main(String[] args) {
System.setProperty("webdriver.gecko.driver", "C:/geckodriver/geckodriver-v0.21.0-win64/geckodriver.exe");
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(40, TimeUnit.SECONDS);
driver.get("http://cp.iagentsolutions.com/login.aspx");
//enter email id
driver.findElement(By.cssSelector("#txtuserName")).sendKeys("abdul123");
//enter password
driver.findElement(By.cssSelector("#txtPassword")).sendKeys("admin123");
// click on login
driver.findElement(By.cssSelector("#LoginSnd")).click();
System.out.println("User Login Successfully from CP");
//hover on menu
//driver.findElement(By.xpath("html body.menubar-hoverable.header-fixed.menubar-visible form#form1 div#base div#menubar.menubar-inverse.animate div.nano.has-scrollbar div.nano-content div.menubar-scroll-panel ul#main-menu.gui-controls"))
Actions action = new Actions(driver);
//WebElement element =
action.moveToElement(driver.findElement(By.cssSelector(".menubar-foot-panel"))).perform();//("html body.menubar-hoverable.header-fixed.menubar-visible form#form1 div#base div#menubar.menubar-inverse.animate div.nano.has-scrollbar div.nano-content div.menubar-scroll-panel ul#main-menu.gui-controls")));
//click on Email Client menu for open sub-menus
driver.findElement(By.xpath("/html/body/form/div[3]/div[2]/div[2]/div[1]/div/ul/li[7]/a/span")).click();
driver.manage().timeouts().implicitlyWait(40, TimeUnit.SECONDS);
// click on Create Email
driver.findElement(By.xpath("/html/body/form/div[3]/div[2]/div[2]/div[1]/div/ul/li[7]/ul/li[1]/a/span")).click();
//Enter draft name
driver.findElement(By.name("ctl00$body$txtDraftName")).sendKeys("Try to send without verify email");
//Click on Next button
driver.findElement(By.name("ctl00$body$btnStep1Next")).click();
//Email Settings
// Enter subject
driver.findElement(By.id("body_txtSubject")).sendKeys("Try to send without verify email");
driver.manage().timeouts().implicitlyWait(50, TimeUnit.SECONDS);
//Click on Add / Edit to open Contact List
driver.findElement(By.linkText("Add / Edit")).click();
driver.manage().timeouts().implicitlyWait(50, TimeUnit.SECONDS);
driver.findElements(By.xpath("//input[#type='checkbox' and #class='datacontact']")).forEach(elelemnt -> {
elelemnt.click();
});
}
}
But this code is only working for getting the check box title instead of clicking on the checkbox.
I have tested it and it is working properly :
using below code :
driver.findElements(By.xpath("//input[#type='checkbox' and #class='datacontact']")).forEach(element -> {
if (element.getAttribute("data-grpname").trim().equals("Website Leads Seller")) {
((JavascriptExecutor) driver).executeScript("arguments[0].click();", element);
}
});
I need to bind an object with a list of objects as an attribute. It is a static list and it is created and partially filled in the Controller. It is displayed correctly in the view, however the value in the input field is not set when the form is sent to the controller. I did some research and found several similar questions, however none of the proposed solutions worked for me.
edit.jsp
<c:forEach items="${priceConfigurationForm.priceList}" var="price" varStatus="priceStatus">
<tr>
<td>
<spring:bind path="priceConfigurationForm.priceList[${priceStatus.index}].country">
${price.country}
<input type="hidden" name="<c:out value="${status.expression}"/>"
id="<c:out value="${status.expression}"/>"
value="<c:out value="${status.value}"/>"/>
</spring:bind>
</td>
<td>
<spring:bind path="priceConfigurationForm.priceList[${priceStatus.index}].amount">
<input type="text" name="price" value="${price.amount}"/>
<input type="hidden"
name="<c:out value="${status.expression}"/>"
id="<c:out value="${status.expression}"/>"
value="<c:out value="${status.value}"/>"/>
</spring:bind>
</td>
<td>
<spring:bind path="priceConfigurationForm.priceList[${priceStatus.index}].currency">
${price.currency}
<input type="hidden" name="<c:out value="${status.expression}"/>"
id="<c:out value="${status.expression}"/>"
value="<c:out value="${status.value}"/>"/>
</spring:bind>
</td>
</tr>
</c:forEach>
Abstract from Controller populating the list:
#RequestMapping(value = "/price/create", method = RequestMethod.GET)
public String toCreatePriceConfiguratioView(Model model) {
log.info("::createPriceConfiguration: {}");
final PriceConfigurationForm priceConfigurationForm = new PriceConfigurationForm();
final List<PriceConfigurationForm.Price> prices = new ArrayList<>();
for (Country country : Country.values()) {
PriceConfigurationForm.Price price = new PriceConfigurationForm.Price();
price.setAmount(100);
price.setCountry(country.getCountryCode());
price.setCurrency(country.getCurrency());
prices.add(price);
}
priceConfigurationForm.setPriceList(prices);
model.addAttribute("priceConfigurationForm", priceConfigurationForm);
return "/secured/sources/onboarding/price/edit";
}
Abstract from Controller for storing the list:
#RequestMapping(value = "/price/create", method = RequestMethod.POST)
public String createPriceConfiguration(Model model, #ModelAttribute("priceConfigurationForm") #Valid PriceConfigurationForm priceConfigurationForm, BindingResult bindingResult, RedirectAttributes attributes) {
log.info("::createPriceConfiguration {}", priceConfigurationForm);
// TODO: Validate, before create
/* transform form to domain object */
PriceConfiguration configuration = PriceConfigurationForm.toPriceConfiguration(priceConfigurationForm);
onboardingApi.createPriceConfiguration(configuration);
attributes.addFlashAttribute("message", success("price configuration saved", priceConfigurationForm.getName()));
return "/secured/sources/onboarding/price/index";
}
Object:
#Data
public class PriceConfigurationForm {
private String name;
private String description;
private List<Price> priceList;
private Map<String, Long> countryToPriceMap;
public static PriceConfiguration toPriceConfiguration(PriceConfigurationForm form) {
final PriceConfiguration pc = new PriceConfiguration();
pc.setName(form.getName());
pc.setDescription(form.getDescription());
final Map<String, Long> prices = form.getPriceList().stream().collect(toMap(Price::getCountry, Price::getAmount));
pc.setCountryToPriceMap(prices);
return pc;
}
#Data
public static class Price {
private String country;
private long amount;
private String currency;
}
}
This is example of how I sucessfully parsed nested objects in one project :
<c:forEach var="block" items="${newplaceform.blocks}" varStatus="counter">
<fieldset data-block-order="${counter.index}" data-block-index="${counter.index}">
<c:if test='${block.type=="quizSingleAnswer"}'>
<legend><s:message code='blocks.type.quizSingleAnswer'/> <a class="glyphicon glyphicon-move move-block pull-right" href="#"></a><a data-remove="block" class="glyphicon glyphicon-remove pull-right" href="#"></a><a data-reordering="up" class="glyphicon glyphicon-chevron-up pull-right" href="#"></a><a data-reordering="down" class="glyphicon glyphicon-chevron-down pull-right" href="#"></a></legend>
<div class="form-group production-hide">
<label class="col-sm-3 control-label">id:</label>
<div class="col-sm-9"><input type="text" name="blocks[${counter.index}].id" value="${block.id}" data-row="blockId" data-disabled class="form-control"/></div>
</div>
<div class="form-group production-hide">
<label class="col-sm-3 control-label">type:</label>
<div class="col-sm-9"><input type="text" name="blocks[${counter.index}].type" value="${block.type}" data-disabled class="form-control"/></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label"><s:message code='blocks.description'/>:</label>
<div class="col-sm-9"><textarea class="form-control" name="blocks[${counter.index}].description" data-description rows="3">${block.description}</textarea></div>
</div>
<div class="row">
<div class="col-sm-6">
<div class="col-sm-6 control-label">
<label class="inner-header"><s:message code='blocks.answers'/>:</label>
</div>
<div class="col-sm-6">
<div class="btn-group m-t-9">
<a class="btn btn-primary btn-xs" href="#" data-add-answer data-add-answer-block-index="${counter.index}"><i class="glyphicon glyphicon-plus"></i> <s:message code="blocks.add-answer" /></a>
</div>
</div>
</div>
</div>
<div class="row quiz-answers" data-count-answer="${block.answers.size()}">
<c:forEach var="answer" items="${block.answers}" varStatus="counterInner">
<div class="col-sm-6">
<fieldset>
<legend>
<div class="bootstrap-center">
<span><s:message code="blocks.answerNo"/> ${counterInner.index+1}</span>
<a data-remove="answer" class="glyphicon glyphicon-remove pull-right" href="#"></a>
</div>
</legend>
<div class="form-group production-hide">
<label class="col-sm-6 control-label">id:</label>
<div class="col-sm-6"><input type="text" name="blocks[${counter.index}].answers[${counterInner.index}].id" value="${answer.id}" data-row="answerId" data-disabled class="form-control"/></div>
</div>
<div class="form-group">
<label class="col-sm-6 control-label"><s:message code="blocks.answer"/>:</label>
<div class="col-sm-6"><input type="text" name="blocks[${counter.index}].answers[${counterInner.index}].text" value="${answer.text}" class="form-control"/></div>
</div>
<div class="form-group">
<div class="col-sm-6 col-sm-offset-6">
<div class="checkbox">
<label>
<input type="checkbox" name="blocks[${counter.index}].answers[${counterInner.index}].right" value="true" ${answer.checked()}/>
<s:message code="blocks.right"/>
</label>
</div>
</div>
</div>
</fieldset>
</div>
</c:forEach>
</div>