I am trying to submit dynamic form data to spring controller using ajax so that i could save list of object later to the database. Everything is set but i am not able to handle dynamic form data in the ajax part. The problem is how to create the javascript object for each row of table and post those objects as JSON data.
All the code is like this:
HTML
<html>
<head>
<title>Add Students</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
</head>
<body>
<div class="container">
<div class="form-group">
<form id="student_detail" name="student_detail">
<table class="table table-bordered" id="student_dynamic_table">
<tr>
<td><input type="text" name="name[]" id="name" placeholder="Enter Name" class="form-control name_list" /></td>
<td><input type="text" name="age[]" id="age" placeholder="Enter Age" class="form-control age_list" /></td>
<td><button type="button" name="add" id="add" class="btn btn-success">+</button></td>
<tr>
</table>
<input type="button" class="btn btn-info" id="submit" name="submit" value="Submit" />
</form>
</div>
</div>
</body> </html>
JS
$(document).ready(function(){
var i=0;
$('#add').click(function(){
i++;
$('#student_dynamic_table').append('<tr id="row'+i+'"> <td><input type="text" name="name[]" id="name'+i+'" placeholder="Enter Name" class="form-control name_list" /></td><td><input type="text" name="age[]" id="age'+i+'" placeholder="Enter Age" class="form-control age_list" /></td><td><button type="button" name="remove" id="'+i+'" class="btn btn-danger btn_remove">x</button></td><tr>');
});
$(document).on('click','.btn_remove', function(){
var button_id=$(this).attr("id");
//id of the clicked button
$('#row'+button_id+'').remove();
});
$('#submit').click(function(){
var url= "${pageContext.request.contextPath}";
var student = ({
name : $('#name').val(),
age : $('#age').val()
});
$.ajax({
type : "POST",
url : url + '/submitDynamicForm',
data:JSON.stringify( student),
dataType : 'json',
contentType : 'application/json',
success : function(response)
{
}
}); }); });
Controller
#Autowired
private StudentDao studentDao;
#RequestMapping(value = "/dynamic", method = RequestMethod.GET)
public ModelAndView geDynamicForm() {
ModelAndView form = new ModelAndView("dynamicform");
return form;
}
#RequestMapping(value = "/submitDynamicForm", method = RequestMethod.POST)
public void saveUser(#RequestBody List<Student> student) {
studentDao.insertListOfStudent(student);
} }
Model
#Entity
public class Student {
#Id
#GeneratedValue
private Long id;
#Column(name = "name")
private String name;
#Column(name = "age")
private int age;
// getters setters
}
Hibernate to insert list of students
#Transactional
public void insertListOfStudent(List<Student> student) {
Session session = sessionFactory.getCurrentSession();
for(Student std : student) {
session.save(std);
}
Thank You in advance
var totalRow=$('#student_dynamic_table tr').length; // last row count
var data={}; //object
for (i = 0; i < totalRow; i++) {
data[$("#row"+i).val()] = $("#age"+i).val(); // adding value to data object which will be in key value format({"ram:"21","hari":"25"})
}
data: { "jsonData": JSON.stringify(data) }, // on your ajax data submit
so now in you controller you can get the data with .key() and .value() but make sure you parse with JSON.parse before .
Related
I have this problem where I try to have an AJAX call to post data the user put in on the webpage to the controller method. The data never arrives at the controller, it always throws an error. The problem is probably that the data the controller expects is not of the same type as what the AJAX call sends to it, but I am really at a loss at what the expected data should look like.
Here's the JS/jQuery that builds the array, which is an array of an array of a table cell's values:
var i = 0;
var cells = new Array(); // cell values in one column
var rows = new Array(); // list of columns (rows)
$('#datatable').find('tr').each(function () {
$('td :not([type="button"],[id="Nr."])', this).each(function () {
cells.push($(this).val());
});
if (i > 0) {
rows.push(cells);
cells = [];
}
i++;
});
this is what the AJAX call looks like:
rows = JSON.stringify({ 'rows': rows });
$.ajax({
url: "/Home/Q_FourthPage",
type: "POST",
datatype: "json",
traditional: true,
data: rows,
success: function (response) {
alert("Success");
console.log("Sucess ", response);
},
error: function (response) {
alert("Error");
console.log("Error ", response);
}
});
The controller is still empty - what parameter should it get in order for the data to arrive as an array of an array of strings/integers/whatever? Thank you.
Edit: This is the view model the Q_FourthPage controller method uses:
public class Q4_Answer_VM
{
public Models.User User { get; set; }
public List<Models.Capacity> Matrix { get; set; } //this is where the data should go
//a capacity describes one row of the table
public Models.QuestionText TMatrix { get; set; }
}
The capacity class looks like this - it is one row of the table.
public class Capacity
{
// This class is a model for the capacity matrix. it represents one column.
//PK
public int ID { get; set; }
//FK
public int Questionnaire_ID { get; set; }
//Values
public String Load { get; set; }
public String Source { get; set; }
public String Goal { get; set; }
public String Frequency { get; set; }
public String Distance { get; set; }
public virtual Questionnaire Questionnaire_ { get; set; }
}
Here's the head of the controller method:
[HttpPost]
public ActionResult Q_FourthPage(ViewModels.Q4_Answer_VM vm)
There are a lot of attributes in these classes - is that why the call fails?
Edit No. 2: The view
Here's the view:
#model MyANTon.ViewModels.Q4_Answer_VM
#{
ViewBag.Title = "myANTon Anforderungserfassung";
ViewBag.HideNavBar = false;
}
#using (Html.BeginForm(Html.BeginForm("Q_FourthPage", "Home", FormMethod.Post, new { enctype = "multipart/form-data" })))
{
<div class="container">
<div align="center">
<ol class="breadcrumb" align="center" text-align="center">
<li class="breadcrumb-item">#Html.ActionLink("Lasten", "Q_Firstpage", "Home", new { #class = "elements" }, null)</li>
<li class="breadcrumb-item">#Html.ActionLink("Lastaufnahme-/abgabe", "Q_Secondpage", "Home", new { #class = "elements" }, null)</li>
<li class="breadcrumb-item">#Html.ActionLink("Weitere Anforderungen", "Q_Thirdpage", "Home", new { #class = "elements" }, null)</li>
<li class="breadcrumb-item"><b><u>#Html.ActionLink("Kapazitäten", "Q_Fourthpage", "Home", new { #class = "elements" }, null)</u></b></li>
<li class="breadcrumb-item">#Html.ActionLink("Auftragserzeugung", "Q_Fifthpage", "Home", new { #class = "elements" }, null)</li>
</ol>
</div>
<div class="jumbotron">
<div>
#Html.TextBox("file", "", new { type = "file" }) <br />
<input type="submit" value="Upload" />
#ViewBag.Message
</div>
<h1>4. Kapazitätsbetrachtung</h1>
<p>Wie viele Fahrzeuge werden benötigt? Um dies auszurechnen wird eine Transportmatrix benötigt.</p>
<p>Ein Beispiel einer Transportmatrix ist in Tabelle 1 zu sehen.</p>
<p>Um die Anzahl der Roboter zu berechnen ist auch eine Angabe der Produktionsschichten relevant:</p>
<ul>
<li>In wie vielen Schichten läuft die Fertigung?</li>
</ul>
<p>
Um mögliche Engpässe oder Umwege zu betrachten ist ein Layout der Produktionsstätte wie in Abbildung 3 von Vorteil.
Idealerweise mit Angaben über andere Verkehrsteilnehmer (Personenverkehr, Staplerverkehr, Kreuzungen).
</p>
<input type="button" id="BtnPlus" name="BtnPlus" class="BtnPlus" value="Zeile hinzufügen (+)" align="center" style="vertical-align: middle" />
<table class="grid" id="datatable" style="table-layout:fixed">
<thead>
<tr style="text-align: center" id="header">
<th style="vertical-align: middle" id="Nr.">Nr.</th>
<th>Last</th>
<th>Quelle</th>
<th>Ziel</th>
<th>Frequenz [/h]</th>
<th>Abstand [m]</th>
<th>Zeile löschen</th>
</thead>
<tbody></tbody>
</table>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" name="Speichern" value="Speichern" id="BtnSave" />
<input type="submit" class="btn btn-default" name="Speichern und weiter" value="Speichern und weiter" />
<input type="button" class="btn btn-default" value="Weiter zu Schritt 5" onclick="#("window.location.href='" + #Url.Action("Q_Fifthpage", "Home") + "'");" />
</div>
</div>
</div>
</div>
}
<script src="~/Scripts/jquery-3.2.1.js"></script>
<link rel="stylesheet" type="text/css" href="//cdn.datatables.net/1.10.16/css/jquery.dataTables.css">
<script type="text/javascript" charset="utf8" src="//cdn.datatables.net/1.10.16/js/jquery.dataTables.js"></script>
#Scripts.Render("~/bundles/datatables")
Edit no. 3: it works now thanks to the solution provided by user derloopkat below. As a hint: it seems that Ajax and Forms don’t go well together. I had to move the “save” button outside the form (#using...{}).
This worked. The thing is creating an object in json matching the exact names and structure in your model. You don't need to have all members in your json but those who appear should match the model if you want to be able to retrieve their values at server.
var capacities = new Array(); // cell values in one column
$('#datatable').find('tr').each(function () {
var cells = $(this).find('td :not([type="button"],[id="Nr."])');
var capacity = {
Load: cells[0].value,
Source: cells[1].value,
Goal: cells[2].value,
Frequency: cells[3].value,
Distance: cells[4].value
};
capacities.push(capacity);
});
In your Ajax call, dataType is what you expect to get from server, not the type you're sending (that is contentType).
var model = JSON.stringify({ 'Matrix': capacities });
$.ajax({
url: "/Home/Q_FourthPage",
type: "POST",
contentType: "application/json; charset=utf-8",
traditional: true,
data: model,
success: function (response) {
alert("Success");
console.log("Sucess ", response);
},
error: function (response) {
alert("Error");
console.log("Error ", response);
}
});
My table was dummy Html.
<table id="datatable">
<tr>
<td><input type="text" value="11" /></td>
<td><input type="text" value="12" /></td>
<td><input type="text" value="13" /></td>
<td><input type="text" value="14" /></td>
<td><input type="text" value="15" /></td>
</tr>
<tr>
<td><input type="text" value="21" /></td>
<td><input type="text" value="22" /></td>
<td><input type="text" value="23" /></td>
<td><input type="text" value="24" /></td>
<td><input type="text" value="25" /></td>
</tr>
</table>
And action method is:
[HttpPost]
public ActionResult Q_FourthPage(ViewModels.Q4_Answer_VM vm)
{
return View("Index");
}
If you intend to return json from here, then you need to adddataType: 'json' in Ajax call.
I am still new in AngularJS and I want to create a form that allow me to upload an image and save it to a database and view it on a html page.
.asmx File
public void AddCard(int id, string cName, string cCoName, string cTpNmbr, string cEmail, string cAddress, string cStatus,string cScan)
{
string cs = ConfigurationManager.ConnectionStrings["DBCS"].ConnectionString;
using (SqlConnection con = new SqlConnection(cs))
{
byte[] cScan = File.ReadAllBytes(imageFilePath);
SqlCommand cmd = new SqlCommand("Insert into tblCards(Id, Name, CoName, TpNmbr, Email, Address, Status, Scan) values('"+id+"','"+cName+"', '"+cCoName+"','" +cTpNmbr+"', '"+cEmail+"', '"+cAddress+"', '"+cStatus+"',#cScan)", con);
SqlParameter param = cmd.Parameters.AddWithValue("#cScan", cScan);
param.DbType = DbType.Binary;
con.Open();
cmd.ExecuteNonQuery();
}
}
.html File
<form>
<fieldset>
<legend> ADD CARD / EDIT CARD </legend>
<p> ID : <input type="text" ng-model="cards.id" /></p>
<p>Name : <input type="text" ng-model="cards.cName" /></p>
<p>Co. Name :<input type="text" ng-model="cards.cCoName" /></p>
<p>Tp. Number : <input type="text" ng-model="cards.cTpNmbr" /></p>
<p>Email : <input type="text" ng-model="cards.cEmail" /></p>
<p>Address : <textarea ng-model="cards.cAddress"></textarea></p>
<p>Status : <input type="text" ng-model="cards.cStatus" /></p>
<p>Card Scan : <input type="file" ng-model="cards.cScan" /></p>
<button type="button" class="btn btn-primary" ng-click="addCard(cards)"> Add Card </button>
<button type="button" class="btn btn-primary" ng-click="editCards(cards)"> Edit Card </button>
<button type="reset" class="btn btn-primary"> Reset Form </button>
</fieldset>
</form>
AngularJS File
$scope.addCard = function (card) {
var id = card.id
var cName = card.cName;
var cCoName = card.cCoName;
var cTpNmbr = card.cTpNmbr;
var cEmail = card.cEmail;
var cStatus = card.cStatus;
var cAddress = card.cAddress;
var cCount = card.cCount;
var cScan = card.cScan;
cCount = 0;
$http({
url: 'CardServices.asmx/AddCard',
params: {
id: id,
cName: cName,
cCoName: cCoName,
cTpNmbr: cTpNmbr,
cEmail: cEmail,
cStatus: cStatus,
cAddress: cAddress,
cScan:cScan
},
method: 'GET'
}).then(function (response) {
GetAllCards();
alert("Card Added to Database!");
});
}
I looked up online and I've tried to use the code but it seems like it is
not working.
Thanks in advance
I want to read the file name while uploading and rename it,save it to a path. For uploading the file I am using an upload image placed in a table. I am using -
#using (Html.BeginForm("file", "Admin", FormMethod.Post, new { enctype = "multipart/form-data" }))
to read the file name and the row values. But the issue is it reads the value of only first row whereever I click. Here is my code -
HTML -
<div>
#using (Html.BeginForm("file", "Admin", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<table>
<tr ng-repeat = "{{data in list}}">
<td>{{data.Name}}</td>
<td>{{data.Id}}</td>
<td>
<label for="file">
<i class="fa fa-upload" id="hello" aria-hidden="true" >
</i>
</label>
<input type="file" name="file" id="file" onchange="this.form.submit();" />
<input type="text" name="Name" id="Name" />
<input type="text" name="Id" id="Id" />
</td>
</tr>
</table>
}
</div>
Controller -
public ActionResult file(HttpPostedFileBase file, string Name, string Id)
{
if (file != null && file.ContentLength > 0)
{
string fileName = file.FileName;
string newName = Name;
string fileId = Id;
}
else
{
ViewBag.Message = "You have not specified a file.";
}
return View("UploadPage");
}
Atpresent this is working but when I click on any upload image button, it only takes the first row Name and Id. I am not able to fix it. Please help.
Thanks
you are getting first row because when this.form.submit(); event triggers it will submit the form with all the rows in it and in action its just HttpPostedFileBase not List<HttpPostedFileBase> so it will get the data of first row because it will match the parameter. so one solution is you do
public ActionResult file(List<HttpPostedFileBase> file, List<string> Name, List<string> Id)
{
for (int i = 0; i < file.Count; i++)
{
var name = Name[i];
}
}
and a better way is to use a class
public class UploadFiles
{
public HttpPostedFileBase File { get; set; }
public string Name { get; set; }
public int Id { get; set; }
}
and your view will be
<div>
#using (Html.BeginForm("file", "Admin", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<table>
<tr ng-repeat = "{{data in list}}">
<td>{{data.Name}}</td>
<td>{{data.Id}}</td>
<td>
<label for="file">
<i class="fa fa-upload" id="hello" aria-hidden="true" >
</i>
</label>
<input type="file" name="files[{{$index}}].File" id="file" />
<input type="text" name="files[{{$index}}].Name" id="Name" />
<input type="text" name="files[{{$index}}].Id" id="Id" />
</td>
</tr>
</table>
<button type="submit" >Upload All</button>
}
</div>
and in your action
public ActionResult AddAuto(List<UploadFiles> files)
{
foreach (var file in files)
{
// here you can access properties e.g file.File
}
}
I'm using Spring MVC for my application. I have a form for receiving start date and end date from daterangepicker. And I want to display another view, that has a table after querying, into the "dataDiv" below the form after submitting the form, but not reload the page.
What I've done so far, the result is when I submitted a form, it redirected to new page (request-data.jsp) but the table worked fine.
Here are my code...
JSP
<form action="view-data" method="get" id="ajaxTest">
<div id="reportrange" class="form-control">
<i class="fa fa-calendar"></i>
<span></span>
<b class="caret"></b>
</div>
<input type="hidden" id="startDate" name="startDate" />
<input type="hidden" id="endDate" name="endDate" />
<input type="submit" value="VIEW" id="ajaxBtn" />
</form>
<div id="dataDiv"></div>
Javascript I used Ajax for loading another view.
$('#ajaxTest').submit(function(event) {
var startDate = $('#reportrange').data('daterangepicker').startDate;
var endDate = $('#reportrange').data('daterangepicker').endDate;
document.getElementById("startDate").value = startDate;
document.getElementById("endDate").value = endDate;
$.ajax({
url : "../request-data",
type : 'GET',
data : data,
success : function(response) {
alert("success");
$('#dataDiv').html( response );
},
error : function() {
alert("error");
}
});
return false;
});
Spring Controller
#RequestMapping(value = "/request-data", method = RequestMethod.GET)
public ModelAndView requestRanking(HttpServletRequest httpRequest, #RequestParam("startDate") Date stDate, #RequestParam("endDate") Date edDate, RedirectAttributes rd) {
ModelAndView mav = new ModelAndView();
/*
*Query for book created between stDate and edDate
*/
rd.addFlashAttribute("bookForms", bookForms);
mav.setViewName("request-data");
return mav;
}
And in request-data.jsp view
$(document).ready(function() {
$('.footable').footable();
});
<div>
<c:if test="${!empty bookForms}">
<input type="text" class="form-control input-sm m-b-xs" id="filter" placeholder="Search in table" />
<table id="page-size-example" class="footable table table-stripped" data-page-size="" data-filter=#filter data-sorting="true">
<thead>
<tr>
<th data-type="numeric" data-sort-initial="true">#</th>
<th>BOOKNAME</th>
<th>PRICE</th>
<th>CREATED_DATE</th>
</tr>
</thead>
<tbody>
<c:forEach items="${bookForms}" var="bookForm" varStatus="status">
<tr>
<td>${status.count}</td>
<td>${bookForm.name}</td>
<td>${bookForm.price}</td>
<td>${bookForm.createdDate}</td>
</tr>
</c:forEach>
</tbody>
</table>
</c:if>
</div>
Is there any other way to do this? Please help me out. Thanks
I found a solution for you how to use spring4 #RestController to return a jsp page?
You should add a #ResponseBody annotation to your method or #RestController to your class if every method works with ajax. This annotations make your controllers/methods to work async with ajax.
Some code
#RequestMapping(value = "/request-data", method = RequestMethod.GET)
#ResponseBody
public ModelAndView requestRanking(HttpServletRequest httpRequest, #RequestParam("startDate") Date stDate, #RequestParam("endDate") Date edDate, RedirectAttributes rd) {
ModelAndView mav = new ModelAndView();
mav.setViewName("request-data");
//your actions
return mav;
}
I want to receive a formdata as a parameter in actionresult, i don't want to covert into FormData(), and Use Request.Form in action Result, cant i receive data directly, without FormData(), here is what I've tried till now ...
<form ng-show="divPatient" name="PatientForm" ng-submit="AddUpdatePatient()">
<table>
<tr>
<td>
<input class="form-control" type="text" readonly placeholder="Key (Automatic)" ng-model="model.PatientID" />
</td>
<td>
<input name="FirstName" class="form-control" type="text" placeholder="FirstName" ng-model="model.FirstName" ng-minlength="3" required />
</td>
<td>
<input name="LastName" class="form-control" type="text" placeholder="LastName" ng-model="model.LastName" ng-minlength="3" required />
</td>
<td>
<input class="form-control" type="text" placeholder="Disease" ng-model="Disease" name="model.Disease" ng-minlength="3" required />
</td>
<td>
<input class="form-control" type="number" placeholder="Phone No." ng-model="model.PhoneNo" name="PhoneNo" ng-pattern="/^[789]\d{9}$/" required />
</td>
<td>
<input type="file" onchange="angular.element(this).scope().selectFileforUpload(this.files)" ng-model="model.PhotoURL" value="" class="form-control profilePic" required/>
</td>
<td colspan="2" class="saveCancel">
<input type="submit" value="save" class="btn btn-success" ng-disabled="PatientForm.PhoneNo.$dirty && PatientForm.PhoneNo.$invalid || PatientForm.LastName.$dirty && PatientForm.LastName.$invalid || PatientForm.FirstName.$dirty && PatientForm.FirstName.$invalid || PatientForm.Disease.$dirty && PatientForm.Disease.$invalid" />
<input type="button" value="cancel" class="btn btn-primary" ng-click="CancelForm()" />
</td>
</tr>
<tr>
<td></td>
<td><span class="eror-text" ng-show="PatientForm.FirstName.$error.minlength">min 3 letters</span></td>
<td><span class="eror-text" ng-show="PatientForm.LastName.$error.minlength">min 3 letters</span></td>
<td><span class="eror-text" ng-show="PatientForm.Disease.$error.minlength">min 3 letters</span></td>
<td><span class="eror-text" ng-show="PatientForm.PhoneNo.$error.pattern">Invalid phone no</span></td>
</tr>
</table>
</form>
My controller in angularJS
app.controller("StudentCtrl", function ($scope, angularService) {
$scope.model = {};
$scope.AddUpdatePatient = function () {
var getData = angularService.AddPatient($scope.model);
getData.then(function (msg) {
alert(msg.data);
}, function () {
alert('Error in adding record');
});
}
}
My Service in angularJS
app.service("angularService", function ($http) {
// Add Employee
this.AddPatient = function (patientData) {
var response = $http({
withCredentials: true,
headers: { 'Content-Type': undefined },
transformRequest: angular.identity,
method: "post",
url: "AddPatient",
data: patientData,
dataType: "json"
});
return response;
}
}
And my action result
public string AddPatient(Patient patientData) {
//but patientdata fields are all null
}
my MVC Model
using ...
namespace WebApplication3.Models
{
public class Patient
{
public int PatientID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public long PhoneNo { get; set; }
public string Disease { get; set; }
public string PhotoURL { get; set; }
}
}
I wonder why that patientData in action Result is null ??
Try this
$http({ method: 'POST', url: '/ControllerName/AddPatient', data: patientData }).
success(function (data, status, headers, config) {
}).
error(function (data, status, headers, config) {
alert(status);
});