Passing Values from React form to Controller and displaying result - c#

I have a question about using react with a function I set up in C# that has a controller to get values via the URL.
This is the Controller:
[HttpGet("{number}/{source}/{aux}/{destination}")]
public string Get(int number, string source, string aux, string destination)
{
Hanoi h = new Hanoi();
return h.MoveDisks(number, source, aux, destination);
}
This is what I've tried so far:
<script type="text/babel">
var Form = React.createClass({
calculate: function () {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (xhttp.readyState == 4 && xhttp.status == 200) {
document.getElementById("moves").innerHTML = xhttp.responseText;
}
};
xhttp.open("GET", "api/values" + "/" + "number" + "/" + "src" + "/" + "aux" + "/" + "dest", true);
xhttp.send();
},
render: function (){
return (
<div>
Number of rings: <input type="number" id="number"/> <br /><br />
Source: <input type="text" id="src"/><br /><br />
Auxiliary: <input type="text" id="aux"/><br /><br />
Destination: <input type="text" id="dest"/><br /><br />
<button onClick={this.calculate}>Get Result!</button>
</div>
);
}
});
ReactDOM.render(<Form />, document.getElementById('form'));
</script>
<div id="form"></div>
<div id="moves"></div>
I want the result to be posted in the "moves" div, but can't figure out how. Am I trying to use React in a way it's not supposed to work?
I'm a beginner so any help is appreciated.

You need to correct api route
[HttpGet]
[Route("api/values/{number}/{source}/{aux}/{destination}")]
public string Get(int number, string source, string aux, string destination)
{
Hanoi h = new Hanoi();
return h.MoveDisks(number, source, aux, destination);
}

Related

Sending simple type from HTML form to ASP API

I am having troubles with sending a simple double number from form to ASP API.
When I submit the form, I firstly need to remove Submit button to avoid sending a redundant 'submit=Submit' value to API controller.
As I have read in this article, I set the name of my input field to be empty. So if I check the http request in Developer mode, the body of sent data looks like so '=value'. My method parameter is decorated with [FromBody] attribute.
Even with all this, the controller method does not get the value. It is allways zero.
What to do?
My form looks like so:
<form action="#Url.Action("Temperature","Api")" method="post" >
<input type="number" name=" " step="0.25"/>
<input type="submit" name="submit" />
</form>
</div>
<script>
$("form").submit(function () {
$(this).children('[name="submit"]').remove();
});
</script>
The controller:
// POST: api/Temperature
public void Post([FromBody]double value) //FormDataCollection data
{
Temperature newEntry = new Temperature() { Timestamp = DateTime.Now, Value = value};
try
{
db.Temperatures.Add(newEntry);
db.SaveChanges();
}
catch(Exception e)
{
Debug.WriteLine(e.Message);
}
}
Try Ajax...
Change your Html little bit like this:
<div>
<input type="number" id="number" name=" " step="0.25"/>
<input type="button" id="submit" name="submit" />
</div>
Then:
$(document).on('click', '#submit', function () {
$.ajax({
type: 'POST',
url: '/ControllerName/Post',
data: {
value: JSON.stringify($('#number').val())
},
success: function (data) {
alert(data);
},
error: function (data) {
alert("An Issue has occured");
}
});
})
Also your controller input parameters would be like:
public void Post([FromBody]string value) //convert string to double later within method

ASP.NET MVC - Html.Action Sending Empty List

