Displaying a message if ajaxform successfull or failed - asp.net-mvc

I would like to upload a file without refreshing all the page. I know that uploading does not support classic ajax form. The trick is to use a classic form and to ajaxify it.
Here is my view:
#model .....
#using (Html.BeginForm("UploadImage", "Admin", FormMethod.Post, new { enctype = "multipart/form-data", id = "uploadform" }))
{
<div class="editor-label"> #Html.LabelFor(model => model.Image) </div>
<div class="editor-field"> <input type="file" name="file" id="file" /> </div>
<button type="submit">
<span>Upload</span>
</button>
}
Here is my javascript:
$(document).ready(function() {
$('#uploadform').ajaxForm(function () {
alert("Thank you for your comment!");
});
});
Here is my controller:
[HttpPost]
public ActionResult UploadImage(HttpPostedFileBase file)
{
// Add code here...
return RedirectToAction("EditProject");
}
When I submit a file, the action in the controller receive the information. BUT next nothing happened. The message 'Thank you for your comment!' is never displayed. I would like to display a message if the upload is successful of failed.
Thanks.

The UploadImage method in your Controller redirects to another action. You should return JSON with a message to be displayed.
public ActionResult UploadImage(HttpPostedFileBase file)
{
//processing code...
return Json(new { message = "Thank you..." });
}
And then in the View just alert the returned message.

Related

MVC 5 partial view async postback

I have a sort of Master-Detail Edit form and I'm trying to follow this post: Using Ajax... to get the partial view to postback.
My Edit form has a partial view that has a list of sub items, and another partial create view in it to add new items. I'd like the partial create view to post back and update the list without refreshing the whole page if possible.
Here's what I have so far:
MyController.cs -
public ActionResult Edit(int? id)
{
//...
ViewBag.CustomFormId = id;
using (var _db = new MkpContext())
{
//...
return View(profileEdit);
}
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(CustomForm editForm)
{
//...
if (!ModelState.IsValid) return View(editForm);
using (var _db = new MkpContext())
{
var form = _db.CustomForms.Find(editForm.CustomFormId);
//...
_db.Entry(form).State = EntityState.Modified;
_db.SaveChanges(User.ProfileId);
return RedirectToAction("Index");
}
}
public ActionResult _CustomFieldList(int id)
{
ViewBag.CustomFormId = id;
using (var _db = new MkpContext())
{
var formCustomFields = (from cf in _db.CustomFields
where cf.CustomFormId == id
select cf);
return PartialView(formCustomFields.ToList());
}
}
// Nested in _CustomFieldList
public ActionResult _CustomFieldCreate(int id)
{
var newField = new CustomField
{
CustomFormId = id
};
return PartialView(newField);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult _CustomFieldCreate(CustomField addField)
{
ViewBag.CustomFormId = addField.CustomFormId;
if (ModelState.IsValid)
{
using (var _db = new MkpContext())
{
_db.CustomFields.Add(addField);
_db.SaveChanges();
}
var newField = new CustomField
{
CustomFormId = addField.CustomFormId
};
return PartialView(newField); // Probably need to change this somehow
}
return PartialView(addField);
}
And the views:
Edit.cshtml -
#model PublicationSystem.Model.CustomForm
#{
ViewBag.Title = "Edit Custom Form";
Layout = "~/Views/Shared/_LayoutSmBanner.cshtml";
}
<div class="form-horizontal">
<div class="row">
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#* Fields for this form *#
}
<div id="CustomFields" class="col-md-6">
#Html.Action("_CustomFieldCreate", new { id = ViewBag.CustomFormId })
</div>
</div>
</div>
<script>
$(function () {
$("#createFieldForm").on("submit", function (e) {
e.preventDefault(); //This prevent the regular form submit
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
$("#CustomFields").html(result);
}
});
return false;
});
});
</script>
_CustomFieldCreate.cshtml -
#model PublicationSystem.Model.CustomField
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div id="result"></div>
<div class="form-horizontal">
<h4>CustomField</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model =>model.CustomFormId)
<div class="row">
#* Fields for the form *#
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div id="customFieldList">
#Html.Action("_CustomFieldList", new { id = ViewBag.CustomFormId })
</div>
_CustomFieldList.cshtml
#model System.Collections.Generic.IEnumerable<PublicationSystem.Model.CustomField>
<table class="table">
#* List table code *#
</table>
Edit: I rewrote the pages so that the list is part of the create partial view. What happens now is, if you enter data for _CustomFieldCreate and press submit, the first time, it refreshes just that view (including the nested list view). However the second time, it redirects to the view, probably because the first refresh didn't rebind the javascript to the submit button. Also, the Create view doesn't clear out the fields, but persists the originally entered data.
You will need a form in your partial view whose submit action binds to a javascript function that posts to your controller.
For example if your form id is MyForm:
$('#MyForm').on('submit', function (e) {
e.preventDefault(); //This prevent the regular form submit
$.ajax({
url: $(this).action, // This will submit the post to whatever action your form goes to
type: "POST", // This tells it that it is a post
data: $(this).serialize(), // This sends the data in the form to the controller
success: function (data) {
// do some javascript on success
},
error: function (xhr, ajaxOptions, thrownError) {
// do some javascript on error
}
});
});
This javascript overrides the default form submit and does an ajax post to your controller and then returns with success or error where you can do anything you want.
Here is some jquery ajax documentation:
http://api.jquery.com/jquery.ajax/
You should look into using AJAX. That should accomplish what I think you are describing. You'll want to create a javascript function that handles the submit event on the form, then post the form data to some create action in your MVC app using AJAX. If you are using jQuery, the library makes it pretty simple.
http://api.jquery.com/jquery.ajax/

