Jquery ajax form submit that contains files - ajax

I have a very long form that contains files attachment:
this is how my form looks like:
The form will be submitted to this action:
[HttpPost]
public ActionResult AddReceivingConfirm(DTOreceiving entry,IEnumerable<HttpPostedFileBase> fileUpload)
{
return PartialView();
}
through ajax call which is:
$(document).on('click', 'input[type="submit"].genericSubmit', function () { //generic function for ajax submit of ANY FORMS t
if (!$("form#ValidateForm").valid()) {
return false;
};
var frmData = $('.genericForm').serialize();
var frmUrl = $('.genericForm').attr('action');
$.ajax({
type: 'post',
url: frmUrl,
data: frmData,
success: function (e) {
$('#target').html(e);
}
});
return false;
});
everything is binding perfectly except the IEnumerable<HttpPostedFileBase>which always results to null,
the file part of my form is done like this:
<tr>
<td>Attachment #1: </td>
<td colspan="3">
<input id="file1" type="file" name="fileUpload" />
</td>
</tr>
<tr>
<td>Attachment #2: </td>
<td colspan="3">
<input id="file2" type="file" name="fileUpload" />
</td>
</tr>
<tr>
<td>Attachment #3: </td>
<td colspan="3">
<input id="file3 "type="file" name="fileUpload" />
</td>
</tr>
I have tried the brackets version and etc but it won't bind.
After an hour of researching, i've read that it's not possible(?) )to do file posting conventionally through the use of Ajax unless iframe. I am not sure of what my action will be, i kinda want to avoid using plugin so i wanna know if there is some "hacky" ways to access the files directly from my form?
this is my form:
using (Html.BeginForm("AddReceivingConfirm", "Wms", FormMethod.Post, new { id = "ValidateForm", #class = "genericForm" , enctype="multipart/form-data"}))

Unfortunately the jQuery serialize() method will not include input file elements. So your files are not going to be included in the serialized value.
What you should be doing is creating a FormData object, append the files to that. You need to append the form field values as well to this same FormData object. You may simply loop through all the input field and add it. Also, in the ajax call, you need to specify processData and contentType property values to false.
$(document).on('click', 'input[type="submit"].genericSubmit', function(e) {
e.preventDefault(); // prevent the default submit behavior.
var fdata = new FormData();
$('input[name="fileUpload"]').each(function(a, b) {
var fileInput = $('input[name="fileUpload"]')[a];
if (fileInput.files.length > 0) {
var file = fileInput.files[0];
fdata.append("fileUpload", file);
}
});
// You can update the jquery selector to use a css class if you want
$("input[type='text'").each(function(x, y) {
fdata.append($(y).attr("name"), $(y).val());
});
var frmUrl = $('.genericForm').attr('action');
$.ajax({
type: 'post',
url: frmUrl,
data: fdata,
processData: false,
contentType: false,
success: function(e) {
$('#target').html(e);
}
});
});

Seems like your $.ajax needs contentType: false to prevent a bad content-type header from being inserted.
Also, if I am reading the docs ( https://api.jquery.com/serialize/ ) correctly .serialize skips file inputs...
This answer also seems helpful How can I upload files asynchronously?

Related

AJAX shows different behaviors in an if/elseif-statement which is inside the success function [duplicate]

I have looked through all the similar posts out there but nothing seems to help. This is what I have
HTML:
<section>
<form id="contact-form" action="" method="post">
<fieldset>
<input id="name" name="name" placeholder="Name" type="text" />
<input id="email" name="email" placeholder="Email" type="text" />
<textarea id="comments" name="comments" placeholder="Message"></textarea>
<div class="12u">
Send Message
Clear Form
</div>
<ul id="response"></ul>
</fieldset>
</form>
</section>
JavaScript/jQuery:
function sendForm() {
var name = $('input#name').val();
var email = $('input#email').val();
var comments = $('textarea#comments').val();
var formData = 'name=' + name + '&email=' + email + '&comments=' + comments;
$.ajax({
type: 'post',
url: 'js/sendEmail.php',
data: formData,
success: function(results) {
$('ul#response').html(results);
}
}); // end ajax
}
What I am unable to do is prevent the page refresh when the #form-button-submit is pressed. I tried return false; I tried preventDefault() and every combination including return false; inside the onClick. I also tried using input type="button" and type="submit" instead and same result. I can't solve this and it is driving be nuts. If at all possible I would rather use the hyperlink due to some design things.
I would really appreciate your help on this.
Modify the function like this:
function sendForm(e){
e.preventDefault();
}
And as comment mentions, pass the event:
onclick = sendForm(event);
Update 2:
$('#form-button-submit').on('click', function(e){
e.preventDefault();
var name = $('input#name').val(),
email = $('input#email').val(),
comments = $('textarea#comments').val(),
formData = 'name=' + name + '&email=' + email + '&comments=' + comments;
$.ajax({
type: 'post',
url: 'js/sendEmail.php',
data: formData,
success: function(results) {
$('ul#response').html(results);
}
});
});
function sendForm(){
// all your code
return false;
}
I was also bit engaged in finding solution to this problem, and so far the best working method I found was this-
Try using XHR to send request to any url, instead of $.ajax()...I know it sounds bit weird but try it out!
Example-
<form method="POST" enctype="multipart/form-data" id="test-form">
var testForm = document.getElementById('test-form');
testForm.onsubmit = function(event) {
event.preventDefault();
var request = new XMLHttpRequest();
// POST to any url
request.open('POST', some_url, false);
var formData = new FormData(document.getElementById('test-form'));
request.send(formData);
This would send your data successfully ...without page reload.
Have you tried using
function sendForm(event){
event.preventDefault();
}
Simple and Complete working code
<script>
$(document).ready(function() {
$("#contact-form").submit(function() {
$("#loading").show().fadeIn('slow');
$("#response").hide().fadeOut('slow');
var frm = $('#contact-form');
$.ajax({
type: frm.attr('method'),
url: 'url.php',
data: frm.serialize(),
success: function (data) {
$('#response').html(data);
$("#loading").hide().fadeOut('slow');
$("#response").slideDown();
}, error: function(jqXHR, textStatus, errorThrown){
console.log(" The following error occured: "+ textStatus, errorThrown );
} });
return false;
});
});
</script>
#loading could be an image or something to be shown when the form is processing, to use the code simply create a form with ID contact-form
Another way to avoid the form from being submitted is to place the button outside of the form. I had existing code that was working and created a new page based on the working code and wrote the html like this:
<form id="getPatientsForm">
Enter URL for patient server
<br/><br/>
<input name="forwardToUrl" type="hidden" value="/WEB-INF/jsp/patient/patientList.jsp" />
<input name="patientRootUrl" size="100"></input>
<br/><br/>
<button onclick="javascript:postGetPatientsForm();">Connect to Server</button>
</form>
This form cause the undesirable redirect described above. Changing the html to what is shown below fixed the problem.
<form id="getPatientsForm">
Enter URL for patient server
<br/><br/>
<input name="forwardToUrl" type="hidden" value="/WEB-INF/jsp/patient/patientList.jsp" />
<input name="patientRootUrl" size="100"></input>
<br/><br/>
</form>
<button onclick="javascript:postGetPatientsForm();">Connect to Server</button>
I expect anyone to understand my idea very well as it's a very simple idea.
give your required form itself an id or you can get it by any other way you prefer.
in the form input "submit" call an onclick method from your javascript file.
in this method make a variable refer to your from id the addEventListener on it and make a preventDefault method on "submit" not on "click".
To clarify that see this:
// element refers to the form DOM after you got it in a variable called element for example:
element.addEventListener('submit', (e) => {
e.preventDefault();
// rest of your code goes here
});
The idea in brief is to deal with the form by submit event after dealing with submit button by click event.
Whatever is your needs inside this method, it will work now without refresh :)
Just be sure to deal with ajax in the right way and you will be done.
Of course it will work only with forms.
The way I approached this: I removed the entire form tag and placed all the form elements such as input, textarea tags inside a div and used one button to call a javascript function. Like this:
<div id="myform">
<textarea name="textarea" class="form-control">Hello World</textarea>
<button type="submit" class="btn btn-primary"
onclick="javascript:sendRequest()">Save
changes</button>
<div>
Javascript:
function sendRequest() {
$.ajax({
type: "POST",
url: "/some/url/edit/",
data: {
data: $("#myform textarea").val()
},
success: function (data, status, jqXHR) {
console.log(data);
if (data == 'success') {
$(`#mymodal`).modal('hide');
}
}
});
return true;
}
I thought why use a form when we are sending the actual request using AJAX. This approach may need extra effort to do things like resetting the form elements but it works for me.
Note:
The above answers are more elegant than this but my use case was a little different. My webpage had many forms and I didn't think registering event listeners to every submit button was a good way to go. So, I made each submit button call the sendRequest() function.

ASP.NET MVC partial view refresh on button click

I'm using VS 2013, MVC 5.
Here is the content of my partial view (_Sales.cshtml):
#model IEnumerable<SomeModel>
<div id="outer">
<div id="inner1">
#(Html.Kendo().Chart<SomeModel>(Model)
...
)
</div>
<div id="inner2">
<table>
<tr>
<td>Total Sales </td>
<td>#Model.First().TotalSales.ToString("C")</td>
</tr>
<tr>
<td>Total Discount </td>
<td>#Model.First().TotalDiscount.ToString("C")</td>
</tr>
</table>
</div>
</div>
Below is an action method used while loading first time:
public ActionResult _Sales()
{
IEnumerable<SomeModel> salesList = null;
SearchCriteriaObject criteria = null;
salesList = getting data as list;
return PartialView(salesList);
}
So far, all work fine as expected. That's my partial view is rendering fine with initial data.
Now my requirement is I need to refresh my partial view as user specify search criteria and hit search button.
Here is the search button specific action method:
public ActionResult Get_BulletChartData_Updated(SearchViewModel criteriaModel)
{
IEnumerable<SomeModel> salesList = null;
SearchObject criteria = new SearchObject();
if (ModelState.IsValid)
{
if (criteriaModel != null)
{
//populating criteria here
}
salesList = //Getting data in list format
}
return PartialView(salesList);
}
On search button click event handler in javascript, I do this:
$("#btnSearch").click(function () {
...
var Url = $('#Url').val(); //Getting action method url from hidden field
$.ajax({
type: "POST",
dataType: 'HTML',
data: JSON.stringify(SearchViewModel),
url: Url, //#Url.Action("Get_SalesDataFiltered", "Sales")
contentType: "application/json; charset=utf-8",
success: function (result)
{
alert('success');
//$("#outer").load(result);
},
error: function ()
{
alert("error");
}
});
On search button click, I always get error alert message.
Could you please guide me the correct way to achieve this.
I'm new to MVC. Please feel free to ask for more info.
If you provide me with code, it'd be great.
Thanks.
I think that your problem is that you post a json object, while your post method has as a parameter a SearchViewModel object.
I believe that If you change this
data: JSON.stringify(SearchViewModel)
to this
data: $("#yourFormId").serialize()
you will get the expected result.

display model contents dynamically in View MVC4

I have a homepage that will display a table with some data for each user. The back-end handles that and I have a list in my model. I am trying to view a dynamic table based on this list and be able to delete elements from without having to hit refresh. I do not know where to start to do something like this. Any help?
Here is what I have so far:
Inside HomePage controller I have an action returning Json representation of the model. Have of 'HpModel' gets set in the login controller and the other is in this one:
public JsonResult GetUserInfo(HomePageModel HpModel)
{
DBOps ops = new DBOps();
HpModel.PhoneDisplay = ops.getDisplayInfo(HpModel.ExtNum);
HpModel.NumberOfLines = HpModel.PhoneDisplay.Count;
return Json(HpModel);
}
In my view I have a javascript to grab this model:
function getInfo() {
alert('here');
$.ajax({
url: '#Url.Action("GetUserInfo", "HomePage")',
data: json,
type: 'POST',
success: function (data) {
alert(data);
}
});
}
I am not sure what is going wrong, and not 100% sure its the way to be done anyway.
Help is appreciated :)
One more idea. You may use jQuery to hide and callback function to $Post to your Delete ActionResult.
For examp: (here I created easy example without $post: jsfiddle)
<script>
$('.delete').click(function()
{
$(this).closest('tr').hide(callback);
function callback() {
$post(/Home/Delete/....
});
</script>
<table>
<tr>
<td>Marry</td>
<td>10 points</td>
<td><a class="delete" href="#">Delete</a></td>
</tr>
<tr>
<td>Jane</td>
<td>8 points</td>
<td><a class="delete" href="#">Delete</a></td>
</tr>
<tr>
<td>Lara</td>
<td>5 points</td>
<td><a class="delete" href="#">Delete</a></td>
</tr>
</table>

How do I get the value of a button to pass back to the server when using JQuery & AJAX?

I am using MVC3, Razor, C#, JQuery and AJAX.
I am using an Ajax call to postback a form to the server. I get all the form element values being passed back to the controller in:
[HttpPost]
public ActionResult Edit(Product myProduct, string actionType)
if (actionType == "Save")
save....
And in the View I have:
#using (Html.BeginForm("Edit", "RA", FormMethod.Post, new { #class = "editForm", #id = "frmEdit" }))
Form Elements:
<td>
#Html.HiddenFor(p=>p.Id)
<button type="submit" name="actionType" value="Save" >Save</button>
</td>
<td>#Html.EditFor(p=>p.Name)</td>
Some Ajax:
$('.editForm').on('submit', function () {
$.ajax({
url: this.action,
type: this.method,
data: $('#frmEdit').serialize(),
context: $('button', this).closest('tr'),
success: function (result) {
$(this).html(result);
}
});
return false;
});
Now I think the problem line is since I have seen quite a few posts about problem with JQuery and submitting button values:
data: $('#frmEdit').serialize(),
But I cannot get the button to submit an actionType of "Save". I just get null.
Thoughts greatly appreciated.
Thanks.
UPDATE:
My code seems to interfere with my JQuery listener ?? My code is:
<input type="submit" id="btn" name="btn" value="Save" onclick="document.getElementById('actionType').value = 'Save';"/>
From the documentation:
No submit button value is serialized since the form was not submitted using a button.
However you can add it by hand:
data: $('#frmEdit').serialize() + '&actionType=Save',
or
data: $('#frmEdit').serialize()
+ '&'
+ encodeURIComponent(button.name)
+ '='
+ encodeURIComponent(button.value),
where button is the <button> DOM element.

Web: Textbox value attribute not the same as value in textbox

I am using Visual Studio 2010 updated to the latest version and the MVC3 framework updated to the latest version. I am also using jquery 1.5.1 but this issue does not appear to be jquery related.
I have the following main page:
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/base/jquery-ui.css" type="text/css" />
<link href="#Url.Content("~/Content/UserMaintainance.css")" rel="stylesheet" type="text/css" />
<script src="#Url.Content("~/Scripts/UserMaintainance.js")" type="text/javascript"></script>
#model TourSystem2.Models.UserMaintainanceViewModel
#{
ViewBag.Title = "UserMaintainance";
}
#Model.Debug
<h2>User Maintainance</h2>
<div id = "EditUser"></div>
<table>
<tr id="1">
<td><button type="button" class = "deleteButton"></button></td>
<td><button type="button" class = "editButton"></button></td>
<td>John </td>
<td>john </td>
<td>A</td>
<td>1234 </td>
<td></td>
//snipped some unrelated form generation of user information showing
<tr id = "0">
<td colspan = "7"><button type = "button" id = "addButton">Add New User</button></td>
</tr>
</table>
In the java script for this form, I do the following for the addButton:
$(function () {
$(':button.editButton, :button#addButton').click(function () {
var myData = $(this).parent().parent().attr("id");
$.post("/Admin/EditUser", { UserID: myData },
function (data) {
$('#EditUser').html(data);
$('#EditUser').dialog({
modal: true,
width: 400,
resizable: false,
buttons: {
"Save": function () {
$(this).dialog("close");
},
"Cancel": function () {
$(this).dialog("close");
}
}
});
}); //end post
});
The partial page /Admin/EditUser looks like this:
#model TourSystem2.Models.UserEditViewModel
<link href="/Content/UserEdit.css" rel="stylesheet" type="text/css" />
#Html.HiddenFor(Model => Model.UserInfo.iUserID)
<table id="useredit">
<tr>
<td>#Html.LabelFor(Model => Model.UserInfo.cLoginName, "Login Name")</td>
<td>#Html.TextBoxFor(Model => Model.UserInfo.cLoginName)</td>
</tr>
//Snip more fields
</table>
My controller code for EditUser looks like:
public ActionResult EditUser(int UserID)
{
UserEditViewModel myUser = new UserEditViewModel();
if (UserID == 0)
{
myUser.UserInfo.iUserID = 0;
return PartialView("UserEdit", myUser);
}
else if (myUser.Load(UserID))
{
return PartialView("UserEdit", myUser);
}
else
{
return Json("Broken: " + myUser.Debug);
}
}
My intention is that upon clicking save, I will do another AJAX post to pass the information back to the server.
So far, everything is working pretty well except the value attribute of the textbox does not change even though the text in the box has changed. If I click on edit, the data files out correctly on the editUser partial page... but any changes are not reflected in the value.
Using firebug, I can visually see that value does not change for any textbox I have on the screen. During the "save user" post, only the original value is returned and not the modified value.
Did I miss something very basic?
*EDIT 1***
I am trying to do the following in my SaveButton event:
"Save": function () {
var myUser =
{
iUserID: ('#UserInfo_iUserID').val,
cLoginName: ('#UserInfo_cLoginName').val,
};
$.ajax({
type: "POST",
url: "/admin/SaveUser",
data: myUser,
success: function (bNum) {
alert("returned" + bNum);
}
});
I am getting old results for the cLoginName: ('#UserInfo_cLoginName').val
This happens before the second POST.
That's a common gotcha when you try to modify values in a POST action that are contained in the ModelState and rendering the same view. You will need to remove the value from model state before changing it or HTML helpers (such as HiddenFor) will use the POSTed value when binding:
ModelState.Remove("UserInfo.iUserID");
myUser.UserInfo.iUserID = 0;
return PartialView("UserEdit", myUser);
Verify by debugging that ModelState contains a value called UserInfo.iUserID.
UPDATE:
It seems that the wrong syntax is used to retrieve the values:
('#UserInfo_iUserID').val
instead of:
$('#UserInfo_iUserID').val()
I had the same issue as Darrin described below
See Updating value provider prior to TryUpdateModel
The helpers exhibit this behavior because they assume if you are redisplaying data after a post there should be a validation failure otherwise you would be redirecting to a get action as part of the MVC PRG (post redirect get)pattern
I believe your issue though is different as was pointed out below.

Resources