I am using Ajax to populate a partial view in my web application. This partial view contains a link to download a PDF file based upon the data that is currently in the table / List<> of the model.
The partial view is as follows:
#model Inspection_Reports.ViewModel.SummaryReportViewModel
<table id="summaryReportTable" class="table-condensed table-striped">
<thead><tr><td>Inspector</td><td>Attendant</td><td>Property</td><td>Room Number</td><td>Date</td><td>HK Score</td><td>Maint. Score</td></tr></thead>
<tbody id="resultsContainer">
#foreach (var report in #Model.reportsList)
{
<tr><td>#report.inspect.empName</td><td>#report.attendant.empName</td><td>#report.location.locName</td><td>#report.room</td><td>#report.endTime</td><td>#report.hkDisplay</td><td>#report.mainDisplay <input type='hidden' name='reportId[i]' /></td></tr>
}
</tbody>
</table>
#Html.ActionLink("Export as PDF", "GenerateSummaryPDF", new { summary = #Model.reportsList })
GenerateSummaryPDF method:
public FileResult GenerateSummaryPDF(List<report_summary> summary) {
Document doc = pdfWorker.readyDocument("Inspection Report, Generated " + DateTime.Now.ToString("MM-dd-yyyy"));
pdfWorker.createSummaryReport(doc, summary);
pdfWorker.savePDF(doc, String.Format("{0}/Inspection_Summary_{1}.pdf", #"C:\Users\Khandokar\Desktop", DateTime.Now.ToString("MM-dd-yyyy")));
return File(String.Format("{0}/Inspection_Summary_{1}.pdf", #"PATH", DateTime.Now.ToString("MM-dd-yyyy")), "application/pdf", "Inspection.pdf");
The problem is that, when the GenerateSummaryPDF is called, the summary list is empty. The list is not null, but merely has no items in it.
However, I am not sure why this is the case. When I click the export link, there is data in Model.reportsList; it is visible in the table and further verified by setting a breakpoint.
The parent view:
#model Inspection_Reports.ViewModel.SummaryReportViewModel
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Report Summaries</title>
</head>
<body>
<h2>Summary Reports</h2>
<form class="form-horizontal">
<div class="form-group"><label class="control-label col-md-2">Start Date: </label><div class="col-md-4"><input class="form-control summaryFilter" type='text' value="#Model.fromDate" name='startDate' id='startDate' /></div><label class="control-label col-md-2">End Date: </label><div class="col-md-4"><input type='text' value="#Model.toDate" class='form-control summaryFilter' name='endDate' id='endDate' /></div></div>
<div class="form-group">
<label class="control-label col-md-2">Filter By: </label>
<div class="col-md-4">
<select class="form-control summaryFilter" name="filterTypeList" id="filterTypeList">
<option value="">Select...</option>
<option value="Property">Property</option>
<option value="Attendant">Attendant</option>
<option value="Inspector">Inspector</option>
</select>
</div>
<label class="control-label col-md-2">Filter Selection: </label><div class="col-md-4">
<select class="form-control summaryFilter" name="filterSelectionList" id="filterSelectionList"></select>
</div>
</div>
</form>
<div id="reportResults">
#{Html.RenderPartial("SummaryPartialView", Model);}
</div>
#section scripts {
<script src="~/Scripts/ajaxReports.js"></script>
}
</body>
</html>
The methods used to populate the partial view (based largely on this article: https://cmatskas.com/update-an-mvc-partial-view-with-ajax/)
[HttpGet]
public async Task<ActionResult> GetSummaryReports(string fromDate, string toDate, string filterType, string filterValue)
{
DateTime from = Convert.ToDateTime(fromDate);
DateTime to = Convert.ToDateTime(toDate);
Int32 filterValID = Int32.Parse(filterValue);
SummaryReportViewModel vm = await GetSummaryVM(from, to, filterType, filterValID);
return PartialView("SummaryPartialView", vm);
}
private async Task<SummaryReportViewModel> GetSummaryVM(DateTime from, DateTime to, string filterType, int filterValID)
{
SummaryReportViewModel vm = new SummaryReportViewModel();
to = to.AddDays(1);
var reports = dbContext.report_summary.Where(r => r.endTime <= to && r.endTime >= from);
if (filterType.Equals("Property"))
{
reports = reports.Where(r => r.locationID == filterValID);
}
else if (filterType.Equals("Attendant"))
{
reports = reports.Where(r => r.employee == filterValID);
}
else
{
reports = reports.Where(r => r.inspector == filterValID);
}
vm.reportsList = reports.ToList<report_summary>();
return vm;
}
The Ajax
$(".summaryFilter").change(function () {
var fromDate = $("#startDate").val();
var toDate = $("#endDate").val();
var filterType = $("#filterTypeList").val();
var filterValue = $("#filterSelectionList").val();
if (filterValue != null || typeof (filterValue) != typeof (undefined)) {
$.ajax({
url: "GetSummaryReports?fromDate=" + fromDate + "&toDate=" + toDate + "&filterType=" + filterType + "&filterValue=" + filterValue,
type: 'get',
success: function (data) {
$("#reportResults").html(data);
},
});
}
});
Thanks for any help.
You're asking a bit much of a Get method - you should instead switch to a form that Posts to allow model binding to handle your complex list object.

How to upload multiple files asynchronously in ASP.NET MVC (C#) using Progress Bar

I am building an MVC based ASP.NET application. One of the functionalities should be to be able to upload files asynchronously using a progress bar.
I've had success with uploading files without the progress bar. The code below does that.
View Code:
<input class="file" type="file" name="file" id="file" />
<input type="submit" name="submit" value="Upload" />
Controller Code:
public ActionResult Upload(){
return View();
}
[HttpPost]
public ActionResult Upload(Resource resource)
{
try
{
if (resource.File.ContentLength > 0)
{
var fileName = Path.GetFileName(resource.File.FileName);
var path = Path.Combine(Server.MapPath("~/Content/Resources"), fileName);
resource.File.SaveAs(path);
}
}
catch (Exception e)
{
Console.WriteLine("Cannot upload file. Exception of type : {0}", e.ToString());
}
return RedirectToAction("Upload");
}
This code works absolutely fine. With slight modifications, I am even able to upload multiple files. But, even though I've tried finding it, I am not able to upload files using a progress bar.
Any help is appreciated.
This is how I do it - the controller code is much the same, but the client has some javascript in it to monitor and update progress of the ajax posting. The UI Html is like this:
<div id="uploadDetails" class="form-group">
<div class="input-group">
<span class="input-group-btn">
<span class="btn btn-primary btn-file">
Browse… <input type="file" name="file" id="file" />
</span>
</span>
<input type="text" id="filename" class="form-control fullwidth" readonly />
<span class="input-group-btn">
<button class="btn btn-primary" type="button" id="uploadFile"><span class="glyphicon glyphicon-upload"></span> Upload File </button>
</span>
</div>
</div>
And the javascript for the upload like this:
$(document).on('click', '#uploadFile', function (e) {
var fileElement = document.getElementById('file');
var file = fileElement.files[0];
var formData = new FormData();
formData.append("filename", fileElement.files[0].name);
formData.append("id", '#Model.SharedIP.Id');
formData.append("file", file, fileElement.files[0].name);
var html = $('#uploadFile').html();
$('#uploadFile').html('Uploading...');
$.ajax({
url: "#Url.Action("UploadFile", "SharedIP")",
type: "POST",
data: formData,
processData: false, // tell jQuery not to process the data
contentType: false, // tell jQuery not to set contentType
xhr: function(){
var xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener("progress", function(evt){
if (evt.lengthComputable) {
$('#uploadFile').html('Uploading... ' + Math.round((evt.loaded / evt.total) * 100) + '%');
}
else $('#uploadFile').html('hmmm');
}, false);
return xhr;
},
success: function (results) {
updateFilesList();
$('#uploadFile').html(html);
fileElement.files = [];
var control = $('#file');
control.replaceWith(control.clone(false));
$('#filename').val("")
},
error: function (xhr, ajaxOptions, thrownError) {
$('#uploadFile').html(html);
alert(xhr.responseText);
}
});
});
For completeness, here's the Controller signature, it's .net Core RC1 so might not work in your target framework, but you will get the idea.
[HttpPost]
public IActionResult UploadFile(string filename, Guid id, IFormFile file)
{
IPFile ipfile = new IPFile()
{
ContentType = file.ContentType,
DateUploaded = DateTime.Now,
Filename = filename,
SharedIPId = (id == Guid.Empty ? (Guid?)null : id),
Id = Guid.NewGuid(),
UploadedBy = User.Alias(),
};
ipfile = FileManager.AddFileFromStream(User.Alias(), ipfile, file.OpenReadStream());
return Ok(ipfile);
}
Hope that answers your question.
[EDIT] Just realised this isn't a "progress bar" - but it's got all the workings and % display - to put a progress bar in, you'd just apply CSS to an element that renders the % graphically for you - see posts like http://www.w3schools.com/bootstrap/bootstrap_progressbars.asp for examples.
Here is the code that I have tried. It's a bare minimum code but works as expected. It still has some bugs and I would appreciate if someone could make it bug free.
Some bugs:
Progress bar does not reset on a new file upload.
Add a button to do the upload (I can do it myself as well).
Model Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace NewDeploymentsTesting.Models
{
public class UploadFilesResult
{
public string Name { get; set; }
public int Length { get; set; }
public string Type { get; set; }
}
}
Controller Code:
using NewDeploymentsTesting.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace NewDeploymentsTesting.Controllers
{
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
return View();
}
[HttpPost]
public ContentResult UploadFiles()
{
var r = new List<UploadFilesResult>();
foreach (string file in Request.Files)
{
HttpPostedFileBase hpf = Request.Files[file] as HttpPostedFileBase;
if (hpf.ContentLength == 0) continue;
string savedFileName = Path.Combine(Server.MapPath("~/Content/Resource"), Path.GetFileName(hpf.FileName));
hpf.SaveAs(savedFileName);
r.Add(new UploadFilesResult()
{
Name = hpf.FileName,
Length = hpf.ContentLength,
Type = hpf.ContentType
});
}
return Content("{\"name\":\"" + r[0].Name + "\",\"type\":\"" + r[0].Type + "\",\"size\":\"" + string.Format("{0} bytes", r[0].Length) + "\"}", "application/json");
}
}
}
View Code:
#{Layout = null;}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Uploading Files</title>
<link href="~/Content/bootstrap/bootstrap.min.css" rel="stylesheet" />
<link href="~/Content/bootstrap/bootstrap-theme.css" rel="stylesheet" />
<link href="~/Content/jquery.fileupload.css" rel="stylesheet" />
<script src="~/Scripts/jquery-1.9.1.min.js"></script>
<script src="~/Scripts/jquery.ui.widget.js"></script>
<script src="~/Scripts/bootstrap.min.js"></script>
<script src="~/Scripts/jquery.fileupload.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$('#fileupload').fileupload({
dataType: 'json',
url: '/Home/UploadFiles',
autoUpload: true,
done: function (e, data) {
$('.file_name').html(data.result.name);
$('.file_type').html(data.result.type);
$('.file_size').html(data.result.size);
}
}).on('fileuploadprogressall', function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
$('.progress .progress-bar').css('width', progress + '%');
});
});
</script>
</head>
<body>
<div class="container">
<span class="btn btn-success fileinput-button">
<i class="glyphicon glyphicon-plus"></i>
<span>Add Files ...</span>
<input id="fileupload" type="file" name="files[]" multiple />
</span><br />
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
<span class="sr-only">0% Complete</span>
</div>
</div><br />
<div class="file_name"></div><br />
<div class="file_type"></div><br />
<div class="file_size"></div><br />
</div>
</body>
</html>
Here is what it looks like on the browser window.

