how to send uploaded file from javascript to controller in MVC? - c#

In my MVC, i have a view and that contains one file upload control and one button.
<input type="file" id="Uploadfile" />
<input type="button" onclick()="GetFile();/>
Javascript function as follows
function GetFile()
{
var file_data = $("#Uploadfile").prop("files")[0];
window.location.href="Calculation/Final?files="+file_data;
}
I need to pass/send the selected file via fileupload control to controller in mvc.
i have the controller
public ActionResult Final(HttpPostedFileBase files)
{
//here i have got the files value is null.
}
How to get the selected file and send it to the controller?
Plz help me to fix this issue.

I had similar functionality to deliver in my project.
The working code looks something like this:
Controller Class
[HttpPost]
public ActionResult UploadFile(YourModel model1)
{
foreach (string file in Request.Files)
{
HttpPostedFileBase hpf = Request.Files[file] as HttpPostedFileBase;
if (hpf.ContentLength > 0)
{
string folderPath = Server.MapPath("~/ServerFolderPath");
Directory.CreateDirectory(folderPath);
string savedFileName = Server.MapPath("~/ServerFolderPath/" + hpf.FileName);
hpf.SaveAs(savedFileName);
return Content("File Uploaded Successfully");
}
else
{
return Content("Invalid File");
}
model1.Image = "~/ServerFolderPath/" + hpf.FileName;
}
//Refactor the code as per your need
return View();
}
View
#using (#Html.BeginForm("UploadFile", "Upload", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<table style="border: solid thin; margin: 10px 10px 10px 10px">
<tr style="margin-top: 10px">
<td>
#Html.Label("Select a File to Upload")
<br />
<br />
<input type="file" name="myfile">
<input type="submit" value="Upload" />
</td>
</tr>
</table>
}

you cannot send file content via javascript (unless HTMl5). and you are doing totally wrong. if you want to do HTML5 based solution via FileReader api then you need to check this out. FileReader Api
Just put a form tag and use the same name of the input in the controller action to perform model binding
#using(Html.BeginForm("yourAction","YourControl",FormMethod.Post))
{
<input type="file" id="fileUpload" />
}
then in controller.
[HTTPPost]
public ActionResult Final(HttpPostedFileBase fileUpload)
{
//here i have got the files value is null.
}

Below code will do a full post back in an hidden form which will give an illusion of ajax file upload. Try it:
Update:
JS
function Upload(sender) {
var iframe = $("<iframe>").hide();
var newForm = $("<FORM>");
newForm.attr({ method: "POST", enctype: "multipart/form-data", action: "/ControllerName/Final" });
var $this = $(sender), $clone = $this.clone();
$this.after($clone).appendTo($(newForm));
iframe.appendTo($("html")).contents().find('body').html($(newForm));
newForm.submit();
}
HTML
<input type="file" id="Uploadfile" name="Uploadfile" />
<input type="button" onclick="Upload($('#UploadFile'));"/>
Controller
public ActionResult Final(HttpPostedFileBase Uploadfile)
{
//here you can use uploaded file
}

As a completion from Ravi's answer, I would suggest to use the following using statement:
#using(Html.BeginForm("yourAction","YourControl",FormMethod.Post, new { enctype="multipart/form-data" }))
{
<input type="file" id="fileUpload" />
}

You can do it by using json data to view.
As instance,
Controller
public ActionResult Products(string categoryid)
{
List<catProducts> lst = bindProducts(categoryid);
return View(lst);
}
public JsonResult Productsview(string categoryid)
{
//write your logic
var Data = new { ok = true, catid = categoryid};
return Json(Data, JsonRequestBehavior.AllowGet);
}
View:
#{
ViewBag.Title = "Index";
}
#model ASP.NETMVC.Controllers.Categories
<h2>List Of Categories</h2>
#Html.ListBox("lst_categories", (IEnumerable<SelectListItem>) ViewBag.Categories)
<script type="text/javascript">
$(function () {
$('#lst_categories').change(function () {
var catid = $('#lst_categories :selected').val();
$.ajax({
url: '#Url.Action("Productsview", "Jquery")',
type: 'GET',
dataType: 'json',
data: { categoryid: catid },
cache: false,
success: function (Data) {
if (Data.ok) {
var link = "#Url.Action("Products", "Jquery", new { categoryid = "catid" })";
link = link.replace("catid", Data.catid);
alert(link);
window.location.href = link;
}
}
});
});
});
</script>

Related

Upload files using .Net 6 MVC model biding serialization by jQuery Ajax/JSON

