Serialize CSV files for ajax request in ASP app - c#

I've a form composed by a Kendo combobox and a Kendo file upload:
#using (Html.BeginForm("Methode", "controller", FormMethod.Post))
{
<p> Select country </p>
#(Html.Kendo().DropDownList().Name("country")
.DataTextField("Text").DataValueField("Value")
.DataSource(source => { source.Read(read => {
read.Action("GetMonth", "BudgetStage");
});
}))
<p> Select a .CSV file: </p>
#(Html.Kendo().Upload()
.Name("files")
.HtmlAttributes(new { accept = ".csv" })
)
<input type="submit" value="Submit" class="k-button k-primary" />
<input type="button" value="Ajax" class="k-button k-primary" onclick="postData(this)
}
Here is my C# controller code:
public JsonResult methode(IEnumerable<HttpPostedFileBase> files, string country)
{
return Json("It's OK !", JsonRequestBehavior.AllowGet);
}
This works when I click on the submit button, the controller receives files and string values but I need to display the Json returned value from my page.
To do that, I use this ajax function:
function postData(button) {
var form = $(button).parents('form');
if (form.kendoValidator().data("kendoValidator").validate()) {
$.ajax({
type: "POST",
url: form.attr('action'),
data: form.serialize(),
error: function (xhr, status, error) {
alert(error);
},
success: function (response) {
alert(response);
}
});
return false;
}
return false;
}
When I click on the Ajax button, the backend method is call, return the Json value and my JS code display it.
The problem is I receive the string value but not the selected CSV file (null).
How can I send the file and the string and display the returned Json value ?
Thank you in advance.

The problem is that form.serialize() doesn't really work in this scenario. With kendo it shouldn't be different to ASP.NET MVC + JavaScript, so basically, this should help you.

Related

Deleting a file from server on button click in ASP.NET MVC