Return csv file and redirect to same page MVC 4

I have a page with two textboxes for From date and To date and a generate csv file button.
so a user enters both from and to date and click genearte button and csv file gets downloaded to browser.
Now the issue is if there are any validations on the page like date is not valid so have added validation summary for that and it shows up correctly. So if a validation message is shown and then i correct the dates and click generate then it directly returns the file and the validation message still shown up on the page.
Any way to refresh the page after csv file returned or any other way to solve the above issue.
Code is as below:
#using (Html.BeginForm("Index", "MyController", null, FormMethod.Post, new { novalidate = "novalidate" }))
{
#Html.ValidationSummary(true, "Error on page")
<div >
<div>
#Html.LabelFor(model => model.FromDate)
<div>
#Html.TextBoxFor(m => m.FromDate, "{0:MM/dd/yyyy}", new { #id="fromDate" })
#Html.ValidationMessageFor(x => x.FromDate)
</div>
</div>
<div>
#Html.LabelFor(model => model.ToDate)
<div>
#Html.TextBoxFor(m => m.ToDate, "{0:MM/dd/yyyy}", new {#id = "toDate"})
#Html.ValidationMessageFor(x => x.ToDate)
</div>
</div>
<div>
<input type="submit" value="Generate CSV File"/>
</div>
</div>
}
Controller:
[HttpPost]
public ActionResult Index(MyModel model)
{
if (ModelState.IsValid)
{
var response = this.GetCsv(model.FromDate, model.ToDate)
return File(new UTF8Encoding().GetBytes(response), "text/csv", "Report.csv");
}
return this.View(model);
}
You could use some javascript to do this.
The javascript
<script>
function ClearErrorMessages() {
var elements = document.getElementsByClassName("validation-summary-errors");
for (var i = 0; i < elements.length; i++) {
elements[i].innerHTML = "";
}
elements = document.getElementsByClassName("field-validation-error");
for (var i = 0; i < elements.length; i++) {
elements[i].innerHTML = "";
}
//Removes validation from input-fields
$('.input-validation-error').addClass('input-validation-valid');
$('.input-validation-error').removeClass('input-validation-error');
//Removes validation message after input-fields
$('.field-validation-error').addClass('field-validation-valid');
$('.field-validation-error').removeClass('field-validation-error');
//Removes validation summary
$('.validation-summary-errors').addClass('validation-summary-valid');
$('.validation-summary-errors').removeClass('validation-summary-errors');
}
</script>
Then add an onclick attribute to the button
<input type="submit" onclick="ClearErrorMessages(); return true;" value="Generate CSV File" />
It's no way to refresh validation status use file output, so you need to do twice post...
A. The fastest way is add a download button make it shows after all fields are validated.
B. Another way is use java script to re-post after all fields are validated.

How to execute only one form action method in asp.net mvc view?