Need to upload files using MVC model biding by AJAX jQuery/JSON.
I was uploading with a normal submit form, but now I need to change to AJAX.
How can I do this? I mean, biding using MVC and AJAX, serializing my form or something like that.
Now, my imagemPro and imagemPre, on Controller, are always 'null'.
At my View:
#model Ri.Models.Produto
<form class="settings-form" id="frmAdd" enctype="multipart/form-data">
<label for="setting-input-1" class="form-label">Título</label>
<input asp-for="#Model.TituloProduto" type="text" class="form-control" required>
<input asp-for="#Model.ImagemProduto" type="file" class="form-control" required>
<label for="setting-input-1" class="form-label">Premio</label>
<input asp-for="#Model.TituloPremio" type="text" class="form-control" required>
<input asp-for="#Model.ImagemPremio" type="file" class="form-control" required>
<input type="button" value="Criar" class="btn app-btn-primary" id="btnAdd">
</form>
#section scripts{
<script src="~/admin/js/produtoAdd.js"></script>
}
At my Controller:
[HttpPost("/api/ProdutoAdd")]
public async Task<IActionResult> ProdutoAdd([Bind("TituloProduto,ImagemProduto,TituloPremio,ImagemPremio")] Produto produto, IFormFile imagemPro, IFormFile imagemPre)
{
if (!ModelState.IsValid)
{
return Json(new { success = false, msg = "1" });
}
if (imagemPro != null)
{
var name = Path.Combine(_enviroment.WebRootPath + "/imgs", System.IO.Path.GetFileName(imagemPro.FileName));
await imagemPro.CopyToAsync(new FileStream(name, FileMode.Create));
produto.ImagemProduto = imagemPro.FileName;
}
if (imagemPro != null)
{
var name = Path.Combine(_enviroment.WebRootPath + "/imgs", System.IO.Path.GetFileName(imagemPre.FileName));
await imagemPro.CopyToAsync(new FileStream(name, FileMode.Create));
produto.ImagemPremio = imagemPre.FileName;
}
_context.Add(produto);
await _context.SaveChangesAsync();
return Json(new { success = true });
}
My script:
$(function () {
$("#btnAdd").click(function (e) {
e.preventDefault();
var _this = $(this);
var _form = _this.closest("form");
var isvalid = _form.valid();
if (isvalid) {
Create();
}
else {
//alert('false');
}
});
Create = function () {
var options = {};
options.type = "POST";
options.url = "/api/ProdutoAdd";
options.dataType = "JSON";
options.cache = true;
options.async = true;
contentType = "application/json; charset=utf-8",
options.data = $('#frmAdd').serialize();
options.beforeSend = function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN", $('input:hidden[name="__RequestVerificationToken"]').val());
};
options.success = function (data) {
};
options.error = function (res) {
};
$.ajax(options);
};
});
I recommend you to create a viewModel
public class ProdutoViewModel
{
public Produto Produto {get; set;}
public IFormFile ImagemPro {get; set;}
public IFormFile ImagemPre {get; set;}
}
action ( remove Bind attribute too)
[HttpPost("/api/ProdutoAdd")]
public async Task<IActionResult> ProdutoAdd(ProdutoViewModel model )
I recommend you to use a submit button instead of ajax, it would be much easier for you
#model ProdutoViewModel
<form class="settings-form" id="frmAdd" enctype="multipart/form-data">
....
<input type="submit" value="Criar" class="btn app-btn-primary">
</form>
1.Model Binding binds the property by name attribute, your parameter name here is imagemPro/imagemPre.
2.The jQuery serialize() method will not include input file elements. So file user selected is not going to be included in the serialized value.
You need create a FormData object, append the files to that then append the form field values as well to this same FormData object. You may simply loop through all the input field and add it.
Here is a whole working demo you could follow:
#model Produto
//add `method="post"` in form tag
//otherwise it will not generate token input
<form class="settings-form" id="frmAdd" enctype="multipart/form-data" method="post">
<label for="setting-input-1" class="form-label">Título</label>
<input asp-for="#Model.TituloProduto" type="text" class="form-control" required>
<input asp-for="#Model.ImagemProduto" type="file" class="form-control" required>
<label for="setting-input-1" class="form-label">Premio</label>
<input asp-for="#Model.TituloPremio" type="text" class="form-control" required>
<input asp-for="#Model.ImagemPremio" type="file" class="form-control" required>
<input type="button" value="Criar" class="btn app-btn-primary" id="btnAdd">
</form>
#section scripts{
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script src="~/admin/js/produtoAdd.js"></script>
}
JS:
<script>
$(function () {
$("#btnAdd").click(function (e) {
e.preventDefault();
var _this = $(this);
var _form = _this.closest("form");
var isvalid = _form.valid();
if (isvalid) {
Create();
}
else {
}
});
Create = function () {
var fdata = new FormData();
var fileInput1 = $('#ImagemProduto')[0];
var file1 = fileInput1.files[0];
fdata.append("imagemPro", file1);
var fileInput2 = $('#ImagemPremio')[0];
var file2 = fileInput2.files[0];
fdata.append("imagemPre", file2);
$("form input[type='text']").each(function (x, y) {
fdata.append($(y).attr("name"), $(y).val());
});
var options = {};
options.type = "POST";
options.url = "/api/ProdutoAdd";
options.dataType = "JSON";
options.contentType = false; //change here...
options.processData= false; //add this...
options.data = fdata;
options.beforeSend = function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN", $('input:hidden[name="__RequestVerificationToken"]').val());
};
options.success = function (data) {
};
options.error = function (res) {
};
$.ajax(options);
};
});
</script>
Your payload and your content type don't match. jQuery.serialize encodes your form data as application/x-www-form-urlencoded, but you're telling the server to expect a content type of application/json. Easiest solution is to change the content type.
Also, you might want to use the form submit event of the form, rather than a 'click' event on a button. The reason for this is that browsers will submit forms in other ways besides clicking the button, (e.g. pressing "enter" key while in a text input). Submit will handle all of these methods.
Another side note: your method of creating your options object will work, but that syntax is a little awkward. The most common "best practice" is to declare the properties inline with the object:
var options = {
type: 'POST',
url: '/api/ProdutoAdd',
// etc ...
success: function (data) {
},
// etc ...
};
That keeps you from having to type options. before every property.

