Post form along with multiple files to Web API - javascript

I'm still new to how Web API 2.0 works but I'm starting to get the hang of things. The one issue I've been having though is how to post a form along with multiple files that the user uploaded to my controller.
I guess I mainly need help with how to use JavaScript or jquery with ajax to post all of the correct values.
Here is a snippit of my HTML:
<form id="CreateAnnouncementForm" class="form-horizontal">
<input type="hidden" name="announcementTypeID"/>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label class="col-sm-2 control-label">Headline</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="headline" />
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">More Info</label>
<div class="col-sm-10">
<textarea class="form-control" name="moreInfo"></textarea>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Attachments</label>
<div class="col-sm-10">
<input type="file" name="Attachments" multiple/>
</div>
</div>
</div>
</div>
</div>
</form>
Here is the JavaScript/jQuery/Ajax that I normally use to post my form to the controller:
onAnnouncementCreate: function () {
var form = $("#CreateAnnouncementForm");
var validator = $(form).kendoValidator().data("kendoValidator");
if (validator.validate()) {
var options = {
url: getApiUrl() + "/Announcement",
dataType: "json",
type: "POST",
headers: {
"Authorization": "Bearer " + getJwtToken(),
"LocationId": getCurrentLocation()
},
data: $(form).serialize(),
statusCode: {
200: function () {
$("#AnnouncementCreateModal").modal("hide");
announcementViewModel.reloadGrids();
},
400: function (response) {
toastr.options = { "positionClass": "toast-bottom-full-width";
toastr.error(response.responseText);
}
}
};
$.ajax(options);
}
}
Now I believe it would be best if I just created a ViewModel that contained both the ViewModel for all of the values in my form and have it contain an IEnumerable for the attachments that the users can upload within the form.
The trouble I'm having though is correctly adding the attachments to the form so that they map correctly.
My ViewModel will look like this:
public class AnnouncementCreateViewModel
{
public AnnouncementViewModel Announcement { get; set; }
public IEnumerable<HttpPostedFileBase> Attachments { get; set; }
}
Of course I would then need to change the names in my form to reflect the new model.
If anyone can help me on how to post them to my controller that would be much appreciated as that's the only thing I'm still struggling with.

Since this turned out to be more difficult than I thought it would be. I decided to go an alternative route.
Since I'm already using the Kendo UI framework, I am now using the Kendo Upload widget to handle the uploading of my files. I have it asynchronously upload the files to my Web API controller and then I have a separate action to handle the form when it's submitted.
Of course I'm welcome to other answers as well that might be able to solve this issue by posting all of the data in one call but for now, this will do.

Related

Bootstrap Searchable Drop down

New to web development. I am working on a ASP MVC app. Currently, I am working on a form, where I need a drop down box, that is searchable. Where I can click the drop down and see all the choices and also search it.
The data for this will be an Ajax request, that has a list of Json Objects, with properties Id and Name. "Id" will be the Option value and "Name" will be Option Name.
I looked through rest of the question regarding this, mostly the solutions were around Angular and ASP Web Forms.
I am not using Angular, please suggest solutions where I can use Bootstarp and Jquery to accomplish the same. Any external plugin suggestions?
Below is the current code:
<h1 class="col-sm-10 text-center">Data Import</h1>
<hr class="col-sm-10"/>
<form class="col-sm-10 form-horizontal">
<div class="form-group">
<label for="test" class="control-label col-sm-2">Name</label>
<div class="col-sm-10">
<select class="col-sm-10 form-control" id="tenantList">
<option value="1">Value</option>
</select>
</div>
</div>
</form>
<script>
$.ajax({
url: 'api/Tenant'
})
.done(function (data) {
$('#tenantList').html("");
var list = "";
$(data).each(function(idx, object) {
list += "<option value = " + object.id + ">"+object.name+"</option>";
});
$('#tenantList').html(list);
})
.fail(function() {
console.log("Problem :(");
});
</script>
Thanks.
Checkout Jquery UI' Combobox:
https://jqueryui.com/autocomplete/#combobox

ASP.NET Core Javascript Throwing Status 404 readyState 4 error (Apparently) my machine only

I think a more appropriate title is my private JavaScript Hell.
First off I am new to JavaScript. Never used it before this attempt.
Three or four weeks back when I first encountered this error I posted on ASP.Net forums and the good folks helped me out there. However after a full week of one hour a day concentrating on this issue I am no further advanced than I was three weeks ago even with their help. The issue seems to be either I am transcribing something incorrectly and I am blind (this wouldn't surprise me) or the error is specific to some aspect within my machine.
First the set up. I have a controller for jobs where I am wanting to cascade a drop down box content based on a preceeding selection. The two drop downs involved are Site and Waterbodys. The relevant part of the controller is:
public class JobsController : Controller
{
private readonly EVAContext _context;
public JobsController(EVAContext context)
{
_context = context;
}
// GET: Jobs/Create
public IActionResult Create()
{
ViewData["SiteID"] = new SelectList(_context.Sites, "SiteID", "SiteName");
ViewData["WaterBodyID"] = new SelectList(_context.WaterBodys, "WaterBodyID", "WBName");
ViewData["DepartmentID"] = new SelectList(_context.Departments, "DepartmentID", "iDepartment");
return View();
}
public IActionResult GetWaterBody(int siteID)
{
var waterBody = new List<WaterBody>();
waterBody = getWaterBodyFromDataBaseBySiteID(siteID);
return Json(waterBody);
}
public List<WaterBody> getWaterBodyFromDataBaseBySiteID(int siteID)
{
return _context.WaterBodys.ToList();
}
Within the associated view I have :
#model EVA.Models.Job
#{
ViewData["Title"] = "Add Job";
}
<h2>Add Job</h2>
<form asp-action="Create">
<div class="form-horizontal">
<hr />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="OrderNumber" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="OrderNumber" class="form-control" />
<span asp-validation-for="OrderNumber" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="SiteID" class="col-md-2 control-label"></label>
<div class="col-md-10">
<select asp-for="SiteID" class="form-control" asp-items="ViewBag.SiteID" id="site-target">
<option>---Select Site First---</option>
</select>
</div>
</div>
<div class="form-group">
<label asp-for="WaterBodyID" class="col-md-2 control-label"></label>
<div class="col-md-10">
<select asp-for="WaterBodyID" class="form-control" asp-items="ViewBag.WaterBodyID" id="wb-target">
<option>---Select Site First---</option>
</select>
</div>
</div>
<div class="form-group">
<label asp-for="DepartmentID" class="col-md-2 control-label"></label>
<div class="col-md-10">
<select asp-for="DepartmentID" class="form-control" asp-items="ViewBag.DepartmentID">
<option>---Select Department---</option>
</select>
</div>
</div>
<div class="form-group">
<label asp-for="JobNumber" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="JobNumber" class="form-control" value="1234" />
<span asp-validation-for="JobNumber" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="JobDescription" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="JobDescription" class="form-control" />
<span asp-validation-for="JobDescription" class="text-danger" />
</div>
</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>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
<script>
$(document).ready(function () {
$("#site-target").on("change", function () {
$list = $("#wb-target");
$.ajax({
url: "Jobs/GetWaterBody",//Core0309 is my controller name
type: "GET",
data: { id: $("#site-target").val() }, //id of the site which is used to extract waterbodies
traditional: true,
success: function (result) {
$list.empty();
$.each(result, function (i, item) {
$list.append('<option value="' + item["WaterBodyID"] + '"> ' + item["WBName"] + ' </option>'); //Must be lowercase ,if not ,you will get value 'Undefined'
});
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert(XMLHttpRequest.status);
alert(textStatus);
},
//error: function () {
// alert("Danger!! Will Robertson Danger!!!!!!!!!!!");
// }
});
});
});
</script>
<!--<script src="~/js/WaterBody.js"></script>-->
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
I previously had Waterbody.js which was also returning the same 404 based error.
What is frustrating and has led me here is on the ASP.Net forum the people there have copied my code to their own machine and it is running without error I am told. Although they are using a different set of drop downs.
I am seriously feeling like I am bashing my head against the wall. I have tried every suggestion, spent hours looking at examples on line and making minor changes to try and find the culprit but nothing works.
I am left with these questions:
1: Is my JobController code correct? Have I inadvertently introduced a stuff up there?
2: Is the script correct? I added alerts at one stage and I keep getting the idea the error is in the url but don't know that.
3: Is there some reference or dependency I may be missing on my machine specifically?
4: Some other question I haven't considered as I am still too new to this?
Help please. I am at the point where I must get this working to be able to move on with the balance of the project. Thanks in advance. I honestly hope this is a silly thing I done.
Bit of an update...
I added some alerts and they are indicating the error is occurring on $.ajax line.
alert("Inside")
$list = $("#wb-target");
alert("aferlist")
$.ajax({
Afterlist is firing but the next alert "Ajax" doesn't fire.

How to populate a whole form after ajax GET request?

I am working on ASP.NET MVC project and have an empty form rendered by MVC controller. Right after it's been rendered, I make an AJAX GET request, and receive JSON data to populate the form.
Everything works fine when I populate each individual field (please see code below), but I have a feeling that there is a better/righter way of how to populate the entire form in one shot. Please help.
In my $.get request, I tried:
$("#content").html(data);
It simply empties my form (all fields disappear).
Then I tried:
$("#content").val(data);
Here, all fields stay blank.
Anyways, here is the code that I have (please see below).
Here is my view (.cshtml file):
#model ViewModels.ProductDetailsViewModel
<form asp-controller="ApiProduct" asp-action="Post" id="content">
<div class="form-group">
<label asp-for="Name" class="control-label">Name</label>
<input asp-for="Name" type="text" class="form-control" id="js-name" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Description" class="control-label">Description</label>
<textarea asp-for="Description" rows="5" cols="40" class="form-control" id="js-description"></textarea>
<span asp-validation-for="Description" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</form>
#section Scripts {
<script>
var id = #Model.Id;
$.get("/apiproduct/get/?id=" + id, function (data) {
$("#js-name").val(data.name);
$("#js-description").val(data.description);
});
</script>
}
​
Here is my API controller:
[HttpGet("{id}")]
public IActionResult Get(int id)
{
var product = _repository.GetProductById(id);
return Ok(product);
}
Here is my MVC controller:
public IActionResult Details(int id)
{
var vm = new ProductDetailsViewModel()
{
Id = id;
};
return View(vm);
}
Apri478 ...Your API is giving you JSon result of your product and not html.
Above this line write console.log(data)
$("#content").html(data);
and see your response of API.
If you bind this json to form there are plenty of way.. writing custom js binding or using MVVM like angular or knockout.
try to explain more if this is not what you were expecting.

Bootstrap Validator and Ajax Begin Form Conflict in Partial Views, MVC

I am using Ajax.Begin Form to post data on a form without refreshing whole page, I need to validate the textbox, if it has value then the data should be posted else validation message should be shown, but the problem is validation and posting data are both occurring at same time. If I do not add jquery.unobtrusive-ajax.js file then my partial view would is returning as separate white page but validation is working and form is not posting until the textbox has value, BUT if I add jquery.unobtrusive-ajax.js file on page, it is posting data whether textbox has value or not. What is wrong with the code, I am not getting this at all. Please help I have spent two days tried my possible solutions and still no success.
This is my Main View(Parent View) having PartialView
<div id="div_SearchPatient2">
#Html.Partial("SearchPatientPartial");
</div>
#Scripts.Render("~/bundles/jqueryval")
jqueryval is a bundle which has jquery.unobtrusive-ajax.js file.
<div>
#using (Ajax.BeginForm("Search", "Patient", new { },
new AjaxOptions
{
HttpMethod = "POST",
UpdateTargetId = "patientfound"
},
new
{
#name = "SearchPatientForm",
#id = "frmSearchPatient",
}
))
{
#Html.AntiForgeryToken()
<div class="form-title">
Enter MR Number to search patient
</div>
<div class="col-lg-4">
<div class="form-group">
<div class="col-lg-6">
<label class="control-label">MR Number</label>
</div>
<div class="col-lg-6">
<input type="text" class="form-control" name="command" data-mask="999-99-99" placeholder="000-00-00" required data-bv-notempty="true" data-bv-notempty-message="MRNo. is required." />
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-4">
<input class="btn btn-darkorange" type="submit" value="Search" />
</div>
</div>
<div id="patientfound">
#Html.Partial("PatientFoundPartial")
</div>
}
</div>
Where patientfound is a div which will render details if found. I have given this in UpdateTargetId of AjaxBeginForm.
My Controller is returning PartialView
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Search(FormCollection collection, string id)
{
// some code to get data
return PartialView("PatientFoundPartial");
}
In the Ajax option write like this :
OnBegin = "return StartValidation();"
Now define a javascript function called StartValidation with this code :
function StartValidation(){ if($('fromid').validate()){return true;}return false;}

Strange issue with Ajax file upload (jQuery, ASP.Net MVC)

On several pages of my web site (ASP.Net MVC, jQuery, KendoUI SPA), I have a modal window to upload a file.
addAttachment: function (e) {
$("form").on("submit", function (event) {
event.preventDefault();
});
e.preventDefault();
var formData = new FormData($("#formUpload")[0]);
var url = 'api/Attachments/UploadAttachment';
app.postFile(url, formData, function (statusCode) {
if (statusCode === 201) {
// File was created -- do stuff
}
});
},
<div id="addAttachmentWindow"
data-role="window"
data-height="300px"
data-width="600px"
data-modal="true"
data-title="Add Attachment"
data-visible="false">
<div class="row">
<form id="formUpload" class="form-horizontal">
<input type="hidden" id="hdnRecordId" name="recordId" data-bind="value: object.id" />
<div class="form-group">
<label class="col-sm-4 control-label" for="txtDocumentTitle">Title</label>
<div class="col-sm-6">
<input name="documentTitle" id="txtDocumentTitle" type="text" class="k-textbox" />
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label" for="fuFileInput">Document</label>
<div class="col-sm-6">
<input id="fuFileInput" name="files" type="file" />
</div>
</div>
<div class="col-sm-6 col-sm-offset-6">
<button data-role="button" data-icon="plus" data-bind="click: addAttachment">Add Attachment</button>
</div>
</form>
</div>
</div>
With the code for postFile
var postFile = function(uri, formData, callback) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
callback(xhr.status);
}
};
xhr.open('POST', uri);
xhr.setRequestHeader("RequestVerificationToken", antiForgeryToken);
xhr.send(formData);
};
Most of the pages, this works fine, But on a couple of pages, it will issue the POST, without the form fields and immediately issue a GET for
/?recordId=1&documentTitle=documentTitleInput&files=FileNameHere.pdf
which goes to the Home Controller's Index function. If I go to one of the pages with this issue, do a Shift-Reload, and try the upload it will work as expected, the form fields are intact, and the callback is called.
Issues
Why the GET is being issued with the form fields in the query string immediately following the initial POST (even before the POST returns a response)
Why the form fields are empty, unless I do a shift-reload on some of pages, whilethe same code works fine on other pages.
I've tried creating an empty FormData, and appending the values to it, and played everything I can find to stop the normal submit event from happening (e.preventDefault(), e.stopPropogation(), return false etc.);
ok so some reading on the subject and its because the prevent default only works on elements, not on a form submit event, which is what your using...
create two submit inputs... one a button, the other a hidden input.. like so ..
<button type="button" id="submit">Submit</button>
<input style="display: none;" type="submit" id="realsubmit">
then do your jquery like so ...
$("#submit").on('click', function() {
//do stuff
$("#realsubmit").trigger('click');
});

Categories

Resources