I have this page that contains 2 forms one exists in the layout file and the other in the view file. The first form is for newsletter subscription (an ajax form) and its location is common in the footer of the page, that's why it's in the layout and is rendered as a partial view. I have another view of the contact us page with its own form (normal form).
My issue is when I submit the contact us form, the code also goes into the action method of the subscription form and returns a model error with JsonResult causing the whole view to be rendered as text. I only want the action method of the contact us form to be executed.
Here is the subscription form in a partial view file
#model MyApp.Models.Subscriber
#using (Ajax.BeginForm("NewsletterSubscription", "Shared", null, new AjaxOptions
{
HttpMethod = "POST",
OnBegin = "OnBegin",
OnComplete = "OnComplete",
OnFailure = "OnFailure"
}, new { id = "subscribeForm" }))
{
#Html.AntiForgeryToken()
#Html.TextBoxFor(model => model.SubscriptionEmail)
#Html.ValidationMessageFor(model => model.SubscriptionEmail)
<input id="btnSubscribe" type="submit" value="Subscribe" />
}
And this is how it's rendered in the _layout.cshtml file
#{ Html.RenderAction("NewsletterSubscription", "Shared"); }
Here's the other form in contactus view file
#using (Html.BeginForm("Index", "Contact", FormMethod.Post, new { id = "contactForm" }))
{
#Html.AntiForgeryToken()
<div class="theForm">
<div class="theFormUnit">
<p>Fullname</p>
#Html.TextBoxFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="theFormUnit">
<p>Email</p>
#Html.TextBoxFor(model => model.Email)
#Html.ValidationMessageFor(model => model.Email)
</div>
<div class="theFormUnit">
<p>Phone</p>
#Html.TextBoxFor(model => model.Phone)
#Html.ValidationMessageFor(model => model.Phone)
</div>
<div class="theFormUnit">
<p>Message</p>
#Html.TextAreaFor(model => model.Message)
#Html.ValidationMessageFor(model => model.Message)
</div>
<input type="submit" value="Submit" />
</div>
}
When I debug the code, first the action method of the contact us is executed then the action method of the subscription and returns an error since the email was not provided.
The subscription action method
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult NewsletterSubscription(Subscriber subscriber)
{
if (ModelState.IsValid)
{
}
else
{
return Json(new { success = false, message = "Failure Message" });
}
return Json(new { success = true, message = "Success Message"});
}
And contact us action method
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(ContactViewModel contact)
{
if(ModelState.IsValid)
{
}
else
{
}
return View(contact);
}
I tried two solutions the first one partially solved the problem and the other solved it completely.
First solution was to add the following lines in the action method of the subscription form
if (!Request.IsAjaxRequest())
{
ModelState.Clear();
return PartialView("Partial/_NewsletterSubscription");
}
Here I am checking if the request is not an ajax request, which means it's the postback request for the contact us form, in this case I clear the model state to remove the error and return a new partial view. Although this solution solved the issue but I wasn't satisfied with it because I was not convinced with the fact that action method of the subscription form gets executed with the action method of the contact us form.
So later I thought of another simple solution, which totally solved the issue and the execution doesn't go into the action method of the subscription form when submitting the contact us form.
I simply changed the action method name from "NewsletterSubscription" to "Subscribe" so instead of
#using (Ajax.BeginForm("NewsletterSubscription", "Shared", null, new AjaxOptions
I changed it to
#using (Ajax.BeginForm("Subscribe", "Shared", null, new AjaxOptions

HttpPostedFileBase in ASP.NET MVC is null while using jQuery Dialog