TempData Dropping Data

I'm trying to persist a TempData value on a return PartialView(). It works correctly in one Post but not another and I'm stymied.
In the following action it works correctly and the value gets passed, via javascript redirect to the action that is using the value:
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult DeletetheFile(int attachmentid, string issueId)
{
string response = _adoSqlService.DeleteAttachment(attachmentid);
TempData["ID"]= issueId;
TempData.Keep();
return PartialView("_DeleteFile");
}
In the following action it is getting set properly (see the first image), but by the time it gets to the same action as the first one I showed it has changed (see second image).
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult EditFile(IFormCollection collection)
{
AttachmentModel model = new AttachmentModel();
model.attachmentId = Convert.ToInt32(collection["attachmentId"]);
model.aIssueAttachmentDescription = collection["aIssueAttachmentDescription"];
string response = _adoSqlService.EditFileDescription(model);
TempData.Remove("ID");
TempData["ID"] = collection["issueId"];
TempData.Keep();
return PartialView("_EditFile");
}
When it gets to the where I need it is now returning [string1] instead of the 20-003.
Both of the above actions run against a partial view in a modal pop-up. The following javascript captures the modal action and redirects the results to the Issue/Edit controller/action.
$('body').on('click', '.relative', function (e) {
e.preventDefault();
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr('action');
var dataToSend = form.serialize();
$.post(actionUrl, dataToSend).done(function (data) {
$('body').find('.modal-content').html(data);
var isValid = $('body').find('[name="IsValid"]').val() == 'True';
if (isValid) {
$('body').find('#modal-container').modal('hide');
window.location.href = "/Issue/Edit";
}
});
})
The redirection seems to happen since the edit action is being called in both cases. It's just that in the second case it is not getting the correct value of the TempData value. Here is the start of the Edit action which resides in a different controller than the 2 actions above:
public ActionResult Edit(string id)
{
if (id == null)
{
id = TempData["ID"].ToString();
}
----------More Comments
So after working on this for the past 4 hrs I've come up with a work-around. I'm not sure this is the correct technique or not. What I ended up doing was adding a hidden input field on the partial views and then parsing the ajax response for that value.
var issueid = $(response).find('[name="issueidSaved"]').val();
window.location.href = "/Issue/Edit/?id=" + issueid
My concern now is that the issueid is now included in the query string and is visible in the URL.
Is this the correct method or should I go back to using TempData and trying to get that to work?
UPDATE
Hopefully I can explain this better. The goal is to get a TempData value into the following action in my Issues Controller which is tied to my Edit Page (Issues/Edit):
public ActionResult Edit(string id)
{
if (id == null)
{
id = TempData["ID"].ToString();
}
I have a modal on my Edit page that is populated with different partial views depending upon what is populating it. The partial views use the Attachment controller, while the Edit view uses the Issues Controller. I use Javascript/ajax to capture the submit from the partial views to close the modal and redirect to the Edit view so a refresh of the data affected by the partial views is reflected on the Edit view. The TempData value is working correctly when I submit the _DeleteFile, but not when I submit the _EditFile partial views in the modal.
Here is the common Javascript/ajax on the Edit view:
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script>
//Using this to scroll the page on the close of the modal/page refresh
$(document).ready(function () {
var JumpTo = '#ViewBag.JumpToDivId';
if (JumpTo != "") {
$(this).scrollTop($('#' + JumpTo).position().top);
}
});
//Using this to Capture the click that opens the modals
$('body').on('click', '.modal-link', function () {
var actionUrl = $(this).attr('href');
$.get(actionUrl).done(function (data) {
$('body').find('.modal-content').html(data);
});
$(this).attr('data-target', '#modal-container');
$(this).attr('data-toggle', 'modal');
});
//Using this to Capture the click that Submits the _EditFile,_DeleteFile,_CreateEdit forms on the modal
$('body').on('click', '.relative', function (e) {
e.preventDefault();
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr('action');
var dataToSend = form.serialize();
$.post(actionUrl, dataToSend).done(function (data) {
$('body').find('.modal-content').html(data);
var isValid = $('body').find('[name="IsValid"]').val() == 'True';
var issueid = "";
issueid = $('body').find('[name="issueidSaved"]').val();
var jumpto = $('body').find('[name="jumpto"]').val();
if (isValid) {
$('body').find('#modal-container').modal('hide');
if (issueid == "")
{
window.location.href = "/Issue/Edit/?id=" + issueid + "&jumpto=" + jumpto;
}
}
});
})
//Using this to Capture the click that Submits the _UploadFile form on the modal
$(function () {
$('body').on('click', '.fileupload', function (e) {
e.preventDefault();
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr('action');
var fdata = new FormData();
$('input[name="file"]').each(function (a, b) {
var fileInput = $('input[name="file"]')[a];
if (fileInput.files.length > 0) {
var file = fileInput.files[0];
fdata.append("file", file);
}
});
$("form input[type='text']").each(function (x, y) {
fdata.append($(y).attr("name"), $(y).val());
});
$("form input[type='hidden']").each(function (x, y) {
fdata.append($(y).attr("name"), $(y).val());
});
$.ajax({
url: actionUrl,
method: "POST",
contentType: false,
processData: false,
data: fdata
}).done((response, textStatus, xhr) => {
var isValid = $(response).find('[name="IsValid"]').val() == 'True';
var issueid = $(response).find('[name="issueidSaved"]').val();
var jumpto = $(response).find('[name="jumpto"]').val();
if (isValid) {
$('body').find('#modal-container').modal('hide');
window.location.href = "/Issue/Edit/?id=" + issueid + "&jumpto="+jumpto;
}
});
})
});
$('body').on('click', '.close', function () {
$('body').find('#modal-container').modal('hide');
});
$('#CancelModal').on('click', function () {
return false;
});
$("form").submit(function () {
if ($('form').valid()) {
$("input").removeAttr("disabled");
}
});
</script>
Here is the _DeleteFile Partial view and the AttachmentController code that handles the submit:
<!--Modal Body Start-->
<div class="modal-content">
<input name="IsValid" type="hidden" value="#ViewData.ModelState.IsValid.ToString()" />
<input name="issueidSaved" type="hidden" value="#ViewBag.ID" />
<input name="jumpto" type="hidden" value="#ViewBag.JumpToDivId" />
<!--Modal Header Start-->
<div class="modal-header">
<h4 class="modal-title">Delete File</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
<!--Modal Header End-->
<form asp-action="DeletetheFile" asp-route-attachmentid="#ViewBag.id" asp-route-issueId="#ViewBag.issueId" asp-controller="Attachment" method="post" enctype="multipart/form-data">
#Html.AntiForgeryToken()
<div class="modal-body form-horizontal">
Are you sure you want to delete the #ViewBag.title File?
<!--Modal Footer Start-->
<div class="modal-footer">
<button data-dismiss="modal" id="cancel" class="btn btn-default" type="button">No</button>
<input type="submit" class="btn btn-success relative" id="btnSubmit" data-save="modal" value="Yes">
</div>
<div class="row">
</div>
</div> <!--Modal Footer End-->
</form>
</div>
<script type="text/javascript">
$(function () {
});
</script>
<!--Modal Body End-->
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult DeletetheFile(int attachmentid, string issueId)
{
string response = _adoSqlService.DeleteAttachment(attachmentid);
ViewBag.ID = issueId;
ViewBag.JumpToDivId = "upload";
TempData["ID"]= issueId;
TempData.Keep();
return PartialView("_DeleteFile");
}
Here is the _EditFile partial view and the AttachmentController code:
Edit File
×
<form asp-action="EditFile" asp-controller="Attachment" method="post" enctype="multipart/form-data">
#Html.AntiForgeryToken()
<div class="modal-body form-horizontal">
<input name="issueId" type="hidden" value="#ViewBag.issueId" />
<input name="attachmentId" type="hidden" value="#ViewBag.attachmentId" />
<label class="control-label">#ViewBag.aFileName</label><br />
Make changes to description then select "Save Changes".<br />
<input name="aIssueAttachmentDescription" class="form-control formtableborders" id="titletext" value="#ViewBag.aIssueAttachmentDescription" />
<!--Modal Footer Start-->
<div class="modal-footer">
<button data-dismiss="modal" id="cancel" class="btn btn-default" type="button">No</button>
<input type="submit" class="btn btn-success relative" id="btnSubmit" data-save="modal" value="Save Changes">
</div>
<div class="row">
</div>
</div> <!--Modal Footer End-->
</form>
</div>
<script type="text/javascript">
$(function () {
});
</script>
<!--Modal Body End-->
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult EditFile(IFormCollection collection)
{
AttachmentModel model = new AttachmentModel();
model.attachmentId = Convert.ToInt32(collection["attachmentId"]);
model.aIssueAttachmentDescription = collection["aIssueAttachmentDescription"];
string response = _adoSqlService.EditFileDescription(model);
ViewBag.ID = collection["issueId"];
ViewBag.JumpToDivId = "upload";
TempData.Remove("ID");
TempData["ID"] = collection["issueId"];
TempData.Keep();
return PartialView("_EditFile");
}
When I inspect the TempData at the Issue/Edit action after the _DeleteFile submit it displays the following (which is correct):
When I inspect the TempData at the Issue/Edit action after the _EditFile submit it displays the following (which is incorrect):
You need to change
TempData["ID"] = collection["issueId"];
to
TempData["ID"] = collection["issueId"].ToString();
Because collection["issueId"] is Type Microsoft.Extensions.Primitives.StringValues rathar than Type String.
Here is a picture to show the Type:

Dynamic "Favorite" button - ASP.NET MVC

I have created a table which dynamically generates records using the "Infinite Loading" process, I have a button in my HTML Code which i need to use to allow users to add the item in their favourite - so this is my HTML code
#model List<PagesAuth.Models.Links.MLink>
#foreach (var I in Model)
{
<tr>
<td class="v-align-top" id="itemcard">
<h4 class="card-title">
#I._title
<small><cite>#I._tp_created.ToString("dd MMM yyyy")</cite> /small>
</h4>
<div class="pull-right" id="options">
<ul class="list-inline text-right" >
#if (I._tp_favourite == 0)
{
<li><button class="btn-link glyphicon glyphicon-heart-empty" onclick="location.href='#Url.RequestContext .Action("_Fav", "Home", "#I._id")'"></button></li>
}
else
{
<li><button class="btn-link glyphicon glyphicon-heart-empty" onclick="location.href='#Url.RequestContext .Action("_UnFav", "Home", "#I._id")'"></button></li>
}
</ul>
</div>
</div>
</td>
</tr>
}
I am trying to use "Favourite" button to allow user to add that website to their favourite list (I am ok with the DB updates etc)
<ul class="list-inline text-right" >
#if (I._tp_favourite == 0)
{
<li><button class="btn-link glyphicon glyphicon-heart-empty" onclick="location.href='#Url.RequestContext .Action("_Fav", "Home", "#I._id")'"></button></li>
}
else
{
<li><button class="btn-link glyphicon glyphicon-heart-empty" onclick="location.href='#Url.RequestContext .Action("_UnFav", "Home", "#I._id")'"></button></li>
}
</ul>
What I want to know is how to achieve this on user front-end - Like I thought I should just create a PartialView and make it child action only in my controller, send it ID and do DB Processing
[ChildActionOnly]
public ActionResult _Fav(int ID)
{//Do DB Processing
return PartialView(ID);
}
First of all the following does not work
onclick="location.href='#Url.RequestContext .Action("_UnFav", "Home", "#I._id")'"
Second, if I end up making this work, it will still refresh the page and I don't want that.
Is there a better way to achieve this
Cheers
I don't know why you want to use partial views but you can do it this way.
Use ajax to send request to controller action.
Handle action result using JavaScript.
View:
#model List<PagesAuth.Models.Links.MLink>
#foreach (var I in Model)
{
<tr>
<td class="v-align-top" id="itemcard">
<h4 class="card-title">
#I._title
<small><cite>#I._tp_created.ToString("dd MMM yyyy")</cite> /small>
</h4>
<div class="pull-right" id="options">
<ul class="list-inline text-right" >
#if (I._tp_favourite == 0)
{
<li><button class="btn-link glyphicon glyphicon-heart-empty" onclick="Fav(#I._id)"></button></li>
}
else
{
<li><button class="btn-link glyphicon glyphicon-heart-empty" onclick="UnFav(#I._id)"></button></li>
}
</ul>
</div>
</div>
</td>
</tr>
}
JS:
Here I am just alerting that the favorite action succeeded, else you have an array of string errors to work with. You could redirect or do some stuff, whichever you prefer.
<script type="text/javascript">
function Fav(id) {
var url = '#Url.Action("_Fav", "Home")';
$.ajax({
url: url,
type: 'POST',
data: {
id: id
},
success: function (data) {
if(data.length == 0) // No errors
alert("Fave success!");
},
error: function (jqXHR) { // Http Status is not 200
},
complete: function (jqXHR, status) { // Whether success or error it enters here
}
});
};
function UnFav(id) {
var url = '#Url.Action("_UnFav", "Home")';
$.ajax({
url: url,
type: 'POST',
data: {
id: id
},
success: function (data) {
if(data.length == 0) // No errors
alert("Unfave success!");
},
error: function (jqXHR) { // Http Status is not 200
},
complete: function (jqXHR, status) { // Whether success or error it enters here
}
});
};
</script>
Controller:
[HttpPost]
public ActionResult _Fav(int ID)
{
List<string> errors = new List<string>(); // You might want to return an error if something wrong happened
//Do DB Processing
return Json(errors, JsonRequestBehavior.AllowGet);
}
[HttpPost]
public ActionResult _UnFav(int ID)
{
List<string> errors = new List<string>(); // You might want to return an error if something wrong happened
//Do DB Processing
return Json(errors, JsonRequestBehavior.AllowGet);
}

Save Image Using Ajax.BeginForm in MVC 4

I'm trying to Save Image Using Ajax form. But Unable to Get uploaded image in my action.
This is my Index Page, In this page I'm loading partialview for Add Item .
My Index.Cshtml
#Html.Action("_AddOrUpdateItem","Admin")
My Action Code
public PartialViewResult _AddOrUpdateItem(int? itemId)
{
//Some Code Here
return PartialView("_AddItem", item);
}
[HttpPost]
public PartialViewResult AddOrUpdateItem(ToolItem toolItem, HttpPostedFileBase toolItemImage)
{
////Some Code Here
return PartialView("_AddItem", toolItem);
}
}
And My ajax form is as follow
#using (Ajax.BeginForm("AddOrUpdateItem", "Admin", new AjaxOptions() { HttpMethod = "POST" }, new { enctype = "multipart/form-data" }))
{
// Some more text boxes here
<input type="file" id="ToolItemImage" name="toolItemImage" />
<input type="submit" value="Save" />
}
I got a link for this same type of problem , But In my case it is not working
Upload file using Ajax form
It's impossible load file using only Ajax.BeginForm without additional js script,which have been provided in your link and I can't see it in your code.Anyway I strongly recommend use Jquery Form Plugin for such purposes.
I dont know ASP MVC but for submitiing a form with file you have to use enctype="multipart/form-data">
so your form must be having something like this
<form action"your controller" method="post" enctype="multipart/form-data">
<input type="file" id="ToolItemImage" name="toolItemImage" />
<input type="submit">
</form>
Save Ajax.Begien Form Image save this Jquery method and also check validation your form using ($("#frmUploader").valid()) this line of code ...
#using (Ajax.BeginForm("Create", "Employee", new AjaxOptions()
{
OnBegin = "startBLoading",
OnComplete = "stopBLoading",
OnSuccess = "OnSuccessI"
}, new { enctype = "multipart/form-data", id = "frmUploader" }))
{
<div class=row>
..... Enter the Page View Desgine.....
<button type="submit" class="btn btn-product text-capitaliz">Create</button>
</div>
}
<script type="text/javascript">
window.addEventListener("submit", function (e) {
debugger
if ($("#frmUploader").valid()) {
var form = e.target;
if (form.getAttribute("enctype") === "multipart/form-data") {
if (form.dataset.ajax) {
e.preventDefault();
e.stopImmediatePropagation();
var xhr = new XMLHttpRequest();
xhr.open(form.method, form.action);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
if (form.dataset.ajaxUpdate) {
var updateTarget = document.querySelector(form.dataset.ajaxUpdate);
if (updateTarget) {
updateTarget.innerHTML = xhr.responseText;
}
}
}
};
xhr.send(new FormData(form)
);
}
}
OnSuccessI();
} else {
e.preventDefault();
}
},
true
);
</script>