jQuery to add and remove textboxes - just removes everything or nothing

So I have a simple ASP.NET/ C# generated html form where I have a list of textboxes that I want to be able to add and/or delete on the fly. There are pre-existing textboxes that are generated from a SP that look like this, with an 'add another textbox' button below:
<tr>
<td id="lblRole" style="vertical-align:top;" ><strong>The Role *</strong><br />(2000 characters maximum each)</td>
<td id="rolesColumn">
<div id="roles-1" class="div_row">
<textarea name="ctl00$mainContent$uxRolesList$ctl01" rows="5" cols="100"
id="ctl00_mainContent_uxRolesList_ctl01">yuyuy</textarea>
<input type="button" style="vertical-align:top;" value="X" class="remove-roles-btn" /><br /><br />
</div>
<input type="hidden" name="ctl00$mainContent$uxTxtBoxRolesCount"
id="ctl00_mainContent_uxTxtBoxRolesCount" value="1" />
</td>
</tr>
<tr>
<td> </td>
<td>
<input type="submit" name="ctl00$mainContent$uxAddRoleBtn"
value="Add a new role requirement"
id="ctl00_mainContent_uxAddRoleBtn" class="btn" />
</td>
</tr>
My jQuery is this:
$("#ctl00_mainContent_uxAddRoleBtn").live("click", (function (e) {
var rolesCounter = $('#ctl00_mainContent_uxTxtBoxRolesCount').val();
rolesCounter++;
if (rolesCounter < 10) {
var rolesCounterText = "0" + rolesCounter;
} else {
var rolesCounterText = rolesCounter;
}
$('#rolesColumn').append("<div id='roles-" + rolesCounter + "' class='div_row'><textarea name='ctl00$mainContent$uxRolesList$ctl" + rolesCounterText + "' rows='5' cols='100' id='ctl00_mainContent_uxRolesList_ctl" + rolesCounterText + "'></textarea><input class='remove-roles-btn' type='button' value='X' style='vertical-align:top;' /><br /><br /></div>");
e.preventDefault();
$('#ctl00_mainContent_uxTxtBoxRolesCount').val(rolesCounter);
}));
$(".remove-roles-btn").on("click", (function (e) {
$(this).parents('.div_row').remove();
e.preventDefault();
var rolesCounter = $('#ctl00_mainContent_uxTxtBoxRolesCount').val();
rolesCounter--;
$('#ctl00_mainContent_uxTxtBoxRolesCount').val(rolesCounter);
}));
But when I click to add a new textbox, all the textboxes are deleted.
And when I click to delete a textbox, nothing happens.
Thank you.
You have a typo in your code:
$("#ctl00_mainContent_uxAddRoleBtn").live("click", (function (e) {
//-------------------------------------------^----here you can see a "("
and here:
$(".remove-roles-btn").on("click", (function (e) {
//------------------^-----------------here
but i suggest you to use .on() method:
$(document).on("click", "#ctl00_mainContent_uxAddRoleBtn", function (e) {
and this:
$(document).on("click", ".remove-roles-btn", function (e) {
NOTE, be sure to be using jQuery 1.8.3 or lower, otherwise it will NOT work. All you have to do is change 'on' to 'live'
$(".remove-roles-btn").live("click", (function (e) {
Here is a simple example with your code that shows it working.
For remove button you need to use event delegation
$(document).on("click", "#rolesColumn .remove-roles-btn", function (e) {
e.preventDefault();
$(this).closest('.div_row').remove();
var rolesCounter = $('#ctl00_mainContent_uxTxtBoxRolesCount').val();
$('#ctl00_mainContent_uxTxtBoxRolesCount').val(rolesCounter - 1);
});
$(document).on("click", "#ctl00_mainContent_uxAddRoleBtn", function (e) {
var rolesCounter = $('#ctl00_mainContent_uxTxtBoxRolesCount').val();
rolesCounter++;
if (rolesCounter < 10) {
var rolesCounterText = "0" + rolesCounter;
} else {
var rolesCounterText = rolesCounter;
}
$('#rolesColumn').append("<div id='roles-" + rolesCounter + "' class='div_row'><textarea name='ctl00$mainContent$uxRolesList$ctl" + rolesCounterText + "' rows='5' cols='100' id='ctl00_mainContent_uxRolesList_ctl" + rolesCounterText + "'></textarea><input class='remove-roles-btn' type='button' value='X' style='vertical-align:top;' /><br /><br /></div>");
e.preventDefault();
$('#ctl00_mainContent_uxTxtBoxRolesCount').val(rolesCounter);
});
Demo: Fiddle

How to capture ajax drop down list value in MVC 3 view?

I have the following view that has tow dropdowns and one button:
#model RoomReservation.Webb.Models.HomeViewModel
#{
ViewBag.Title = "";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
<fieldset>
<legend>Select a city and a hotel</legend>
<br />
<br />
<br />
#Html.DropDownListFor(x=>x.City_DDL_ID, new SelectList(Model.AllCities, "Value", "Text"),"...pick a city..." )
<br />
<br />
#Html.DropDownListFor(x => x.Hotel_DDL_ID, Enumerable.Empty<SelectListItem>(), "...pick a hotel...", new { disabled = "disabled"})
<br />
<br />
<input id="SearchButton" type="submit" onclick="window.location.href='/Home/SearchForRooms'" disabled="disabled"/>
</fieldset>
<script type="text/javascript" language="javascript">
$('#City_DDL_ID').change(function () {
var selectedCity = $(this).val();
if (selectedCity != null && selectedCity != '-1') {
$.getJSON('#Url.Action("GetHotels")', { id: selectedCity }, function (hotels) {
var hotelsSelect = $('#Hotel_DDL_ID');
hotelsSelect.empty();
$.each(hotels, function (index, hotel) {
hotelsSelect.append($('<option/>',
{
value: hotel.Value,
text: hotel.Text
}));
});
$('#Hotel_DDL_ID').attr('disabled', false);
$('#SearchButton').attr('disabled', false);
});
}
});
</script>
<script type="text/javascript" language="javascript">
function onsubmitclcik() {
var SecondDrpId = $('#Hotel_DDL_ID').val();
window.location.href = '/Home/SearchForRooms?parameter=' + SecondDrpId;
}
I would like to get a value from second dropdown so that I can give it as paramater to my method f**ired from the button atribute "onclick". It is now working (above script).
But my action still gets null parameter. Here is the code:
public ActionResult SearchForRooms(int SecondDrpId)
{
if (SecondDrpId > -1)
return View(); //Here goes some model, not important
else
return RedirectToRoute("Home/Index");
}
Here is the Chrome parameter:
Request URL:http://localhost:22191/Home/SearchForRooms?parameter=3
Request Method:GET
thank you**
You can use following code to solve your problem.
<input id="SearchButton" type="submit" onclick="onsubmitclcik();" disabled="disabled"/>
Write a javascript function to call your next url,
function onsubmitclcik() {
var SecondDrpId = $('#Hotel_DDL_ID').val();
window.location.href = '/Home/SearchForRooms?parameter=' + SecondDrpId;
}
Why are you calling your action by setting window.location.href to your actions url?
That way, not a single parameter will be sent to your action.
Either add the parameter to the url and name it like your action paramter is named. In your example the parameter has to be called SecondDrpId:
onclick="window.location.href='/Home/SearchForRooms?SecondDrpId=' + $('#Hotel_DDL_ID').val()"
Or embed your dropdowns inside a form and post it to your action method.

Categories