I'm not well versed in this framework so I need some help here. In a view I want to add a link or a button on clicking which a certain file gets deleted from the server.
I've added this method to the controller:
[Authorize]
public ActionResult DeleteFile(string path)
{
if ((System.IO.File.Exists(path)))
{
try
{
System.IO.File.Delete(path);
}catch(Exception ex)
{
Debug.WriteLine("Deletion of file failed: " + ex.Message);
}
}
return View();
}
Seemed straightforward, though I'm not sure about the return View();. Now in the view, I need a form, because the path to the file that should be deleted needs to be posted to the controller, is that correct? This is what I got so far, mimicked from other code in the project:
#Html.BeginForm("DeleteFile", "Home", FormMethod.Post, new { id = "delete-attachment-form" })
{
#Html.Hidden("path", path)
}
path is a JavaScript variable containing the server path to the file that needs to be deleted. If I'm on the right track here, how do I add a button or a link to click on that will send the form?
Should just be able to add a submit button:
<input type="submit" name="submit" />
You should have a form and a button like this
#Html.BeginForm("Controller", "DeleteFile", new {Path= filePath},FormMethod.Post)
{
//Button
}
Or using Ajax and Jquery
var values = $(this).serialize();
$.ajax({
type: 'POST',
url: "url?path="+path.tostring(),
data: values ,
success: function(response) { //update view }
});
Inside your form you can add a button and then handle the button click in JavaScript.
#Html.BeginForm("DeleteFile", "Home", FormMethod.Post, new { id = "delete-attachment-form" })
{
#Html.Hidden("path", path)
<button id="delete-btn" type="button" class="btn btn-danger">
Delete
</button>
}
Then the <script type="text/javascript"> block:
$(function () {
$('#delete-btn').click(function () {
var query = $('#delete-attachment-form');
var form = query[0];
var toPost = query.serialize();
$.ajax({
url: form.action,
type: form.method,
data: toPost,
success: function (result) {
// display result
},
error: function () {
// handle error
}
})
});
});
Also, this is a good tutorial on deleting in ASP.NET MVC

Search method issue

I'm using MVC 5, C# and I'm trying to build a search filter that will filter through upon each key stroke. It works as so, but the textbox erases after submitting. Now this is probably not the best approach to it either. Is there a way to make so when it posts it doesn't erase the textbox, or better yet, is there a better alternative?
#using (Html.BeginForm("Index", "Directory", FormMethod.Post, new { id = "form" }))
{
<p>
Search Employee: <input type="text" name="userName" onkeyup="filterTerm(this.value);" />
</p>
}
<script>
function filterTerm(value) {
$("#form").submit();
event.preventDefault();
}
</script>
I agree with the comments on your question. Posting on every key stroke would be a frustrating user experience.
So, two answers, use ajax to perform the search (which will then keep the value since the whole page will not post) or have a submit button and name the input the same as the controller action parameter.
Controller code (used with your existing code):
public class DirectoryController : Controller
{
[HttpPost()]
public ActionResult Index(string userName)
{
// make the input argument match your form field name.
//TODO: Your search code here.
// Assuming you have a partial view for displaying results.
return PartialView("SearchResults");
}
}
View Code (to replace your code with Ajax):
<p>
Search Employee:#Html.TextBox("userName", new { id = "user-name-input" })
</p>
<div id="results-output"></div>
<script type="text/javascript">
$("#user-name-input").change(function(e) {
$.ajax({
url: '#Url.Action("Index", "Directory")'
, cache: false
, type: "post"
, data: {userName: $("#user-name-input").val() }
}).done(function (responseData) {
if (responseData != undefined && responseData != null) {
// make sure we got data back
$("#results-output").html(responseData);
} else {
console.log("No data returned.");
alert("An error occurred while loading data.");
} // end if/else
}).fail(function (data) {
console.log(data);
alert("BOOOM");
});
}
</script>
A better way is to ditch your Html.BeginForm (unless you actually need it for something else) and use a pure ajax method of getting the data.
So your modified html would be:
<p>
Search Employee:
<input type="text" name="userName" onkeyup="filterTerm(this.value);" />
</p>
<script>
function filterTerm(value) {
$.ajax({
url: '#Url.Action("Index", "Directory")',
data: {
searchTerm: value
},
cache: false,
success: function (result) {
//do something with your result,
//like replacing DOM elements
}
});
}
</script>
You also need to change the action that ajax will be calling (and I have no idea why you are calling the "Index" action).
public ActionResult Index(string searchTerm)
{
//lookup and do your filtering
//you have 2 options, return a partial view with your model
return PartialView(model);
//or return Json
return Json(model);
}
The best thing about this ajax is there is no posting and it's async, so you don't have to worry about losing your data.

call an c# mvc controller method from jquery using $.getJson Method

I'm clearly missing something but can't for the life of me see what it is so would appreciate if anyone could point out my error.
I have a simple details page with a form to add comments to the selected detail.
I have a view with the following formed contained within it:
#using (Html.BeginForm("Details", "Home", FormMethod.Post, new { id ="commentForm" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.NewComment.Name);
#Html.TextBoxFor(model => model.NewComment.Name, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(model => model.NewComment.Body);
#Html.TextAreaFor(model => model.NewComment.Body, new { #class = "form-control" })
</div>
<input type="submit" class="btn btn-primary" value="Add Comment" />
}
This view then calls the following c# controller method:
[HttpPost]
public ActionResult Details(int id,DetailsViewModel model)
{
if (!ModelState.IsValid)
return View(model);
var content =_data.First(c => c.Id == id);
content.Comments.Add(model.NewComment);
return View(new DetailsViewModel(content));
}
If I use the form without adding any additional code to catch the submit with jquery then this all works correctly.
When i add the following JQuery code to the page then the above server code is not executed (I know i am not actually returning any json in the above method but if the method is not executed that seems redundant for now?):
$(document).ready(function () {
$("#commentForm").submit(function (event) {
event.preventDefault();
var url = $(this).attr('action');
$.getJSON(url, $(this).serialize(), function (comment) {
alert(comment)
});
});
});
If is also worth noting that if i add any alerts around the getjson call then these all fire correctly.
Does anyone have any ideas about what i'm doing wrong?
When you are using .getJSON it makes a GET request, and your Details method only answers POST requests.
Try this instead:
$.ajax({
type: "POST",
url: url,
data: $(this).serialize(),
success: function(comment) {
alert(comment);
}
});
Try posting to the controller.
$.getJSON is performing a http get under the covers. Your controller endpoint is expecting a post and will not accept a http get.
Here is a function(blog reference) that will provide the same functionality:
(function ($) {
$.postJSON = function (url, data) {
var o = {
url: url,
type: "POST",
dataType: "json",
contentType: 'application/json; charset=utf-8'
};
if (data !== undefined) {
o.data = JSON.stringify(data);
}
return $.ajax(o);
};
} (jQuery));
Simply add this somewhere after your jQuery include.
use $.post() instead, when you use FormMethod.Post : http://api.jquery.com/jQuery.post/

Display a loading screen using anything

I sometimes have operation that takes a while to compute. I would like to be able to display something, like a kind of grey layer covering everything, or a loading screen, while the operation computes. But I frankly have no idea how to do it.
I'm building an MVC app using MVC4, I'm beginning with jQuery and opened to any suggestions. How might I do that?
EDIT
Here's a sample of page I've been building:
<h2>Load cards</h2>
<script type="text/javascript">
$(document).ready(function () {
$("form").submit(function (event) {
event.preventDefault();
alert("event prevented"); // Code goes here
//display loading
$("#loadingDialog").dialog("open");
alert("dialog opened"); // Never reaches here.
$.ajax({
type: $('#myForm').attr('method'),
url: $('#myForm').attr('action'),
data: $('#myForm').serialize(),
accept: 'application/json',
dataType: "json",
error: function (xhr, status, error) {
//handle error
$("#loadingDialog").dialog("close");
},
success: function (response) {
$("#loadingDialog").dialog("close");
}
});
alert("ajax mode ended");
});
});
</script>
#using (Html.BeginForm())
{
<div class="formStyle">
<div class="defaultBaseStyle bigFontSize">
<label>
Select a Set to import from:
</label>
</div>
<div class="defaultBaseStyle baseFontSize">
Set: #Html.DropDownList("_setName", "--- Select a Set")<br/>
</div>
<div id="buttonField" class="formStyle">
<input type="submit" value="Create List" name="_submitButton" class="createList"/><br/>
</div>
</div>
}
Here's a snippet of code from my javascript file:
$(document).ready(function ()
{
$(".createList").click(function() {
return confirm("The process of creating all the cards takes some time. " +
"Do you wish to proceed?");
});
}
As a bonus (this is not mandatory), I'd like it to be displayed after the user has confirmed, if it is possible. else I do not mind replacing this code.
EDIT
Following Rob's suggestion below, here's my controller method:
[HttpPost]
public JsonResult LoadCards(string _submitButton, string _cardSetName)
{
return Json(true);
}
And here's the "old" ActionResult method:
[HttpPost]
public ActionResult LoadCards(string _submitButton, string _setName)
{
// Do Work
PopulateCardSetDDL();
return View();
}
As of now the code never reaches the Json method. It does enter the ajax method up there (see updated code), but I don't know how to make this work out.
We hide the main content, while displaying an indicator. Then we swap them out after everything is loaded. jsfiddle
HTML
<div>
<div class="wilma">Actual content</div>
<img class="fred" src="http://harpers.org/wp-content/themes/harpers/images/ajax_loader.gif" />
</div>
CSS
.fred {
width:50px;
}
.wilma {
display: none;
}
jQuery
$(document).ready(function () {
$('.fred').fadeOut();
$('.wilma').fadeIn();
});
First you want to have jQuery "intercept" the form post. You will then let jQuery take care of posting the form data using ajax:
$("form").submit(function (event) {
event.preventDefault();
//display loading
$("#loadingDialog").dialog("open");
$.ajax({
type: $('#myForm').attr('method'),
url: $('#myForm').attr('action'),
data: $('#myForm').serialize(),
accept: 'application/json',
dataType: "json",
error: function (xhr, status, error) {
//handle error
$("#loadingDialog").dialog("close");
},
success: function (response) {
$("#loadingDialog").dialog("close");
}
});
});
More information on the $.ajax() method is here: http://api.jquery.com/jQuery.ajax/
You could use the jquery dialog to display your message: http://jqueryui.com/dialog/
There are other ways to display a loading message. It could be as simple as using a div with a loading image (http://www.ajaxload.info/) and some text, then using jQuery to .show() and .hide() the div.
Then, in your controller, just make sure you're returning JsonResult instead of a view. Be sure to mark the Controller action with the [HttpPost] attribute.
[HttpPost]
public JsonResult TestControllerMethod(MyViewModel viewModel)
{
//do work
return Json(true);//this can be an object if you need to return more data
}
You can try creating the view to load the barebones of the page, and then issue an AJAX request to load the page data. This will enable you to show a loading wheel, or alternatively let you render the page in grey, with the main data overwriting that grey page when it comes back.
This is how we do it in our application, however there is probably a better way out there...
if not I'll post some code!
EDIT: Here's the code we use:
Controller Action Method:
[HttpGet]
public ActionResult Details()
{
ViewBag.Title = "Cash Details";
return View();
}
[HttpGet]
public async Task<PartialViewResult> _GetCashDetails()
{
CashClient srv = new CashClient();
var response = await srv.GetCashDetails();
return PartialView("_GetCashDetails", response);
}
Details View:
<div class="tabs">
<ul>
<li>Cash Enquiry</li>
</ul>
<div id="About_CashEnquiryLoading" class="DataCell_Center PaddedTB" #CSS.Hidden>
#Html.Image("ajax-loader.gif", "Loading Wheel", "loadingwheel")
</div>
<div id="About_CashEnquiryData"></div>
<a class="AutoClick" #CSS.Hidden data-ajax="true" data-ajax-method="GET"
data-ajax-mode="replace" data-ajax-update="#About_CashEnquiryData"
data-ajax-loading="#About_CashEnquiryLoading" data-ajax-loading-duration="10"
href="#Url.Action("_GetCashDetails", "Home")"></a>
</div>
Custom Javascript:
$(document).ready(function () {
// Fire any AutoClick items on the page
$('.AutoClick').each(function () {
$(this).click();
});
});

How to upload a file through jQuery?

I am wondering how would I do this with like jQuery ajax. Right now I have a jQuery ui dialog box popup and it has an html input file on it.
Now when the user clicks import I want to do an ajax post to the server with jQuery.
I am not sure how to pass the file in though to my action view.
Right now I have it doing a full post back so I have this
<% using (Html.BeginForm("Import", "Controller", FormMethod.Post, new { enctype = "multipart/form-data" }))
{%>
<br />
<p><input type="file" id="file" name="file" size="23 accept="text/calendar"></p><br />
<p><input type="submit" value="Upload file" /></p>
<% } %>
Then in my controller
public ActionResult Import(HttpPostedFileBase file)
So I am not sure how to pass in an HttpPostedFileBase with jQuery and how to set enctype = "multipart/form-data" in jQuery.
Edit
Ok well the jQuery form plugin seems to be the way to go.
$('#frm_ImportCalendar').livequery(function()
{
var options = {
dataType: 'json',
success: function(response)
{
alert(response);
}
};
$(this).ajaxForm(options);
});
I was wondering why my json was not working but someone mentioned you can't use it just as is. I am checking out the other link where someone was able to use json.
I am not sure though why in Lck used .submit before the ajax submit method.
Edit
How could I change the file upload json result to return my dictionary array?
Dictionary<string, string> result = new Dictionary<string, string>();
result.Add("Msg", "Success!!");
result.Add("Body", calendarBody);
// how can I change this?
return new FileUploadJsonResult { Data = new { message = string.Format("{0} uploaded successfully.", System.IO.Path.GetFileName(file.FileName)) } };
Using the jQuery Form Plugin, you can accomplish an async file upload. Check-out the following link,
jQuery Form Plugin - Code Samples - File Uploads
http://jquery.malsup.com/form/#file-upload
Good luck!
As suggested by Dominic, use the jQuery Form plugin. The form you already built should already work correctly. Just add an ID to identify it:
<% using (Html.BeginForm("Import", "Controller", FormMethod.Post, new { id = "asyncForm", enctype = "multipart/form-data" }))
and use jQuery Form to post the data:
$(document).ready(function(){
$('#asyncForm').submit(function(){
$(this).ajaxSubmit({
beforeSubmit: function(){
//update GUI to signal upload
}
data: { additional = 'value' },
dataType: 'xml',
success: function(xml){
//handle successful upload
}
});
});
});
Note that the return dataType in forms that upload files cannot be JSON. Use XML or HTML as response in your controller's method.
I was able to upload a file via AJAX using the jQuery Form plugin and a custom JsonResult class as described here.
Use this to return something like your Dictionary
return new FileUploadJsonResult { Data = new { Msg = "Success!!", Body = calendarBody } };
and to get your message in the callback function
success: function(result) {
$("#ajaxUploadForm").unblock();
$("#ajaxUploadForm").resetForm();
alert(result.Msg);
}

Categories