Reloading partial page after jQuery ajax command

I am very new to both JQuery and Asp.net MVC 3 (C#), so I apologize if this is trivial. I have an MVC partial view (Index.cshtml) that has a list of tasks. These tasks are contained within indivudal divs that I have in a list style layout. I have a button called "add task" that opens a dialog. This dialog will save the added task to the database via an AJAX Json call to the controller.
This is where I am having trouble - after the dialog closes I would like the list of tasks to reload with the task i just added. I have found examples where the entire page is reloaded, and I found examples where the controller is supposed to return a rendered view. My problem is that the dialog is being opened from the partial I want to reload. Is there a way to accomplish what I am trying to do.
Index.cshtml
#model IEnumerable<TaskManagementApplication.Models.Project>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<div id="ProjectAccordionWrapper">
#foreach (var item in Model)
{
<div class="ProjectWrapper">
<h3>#item.Name</h3>
<div class="column">
<button class="createTaskButton" id="#item.ProjectID">Create New Task</button>
#foreach(var task in item.Tasks) {
var buttonClass = "taskID" + task.TaskID;
<div class="portlet">
<div class="portlet-header">#task.TaskName</div>
<div class="portlet-content">#task.TaskDescription</div>
<button class="editTaskButton" id="#task.TaskID">Edit Task</button>
</div>
}
</div>
</div>
}
</div>
<div id="dialog-form" title="Create new user">
<p class="validateTips">All form fields are required.</p>
<form>
<fieldset>
<label for="TaskName">Task Name</label>
<input type="text" name="TaskName" id="name" class="text ui-widget-content ui-corner-all" />
<label for="TaskDescription">Task Description</label>
<input type="text" name="TaskDescription" id="description" value="" class="text ui-widget-content ui-corner-all" />
<input type="hidden" name="TaskID" id="ID" />
<input type="hidden" name="ProjectID" id="ProjectID" />
</fieldset>
</form>
</div>
Partial Javascript
function GetTask(id) {
if (id.length > 0) {
$.ajax({
url: '/Project/GetTaskFromID',
type: "POST",
data: { "id": id },
success: PopulateDialogFields,
error: HandleError
});
}
}
function PopulateDialogFields(data) {
$("#name").val(data.TaskName);
$("#description").val(data.TaskDescription);
$("#ID").val(data.TaskID);
}
function HandleError(data) {
alert(data.error);
var foo = data;
}
function SaveTask() {
var taskName = $("#name").val();
var taskDescription = $("#description").val();
var id = $("#ID").val();
var projectID = $("#ProjectID").val();
if (id.length > 0) {
$.ajax({
url: '/Project/SaveTask',
type: "POST",
data: { "taskName": taskName, "taskDescription": taskDescription, "taskID": id }
});
}
else {
$.ajax({
url: '/Project/SaveTask',
type: "POST",
data: { "taskName": taskName, "taskDescription": taskDescription, "projectID": projectID }
});
}
}
$("#dialog-form").dialog({
autoOpen: false,
height: 300,
width: 350,
modal: true,
buttons: {
"OK": function () {
SaveTask();
$(this).dialog("close");
},
Cancel: function () {
$(this).dialog("close");
}
},
close: function () {
allFields.val("").removeClass("ui-state-error");
window.location.reload(true);
},
open: function () {
var id = $(this).data("id");
var projectID = $(this).data("projectID");
$("#ProjectID").val(projectID);
var button = $("#" + id);
GetTask(id);
}
});
$(".editTaskButton")
.button()
.click(function () {
$("#dialog-form").data('id', this.id).dialog("open");
});
$(".createTaskButton")
.button()
.click(function () {
$("#dialog-form").data('projectID', this.id).dialog("open");
});
I am relatively new to jQuery and ASP.NET MVC as well, however, here's what first comes to mind.
In order to maintain the AJAX-y aspect of the page, I suggest that you create a method that handles a POST which returns a JSON formatted set of TaskManagementApplication.Models.Project. This method can optionally return filtered results.
The markup would look like this,
<div id="ProjectAccordionWrapper">
<div id="ProjectWrapperTemplate" class="ProjectWrapper" style="display: none;">
<h3 id="itemName"></h3>
<div class="column">
<button class="createTaskButton" id="itemProjectID">Create New Task</button>
<div id="portletTemplate" class="portlet">
<div class="portlet-header" id="taskName"></div>
<div class="portlet-content" id="taskDescription"></div>
<button class="editTaskButton" id="taskID">Edit Task</button>
</div>
</div>
</div>
</div>
Next, you would have jQuery clone the ProjectWrapperTemplate element, and set all of the corresponding fields.
$(function () {
$.ajax({
url: '/Project/GetTasks',
type: "POST",
data: { }
}).done(function (data) {
data.forEach(function (element) {
AppendProjectWrapper(element);
});
});
function AppendProjectWrapper(data) {
var projectAccordionWrapper = $('#ProjectAccordionWrapper');
var projectWrapper = $('#ProjectWrapperTemplate').clone(true, true);
projectWrapper.id = nothing; // remove the id, so as to not have duplicates
projectWrapper.style.display = nothing; // remove the style "display: none"
var itemName = projectWrapper.children('#itemName'); // h3
itemName.id = nothing;
itemName.text(data.ItemName);
var itemProjectID = projectWrapper.children('#itemProjectID'); // button Create New Task
itemProjectID.id = data.ItemProjectID;
var portletTemplate = projectWrapper.children('#portletTemplate'); // div
data.Tasks.forEach(function (element) {
var portlet = portletTemplate.clone();
portlet.id = nothing;
var taskName = portlet.children('#taskName');
taskName.id = nothing;
taskName.text(element.TaskName);
var taskDescription = portlet.children('#taskDescription');
taskDescription.id = nothing;
taskDescription.text(element.TaskDescription);
var editTaskButton = portlet.children('#taskID');
editTaskButton.id = element.TaskID;
portlet.appendTo(projectWrapper);
});
portletTemplate.remove(); // remove the portlet template element
projectWrapper.appendTo(projectAccordionWrapper);
}
}
Finally, have '/Project/SaveTask' return a JSON formatted TaskManagementApplication.Models.Project of the currently saved task.
$.ajax({
url: '/Project/SaveTask',
type: "POST",
data: { "taskName": taskName, "taskDescription": taskDescription, "taskID": id }
}).done(function (data) {
AppendProjectWrapper(data);
});
The return data for '/Project/GetTasks' should look as follows:
[
{
ItemName: '#item.Name',
ItemProjectID: '#item.ProjectID',
Tasks: [
TaskName: '#task.TaskName',
TaskDescription: '#task.TaskDescription',
TaskID: '#task.TaskID'
]
}
]
The return data from '/Project/SaveTask' should follow the same format, except or the outer-most array.
Please note that a lot of this code is untested.
It may be easiest to refactor the list into another action+view. Then, you can call this in both the original Index.cshtml view, and via the .load() method in jQuery. So, assuming this:
Projects controller
[HttpGet]
[ChildActionOnly]
public ActionResult Tasks(int id)
{
// create the appropriate model object as an IEnumerable of your Task type
return View(model);
}
Tasks.cshtml
#foreach(var task in Model) {
var buttonClass = "taskID" + task.TaskID;
<div class="portlet">
<div class="portlet-header">#task.TaskName</div>
<div class="portlet-content">#task.TaskDescription</div>
<button class="editTaskButton" id="#task.TaskID">Edit Task</button>
</div>
}
You would adjust Index.cshtml like so:
#model IEnumerable<TaskManagementApplication.Models.Project>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<div id="ProjectAccordionWrapper">
#foreach (var item in Model)
{
<div class="ProjectWrapper">
<h3>#item.Name</h3>
<div class="column">
<button class="createTaskButton" id="#item.ProjectID">Create New Task</button>
<div id="tasks-#item.ProjectID">
#Html.Action("Tasks", "Project", new { id = item.ProjectID })
</div>
</div>
</div>
}
</div>
//... the rest of the view
And finally,
// this should happen inside the callback of your .ajax() method
$('#tasks-'+projectID).load('/project/tasks/'+ projectID);

Categories

Resources