File upload paths in MVC is null with jquery dialog
I have created a MVC application having two file uploads in view and created a POST action for this, with IEnumerable parameter to catch the files. When i am submitting the form the files are coming fine in the HttpPostedFileBase collection, but if the file upload controls are in a dialog(jquery pop up) the IEnumerable object is null. Please help me.
The following are the codes i have done.
View
#using (Html.BeginForm("Details", "StudentRegistration", FormMethod.Post, new{ #class = "form ideal-form",enctype = "multipart/form-data"}))
{
<div id="divSignatureCapturePopUp" title="Capture Photo" style="display:none; float:left;">
<input id="fileUploadSignature" type="file" name ="fileUploadImages" style="width:200px"/>
</div>
}
<input type="button" id="buttonCaptureSignature" name="CaptureSignature" class="ideal-button" value="Capture Signature" />
<script type="text/javascript">
$(document).ready(function () {
$("#buttonCaptureSignature").click(function () {
$("#divSignatureCapturePopUp").dialog({
width: 560,
});
});
}
</script>
controller
[HttpPost]
public ActionResult Details(IEnumerable<HttpPostedFileBase> fileUploadImages)
{
}
Seems like jqueryui widget move file input field outside form. Check posted data in chrome dev console in 'Network' tab and make sure that file data is in request.
If this suggestion is right you can modify form this way:
<div id="divSignatureCapturePopUp" title="Capture Photo" style="display:none; float:left;">
#using (Html.BeginForm("Details", "StudentRegistration", FormMethod.Post, new{ #class = "form ideal-form",enctype = "multipart/form-data"}))
{
<input id="fileUploadSignature" type="file" name ="fileUploadImages" style="width:200px"/>
<input type="submit" value="rtwert" />
}
</div>
Оtherwise possible get files in other way:
[HttpPost]
public ActionResult Details()
{
var files = Request.Files;
}

Submit Data from partial view to a controller MVC

I have a list of employment records, you can also add an employment record from the same page using a partial view.
Heres employment.cshtml that has a partial view for the records list and a partial view to add a new record which appears in a modal pop up.
<h2>Employment Records</h2>
#{Html.RenderPartial("_employmentlist", Model);}
<p>
Add New Record
</p>
<div style="display:none">
<div id="regModal">
#{Html.RenderPartial("_AddEmployment", new ViewModelEmploymentRecord());}
</div>
</div>
Heres the partial view _AddEmployment.cshtml
#using (Html.BeginForm("AddEmployment, Application"))
{
#Html.ValidationSummary(true)
<div class="formEl_a">
<fieldset>
<legend></legend>
<div class="sepH_b">
<div class="editor-label">
#Html.LabelFor(model => model.employerName)
</div>
etc....etc....
</fieldset>
</div>
<p>
<input type="submit" class="btn btn_d" value="Add New Record" />
</p>
}
and heres my Application controller:
[HttpPost]
public ActionResult AddEmployment(ViewModelEmploymentRecord model)
{
try
{
if (ModelState.IsValid)
{
Add Data.....
}
}
catch
{
}
return View(model);
}
When compiling the following html is generated for the form:
<form action="/Application/Employment?Length=26" method="post">
It brings in a length string? and is invoking the Employment controller instead?
Hope all is clear....
QUESTION ONE: when I click the submit button from within the partial view it does not go to the controller specified to add the data. Can anyone see where im going wrong?
QUESTION TWO: When I get this working I would like to update the employment list with the new record....am I going about this the correct way? Any tips appreciated.
Answer 1: First try this and let me know if that hits your controller.
#using (Html.BeginForm("AddEmployment", "Application", FormMethod.Post))
Answer 2: To update the employment list, I would assume you would want to save the model to your database then have your employment list displayed on the same page or a different page calling the data from the DB into the the list or table to be displayed.
Edit:
It looks as though your form attributes are not being applied.
For your employment.cshtml, I personally don't use { } around my #Html statements.
You must not be doing what I stated above because your error occurs only when I write it as
#using (Html.BeginForm("AddEmployment, Application", FormMethod.Post))
missing those closing quotes is what is causing your problem.
jQuery code:
window.jQuery(document).ready(function () {
$('#btnsave').click(function () {
var frm = $("form");
var data = new FormData($("form")[0]);
debugger;
$.ajax({
url: '/Home/Update',
type: "POST",
processData: false,
data: data,
dataType: 'json',
contentType: false,
success: function (response) {
alert(response);
},
error: function (er) { }
});
return false;
});
});
Controller Code
[HttpPost]
public JsonResult Update(Generation obj)
{
if (ModelState.IsValid)
{
return Json("done");
}
else
{
return Json("error create");
}
}
Using those code you can post form using jquery and get response in jsonresult
I know this is very old Question
the reason it didn't work for you because your syntax
Here is your code
#using (Html.BeginForm("AddEmployment, Application"))
the fix
#using (Html.BeginForm("AddEmployment", "Application"))
Regards
you have put #using (Html.BeginForm("AddEmployment, Application")) what this is trying to do is invoke a action called "AddEmployment, Application" i think you meant #using (Html.BeginForm("AddEmployment", "Application"))

Resources