Apologies if this question has been asked and answered elsewhere, but I couldn't find much help about it so thought I'll ask here. I am very new to Thymeleaf and still trying to make sense of things. So here is what I'm trying to do,
OBJECTIVE: Extract data from the database and display it on a simple webpage in tabular form (i.e., Rows and Columns). All fields are editable with a Submit and Reset button at the end. Something like this,
PROBLEM: So the issue I am facing is this, if there is only one row data, there is no issue in updating the records, but if there is more than 1 record when I edit the record and press Submit, the updated record remains the same as before, but the first record in the list gets the updated text concatenated to the existing text in their respective columns. This behavior is shown in the following image,
As seen in the image above, I had two records ... without even changing the record, I press Submit button and now I can see Record 1 has Row 2 text concatenated to its existing text.
This is my Code,
HTML
<form
action="#"
th:action="#{/saveMapping}"
th:object="${hanaMappingT}"
method="post"
>
<table id="mappings">
<thead>
<tr>
<th>ID</th>
<th>WBSNAME</th>
<th>ITEMDESCRIPTION</th>
<th>WBSCANDYCODE</th>
<th>WBSHENAME</th>
</tr>
</thead>
<tbody>
<tr th:each="mapping : ${allMappings}">
<td>
<input
type="text"
field="*{id}"
th:name="id"
th:value="${mapping.id}"
/>
</td>
<td>
<input
type="text"
field="*{wbsName}"
th:name="wbsName"
th:value="${mapping.wbsName}"
/>
</td>
<td>
<input
type="text"
id="itemDescription"
field="*{itemDescription}"
th:name="itemDescription"
th:value="${mapping.itemDescription}"
/>
</td>
<td>
<input
type="text"
field="*{wbsCandyCode}"
th:name="wbsCandyCode"
th:value="${mapping.wbsCandyCode}"
/>
</td>
<td>
<input
type="text"
field="*{wbsHeName}"
th:name="wbsHeName"
th:value="${mapping.wbsHeName}"
/>
</td>
</tr>
</tbody>
</table>
<input type="submit" value="Submit" />
<input type="reset" value="Reset" />
</form>;
CONTROLLER CLASS
#PostMapping("/saveMapping")
public String saveMapping(
#ModelAttribute HanaMappingT mapping, Model model) {
try {
log.info(mapping.toString());
List<HanaMappingT> mappingList = new ArrayList<HanaMappingT>();
mappingList.add(mapping);
log.info("List : " + mappingList.toString());
hanaService.updateMapping(mappingList);
} catch (Exception e) {
log.error("Unable to save mapping data - ", e);
}
return "result";
}
HanaMappingT class
#Data
#Entity
#Table(name = "MAPPING_T")
public class HanaMappingT {
#Id
#Column(name = "ID")
private Integer id;
#Column(name = "WBSNAME")
private String wbsName;
#Column(name = "ITEMDESCRIPTION")
private String itemDescription;
#Column(name = "WBSCANDYCODE")
private String wbsCandyCode;
#Column(name = "WBSHENAME")
private String wbsHeName;
}
I am not really sure how to deal with multiple records, how with one single submit button I can store all records in their respective columns and rows.
If you need further clarification, please feel free to ask questions and I'll try to answer to the best of my ability.
Related
I have a language quiz in an HTML form When the user checks their entry, feedback is inserted into cell in the form of a tick or cross icon . My problem is that the feedback is always inserted into the first td whether the first or second question is answered and checked. Question and appropriate answer are associated with elementNo: I can't figure out how to associate the "mark" cell with the its answer and question
<SCRIPT>
//Define the answers.
Answer = new Array( "Die Maus ist weiss.", "",
"Auf Wiedersehen!");
//inserts icon, however only in the first element named "mark".
// Somehow needs to select correct place according to element number
function itemfeedback (elementNo)
{
if (document.E1a.elements[elementNo].value == "")
{
alert("You must type an answer!");
}
else if (document.E1a.elements[elementNo].value == Answer[elementNo])
{
document.getElementById("mark").innerHTML = "<img src='correct.jpg'>";
}
else
{
document.getElementById("mark").innerHTML = "<img src='incorrect.jpg'>";
}
}
</SCRIPT>
</HEAD>
<BODY>
<FORM NAME="E1a" accept-charset="ISO-8859-1" onReset="return confirm('Clear entries? Are you sure?')">
<HR>
<H3>
translate, remembering punctuation and capitalisation...
</H3>
<table>
<tr>
<td>1. The mouse is white.</td>
<td><INPUT TYPE="TEXT" NAME="Q1" SIZE=50 MAXLENGTH=50></td>
<td><INPUT TYPE="button" id ="check_button" VALUE="check..." NAME="B1" onClick="itemfeedback(0)"></td>
<td id="mark"></td>
</tr>
<tr>
<td>2. Good-bye!</td>
<td><INPUT TYPE="TEXT" NAME="Q2" SIZE=50 MAXLENGTH=50></td>
<td><INPUT TYPE="button"id ="check_button" VALUE="check..." NAME="B2" onClick="itemfeedback(2)"></td>
<td id="mark"></td>
</tr>
</table>
<hr>
<INPUT TYPE="RESET" id ="reset_fields" VALUE="Clear Entries">
</CENTER>
</FORM>
</BODY>
</HTML>
I hope that my question is clear and that someone will help.
Quick Answer
ID's are intended to be unique within a HTML document according to HTML5 specs. Because of this, all instances of an ID after the first occurrence are ignored by JavaScripts "getElementById" function. A more proper way to select multiple DOM elements is to use the "class" attribute, like this:
<td class="mark"></td>
...
<td class="mark"></td>
And reference it using JavaScript, using "getElementsByClassName"
document.getElementsByClassName('mark')
More Helpful Answer
I would make a couple more suggestions, to make your code a bit more dynamic, and functional. I have inserted comments in the code below to explain the changes/suggestions I have.
<html>
<head>
<script>
// We will use an object instead of an array, so that we can reference the answers by a string, rather then an integer.
// Also, any time a NEW variable is defined, it should be prefaced with "let" or "const" for >= ES2015, or "var" for < ES2015 (see https://codeburst.io/javascript-wtf-is-es6-es8-es-2017-ecmascript-dca859e4821c for details on the different script versions)
const answer = {
Q1: "Die Maus ist weiss.",
Q2: "Auf Wiedersehen!"
};
// itemfeedback function is now passing the input id, rather than the index
function itemfeedback (id) {
// This will get the input, associated with the button
let input = document.getElementById(id),
// This will be the ID of the mark element that is associated with the submitted input
markId = "mark" + id,
// This is the mark element assocaited with the submitted input
mark = document.getElementById(markId);
if (input.value == "") {
alert("You must type an answer!");
}
// Since we have assigned the answers to an object, and gave each of the answers indexes to match the input ids, we can find the answer by that
else if (input.value == answer[id]){
mark.innerHTML = "<img src='correct.jpg'>";
} else {
mark.innerHTML = "<img src='incorrect.jpg'>";
}
}
</script>
</head>
<body>
<form NAME="E1a" accept-charset="ISO-8859-1" onReset="return confirm('Clear entries? Are you sure?')">
<HR>
<H3>
translate, remembering punctuation and capitalisation...
</H3>
<table>
<tr>
<td>1. The mouse is white.</td>
<!-- Gave input ID of "Q1" -->
<td><input TYPE="TEXT" NAME="Q1" SIZE=50 MAXLENGTH=50 id="Q1"></td>
<!-- Changed id to class, since it is non-unique -->
<td><input TYPE="button" class="check_button" value="check..." NAME="B1" onClick="itemfeedback('Q1')"></td>
<!-- We will give this an ID that can be associated with it's related inputs name attribute -->
<td id="markQ1"></td>
</tr>
<tr>
<td>2. Good-bye!</td>
<!-- Gave input ID of "Q2" -->
<td><input TYPE="TEXT" NAME="Q2" SIZE=50 MAXLENGTH=50 id="Q2"></td>
<!-- Passed ID to onChange handler, instead of index. Also hanged id to class, since it is non-unique -->
<td><input TYPE="button" class="check_button" value="check..." NAME="B2" onClick="itemfeedback('Q2')"></td>
<!-- We will give this an ID that can be associated with it's related inputs name attribute -->
<td id="markQ2"></td>
</tr>
</table>
<hr>
<input TYPE="RESET" id="reset_fields" value="Clear Entries">
</center>
</form>
</body>
</html>
EDIT for Form Reset
Place this function to remove images from form onReset:
<!-- We are now calling a function to be executed, and the returned value of the function will determine if the form itself is cleared. A negative blue will not, a positive value will -->
<form NAME="E1a" accept-charset="ISO-8859-1" onReset="return clearForm(this)">
function clearForm (form) {
// Get option that is pressed
var clear = confirm('Clear entries? Are you sure?');
// If positive option is clicked, the form will be reset
if (clear) {
// This will select all images within the document
var markImgs = document.getElementsByTagName('img');
// Iterates through each image, and removes it from the dom
while (markImgs[0]) markImgs[0].parentNode.removeChild(markImgs[0])
}
return clear;
}
(I know the questions is a bit long but I do believe solution is easy, so would really appreciate it if someone can help me have a look)
I am trying to write a school system, where you can enter a student's name, year, grade, on a webpage, and save the student's info to produce a list. I would like it to have two "buttons" on the webpage:
One is "save and next", i.e. if you finished entering one student info, click this, the info get saved and the webpage renew to enter the next student info.
Second is "save and finish", i.e. if this is the final student you want to enter, click this and the last student info get saved, and webpage is redirected to the next page where it shows a list of all student info.
To achieve this, in JSP, I used two HTML forms, and one of them I used javascript to try to submit to servlet, But I must have done something wrong because it does not work properly:
Here are my codes:
InputGrade.jsp:
<html>
<head>
<title>Title</title>
</head>
<body>
The first form: used input labels for users to enter info, also used input label to create a submit button "save it next":
<form action = "InputGradeServlet" method="POST">
<table>
<tr>
<td>
Enter Student Name: <input type="text" id="stName" name = "stName" />
</td>
<td>
Enter Subject: <input type="text" id="Subject" name = "Subject" />
</td>
<td>
Enter Grade: <input type = "text" id="Grade" name = "Grade" />
</td>
<td>
<input type="submit" value="save and next"/>
</td>
</tr>
</table>
<input type="text" name = "flag" style="display: none" value="1"/>
</form>
The second form include the "save and finish" button, but use javascript to submit the information: (I think where the problem is)
User still enter student info in the first form, but the javascript function use getElementById function to acquire the info in first form
<form name="form2" action ="InputGradeServlet" method="POST" >
<input type="text" name = "flag" style="display: none" value="2"/>
<button onclick="finSaveFunc()">Finish and submit</button>
<script>
function finSaveFunc() {
var stName = document.getElementById("stName")
var Subject = document.getElementById("Subject")
var Grade = document.getElementById("Grade")
document.stName.submit();
document.Subject.submit();
document.Grade.submit();
}
</script>
And in the Servlet, a list created to add the students the user entered
public class InputGradeServlet extends HttpServlet {
List<Student> inputStList = new <Student>ArrayList();
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if user press "save and next" button, form one is submitted, and servlet do the action of saving student to the list and redirect to the same JSP file i.e. redirect the the same webpage again of entering the next student:(also might be problematic)
if (request.getParameter("flag").equals("1")) {
request.getParameter("Grade");
...... (get other info: name, year ect)
inputStList.add(findstudent); //add student entered to the list
response.sendRedirect("InputGrade.jsp");
}
}
}
If user press "save and finish", i.e. submitting the second form, and servlet again add the final student entered to the list and redirect to the next webpage showing the whole list:
}else if (request.getParameter("flag").equals("2")) {
request.getParameter("Grade");
....
inputStList.add(findstudent);
request.getSession().setAttribute("inputStList",inputStList);
response.sendRedirect("ShowList.jsp"); }
This is where it gets problematic: when submitting the first form hitting "save and next" button it works fine, but when submitting the second from hitting "save and finish" button, it returns error.
Therefore I would really appreciate it if some can help me have a look?
There are many reason that's why you can get a NullpointerException.
Rule of Thumbs : If you want to compare a string then first check if it is not null.
According to your requirement I am giving a solution that how can you do that.
Suppose your form be like:
<html>
<head>
<script>
function _submit(flagVal) {
document.getElementById('flagValId').value=flagVal;
document.getElementById('someFormId').submit();
}
</script>
</head>
<body>
<form action = "InputGradeServlet" method="POST" id="someFormId">
<table>
<tr>
<td>
Enter Student Name: <input type="text" id="stName" name ="stName" />
</td>
<td>
Enter Subject: <input type="text" id="Subject" name = "Subject" />
</td>
<td>
Enter Grade: <input type = "text" id="Grade" name = "Grade" />
</td>
<td>
<input type="button" value="save and next" onclick="_submit('1')"/>
<input type="button" value="save and exit" onclick="_submit('2')"/>
</td>
</tr>
</table>
<input type="hidden" id="flagValId" name = "flag" value=""/>
</form>
</body>
</html>
Now when you click save and next button, then it set flagVal 1 and if we click save and exit button then it sets flagVal 2. After setting the flagVal it submits the form. After submitting your from you should check first that what is your flagVal. So in doPost method
if (request.getParameter("flag")!=null && request.getParameter("flag").equals("1")) {
//Add your student in this block and show the input page again.
response.sendRedirect("InputGrade.jsp");
}else if (request.getParameter("flag")!=null && request.getParameter("flag").equals("2")) {
//Add your student in this block and show the list.
response.sendRedirect("ShowList.jsp");
}
Hope that helps.
You don't get form1 values. You post form2 values so you get null error.
Try it please:
function finSaveFunc() {
var stName = document.getElementById("stName")
var Subject = document.getElementById("Subject")
var Grade = document.getElementById("Grade")
var newForm = document
.getElementById("form2")
.appendChild(stName)
.appendChild(Subject)
.appendChild(Grade);
newForm.submit();
}
I have a webpage written in C#/Razor. I am printing all the values from a database on this page like so :
<div style="min-height: 150px; font-size: 1.25em">
<div style="margin-bottom: .5em">
<table>
<thead>
<tr>
<th>Name</th>
<th>Branch</th>
<th>Phone No.</th>
<th>Extension</th>
<th>Email</th>
</tr>
</thead>
<tbody>
#foreach (var prod in Model)
{
<tr>
<td>#prod.FullName</td>
<td>#prod.Branch</td>
<td>#prod.PhoneNo</td>
<td>#prod.Extension</td>
<td>#prod.Email</td>
#if (User.IsInRole(#"Admins") || User.Identity.Name == prod.DomainAC)
{
<td>edit</td>
}
else
{
<td>User => #User.ToString()</td>
}
<td>
<input type="checkbox" name="message" value="#prod.PhoneNo">Message<br>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
This works fine to display their info. What I would like to do now is a small bit more difficult.
Below this, I have a form with a username, password and message. Using this form, I would like to have the behaviour that on submit, it will take the values in the input boxes of the form and the above C#, construct a link, navigate to the link and print the response of the server
So I have :
#{if (IsPost)
{
//handle and print response
}
else
{
<form method="post" action="">
Username:<br />
<input type="text" name="u" /><br />
Password<br />
<input type="text" name="p" /><br />
<br />
Password<br />
<textarea name="m" cols="25" rows="5">
Enter your comments here...
</textarea><br>
<br />
<input type="submit" value="Submit" class="submit" />//when this is clicked, construct url and navigate to it.
</form>
}
}
The URL I want to construct from this form is :
http://webaddress.com/web/d.php?u=<Username entered by user>&p=<Password entered by user>&s=<List of Phone Numbers from the C# above where the checkbox is selected, comma separated>&m=<Comment submitted by user>
So, if my name is "John", Password is "Password1", Comment is "Test" and I have selected one checkbox for a user with the phone number "12345678", the URL I will navigate to is :
http://webaddress.com/web/d.php?u=John&p=Password1&s=12345678&m=Test
Ideally I would like to print the response of the webpage in a <div> while still on the same parent web page rather than going to a new one if this is possible.
I have no idea where to begin with this, how to do it or even if this is possible. Can anyone help me please ?
UPDATE :
Trying this JQuery which does not alert me so I cannot debug :
<script>
$("#thebutton").click(function() {
var form = $(document.getElementById('FormID'));
var urlToConstruct = 'http://webaddress.com/web/d.php';
urlToConstruct += '?u=' + form.find('#u').val();
urlToConstruct += '&p=' + form.find('#p').val();
('#employeeTable tbody tr').has(':checkbox:checked').find('td:eq(2)').each(function() {
urlToConstruct.append($(this).text());
alert(urlToConstruct);
})
});
</script>
$("#SubmitButtonID").click(function() {
var form = $(document.getElementById('FormID');
var urlToConstruct = 'http://webaddress.com/web/d.php';
urlToConstruct += '?u=' + form.find('#iDoFInputControl1').val();
urlToConstruct += '&p=' + form.find('#iDoFInputControl2').val();
form.submit();
});
this example uses jQuery, a javascript library (jquery.com), i'm using getElementById to find your form, faster then the native jQuery() selector. This example assumes all your controls are inside your form (but if they are not it wouldn't be a train smash, just cant use (jQuery obj).find).
.val() gets the value, and it should work for checkboxes too, but if it doesn't, a quick google search for getting values from checkboxes using jquery will return loads of results.
p.s. I've written that code mostly freehand, not checked it in a browser to make sure that it is completely correct.
Update... to answer your follow up question...
If you are using mvc (assumed as you using razor), inside your controller you can use Request.Params["urlParameter"] or Request.Form["controlID"] to access what you've received from the browser. Then once you've got those values, you should place them inside the 'ViewBag' (ViewBag.yourVariableHere="val") for them to be accessible in your view via #ViewBag.yourVariableHere, or you can include the required data in your model which can also be accessed in your view
I have an HTML table with dynamically generated rows (using MVC3's EditorFor). Users fill in the data in the table (row by row), then submit the form to the server (via MVC3 HTML form). Users can delete a row by pushing a button that calls $(tableRow).remove() on the TR element, and then calls an async server method that removes the row from the database.
I've found that if I have say 5 rows in my table and I delete the third one then submit, the server method receives rows 1 and 2, but looses the other rows (the original 4th and 5th rows).
I've tried searching online as to why the postback would receive the first two rows and miss the last two, but all the answers I could find revolved around JQuery posts, which I'm not using.
Any help or direction would be great, please let me know if I need to clarify anything.
EDIT: adding code from my project that applies to the question. if you need more code for context, let me know and I'll add it.
//////////////// VIEW ////////////////
// model info and initialization logic
#using (Html.BeginForm("EditTimesheet", "ControllerName", FormMethod.Post, new { enctype = "multipart/form-data", id = "editTimesheet" }))
{
#Html.ValidationSummary(true)
<fieldset>
<table width="100%">
<tr>
<td colspan="14" align="right">
// lots of code
</td>
</tr>
#Html.EditorFor(m => m.Rows)
<tr>
<td colspan="14" align="right">
// lots of code
</td>
</tr>
// closing statements
//////////////// EditorFor ////////////////
// model info and initialization logic
<tr class="timesheet-row">
<td>
<a href='#'>
<img src='#Url.Content("~/Content/Images/delete.gif")'
width='17' height='17' style='border: 0;'
onclick="DeleteRow(this, #Model.RowId)" />
</a>
</td>
// other td's
</tr>
//////////////// JS file ////////////////
function DeleteRow(box, rowId)
{
$(box).closest(".timesheet-row").remove();
// HACK: despicable, detestable HACK!
var url = deleteRowUrl;
url += '?rowId=' + rowId;
var ajaxData = {
type: "POST",
url: url,
dataType: "json",
contentType: "application/json; charset=utf-8",
data: null,
success: null,
error: function (error) {
alert("There was an error posting the data to the server: " + error.responseText);
}
};
$.ajax(ajaxData);
}
When you delete a row you are creating holes in the indexes of the names in the collection and the default model binder stops working because you no longer respect the expected format.
So instead of having the following sequential values:
<input type="text" name="Items[0].Id" value="1" />
<input type="text" name="Items[1].Id" value="2" />
<input type="text" name="Items[2].Id" value="3" />
<input type="text" name="Items[3].Id" value="4" />
<input type="text" name="Items[4].Id" value="5" />
if you delete the third row with $(tableRow).remove() on the TR element you end up with:
<input type="text" name="Items[0].Id" value="1" />
<input type="text" name="Items[1].Id" value="2" />
<input type="text" name="Items[3].Id" value="4" />
<input type="text" name="Items[4].Id" value="5" />
See the problem?
Here's an article which illustrates how to solve this problem by using a custom helper called Html.BeginCollectionItem and which uses GUIDs in the names of the input fields for the collection instead of integer indexes. Also checkout Phil Haacks article about the syntax that the default model binder expects your fields to be named. There's a section towards the end which is called Non-Sequential Indices in which he covers how this could be done.
Sounds like part of your form is being deleted.
Inspect the DOM
find your form
delete a row and see what changes
I want to know how to read the DropDown list value from the JSP. Below is the code of my JSP.
<fieldset>
<s:form theme="simple" enctype="multipart/form-data" name="uploadDocument" method="POST" action="?">
<table>
<tr>
<td wrap>Select The Type of Letter to Upload:</td><td><s:select id="letters" list="letterList" name="ListofLetters" headerKey="-1" headerValue="--Select The Letter Type--"/></td>
<tr>
<td nowrap ><s:file name="userFile" label="userFile" size="25" id="upload" /></td>
<td class="button-blue"><s:submit action="Upload" value="Attach File" onclick=" return validateFile()"/></td>
</tr>
</table>
</s:form>
</fieldset>
where the list is populated dynamically from the Database.I wanted to know how to get the Dropdownlist value not the key.
Because when i used
document.getElementById('letters').value
It returns me the keyvalue like "0,1,2 etc" how can i get the value associated with the individual key so i can perform the proper check.
Thanks in Advance :)
Use this to get the currently selected option's text:
var sel = document.getElementById('letters');
var selText = sel.options[sel.selectedIndex].text;
Fiddle
document.getElementById('letters').value; // returns the value ie 1 / 2 / 3 etc
var dropdown=document.getElementById('letters');
dropdown.options[dropdown.selectedIndex].text; // returns the text
Hope this helps.