AJAX does not get triggered, asp.net - c#

Now it only get the AuctionId value in to the controller the other props are either null or 0...
Here is the form:
<form id="createBid">
<div id="frmBid" class="form-inline">
<input name="Bidder" asp-for="#bidModel.Bidder" value="#User.Identity.Name" type="hidden" />
<input name="AuctionId" asp-for="#bidModel.AuctionId" value="#Model.AuctionId" type="hidden" id="auctionId" />
<label asp-for="#bidModel.Amount" />
<input name="Amount" asp-for="#bidModel.Amount" />
<button type="submit" id="submitBtn" class="btn btn-primary">Lägg</button>
</div>
</form>
Here is the action in the controller:
public async Task<IActionResult> AddBid(BidModel Bid)
{
var result = await _bidBusinessInterface.CreateBidAsync(Bid, Bid.AuctionId);
if (result)
{
ViewBag.Message = "Bud lagt!";
}
else
{
ViewBag.Message = "Bud förlågt!";
}
return RedirectToAction("ViewDetails");
}
And then we have the actual AJAX call:
$('#createBid').on('submit', function (e)
{
e.preventDefault();
var $form = $(this);
$.ajax({
url: '#Url.Action("AddBid")',
type: 'POST',
dataType: 'html',
data: $form.serialize(),
success: function (html)
{
$('#frmBid').html(html);
}
});
});
I'm posting the model here aswell, if it is needed to see where it goes wrong:
public class BidModel
{
[JsonProperty("BudID")]
public string BidId { get; set; }
[JsonProperty("Summa")]
public int Amount { get; set; }
[JsonProperty("AuktionID")]
public string AuctionId { get; set; }
[JsonProperty("Budgivare")]
public string Bidder { get; set; }
}
I'm very grateful for every answer! This has been bugging me for 2 hours..

You are using your asp helpers wrong.
let's take this sample of code:
<input name="Bidder" asp-for="#bidModel.Bidder" value="#User.Identity.Name" type="hidden" />
you set the name to "Bidder" this is what the data will be bound to, when you need "Bid.Bidder" since "Bid" is the name of the object that the action receives.
Now you DO NOT need to set the name attribute since asp-for helper does it for you, it will automatically generate name, id attributes for you.
now make sure at the top of you page you have #model YourNamespace.BidModel
and reference it like so:
<input asp-for="#Model.Bidder" value="#User.Identity.Name" type="hidden" />
the attributes will be generated automatically and the model should be bound correctly.

Related

Always get null exceptions when using API POST to an Entity Framework controller from a React front-end

I am using .NetCore 3.1 Entity Framework to create an online gaming system.
I have a bunch of models and controllers setup and each model represents a table in my MSSQL database and each model has a controller.
The controllers for those models are working fine.
But now, I have a form where the user will create a new object consisting of two different models.
So when the user submits the form, it will need to create a new item in both models/tables.
So I created a separate model class just for that like this:
namespace My_Game.Models
{
public partial class CreateGame
{
public virtual StarSystem StarSystem { get; set; }
public virtual Ship Ship { get; set; }
}
}
Here are the two models the above model uses:
public partial class StarSystem
{
public string Name { get; set; }
public long Location { get; set; }
}
public partial class Ship
{
public string Name { get; set; }
public string Type { get; set; }
public long MaxCrew { get; set; }
}
And here is my controller that is supposed to handle the API call:
[HttpPost]
public async Task<ActionResult> ProcessForm([FromBody] CreateGame newGameEntry)
{
// Read StarSystem data from form and add to DB via EF
_context.StarSystem.Add(newGameEntry.StarSystem);
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateException)
{
if (StarSystemExists(newGameEntry.StarSystem.Id))
{
return Conflict();
}
else
{
throw;
}
}
// Read mentor data from form and add to DB via EF
_context.Ship.Add(newGameEntry.Ship);
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateException)
{
if (ShipExists(newGameEntry.Ship.Id))
{
return Conflict();
}
else
{
throw;
}
}
return Ok();
}
private bool ShipExists(long id)
{
return _context.Ship.Any(e => e.Id == id);
}
private bool StarSystemExists(long id)
{
return _context.StarSystem.Any(e => e.Id == id);
}
Here is the frontend React component that is used to send the form to the API:
import React, { useState } from 'react';
import axios from 'axios';
const App = () => {
const handleSubmit = (e) => {
e.preventDefault()
const { myForm } = e.target.elements.myForm
axios.post('https://localhost:44376/api/formprocessor', { form: myForm })
}
return (
<div id="newGameForm">
<form id="myForm" onSubmit={handleSubmit}>
<input type="text" name="starSystemName" placeholder="Enter star system name:" />
<input type="text" name="starSystemLocation" placeholder="Enter star system location:" />
<input type="text" name="shipName" placeholder="Enter ship name:" />
<input type="text" name="shipType" placeholder="Enter ship type:" />
<input type="text" name="shipMaxCrew" placeholder="Enter max crew:" />
<button type="submit">Submit</button>
</form>
</div >
)
}
But whenever I try to hit the controller from the react page, I just get this error when in debug mode:
System.ArgumentNullException: Value cannot be null. (Parameter 'entity')
I also tried testing with Postman, and put dummy test values in the body and I get the same error.
What am I missing?
Thanks!
The most likely problem is that the format of the sent data does not match to the model used in the action. The model binder is unable to populate based on what is being sent.
Since sending form data, update the action to expect data from a form
[HttpPost]
public async Task<ActionResult> ProcessForm([FromForm] CreateGame newGameEntry) {
//...
}
Next update the client side to send the appropriate form data.
const qs = require('querystring')
//...
const handleSubmit = (e) => {
e.preventDefault()
const { myForm } = e.target.elements.myForm
const form = new FormData();
for ( const key in myForm) {
form.append(key, myForm[key]);
}
axios({
method: 'post',
url: 'https://localhost:44376/api/formprocessor',
data: qs.stringify(form),
headers: {'Content-Type': 'application/x-www-form-urlencoded' }
});
}
return (
<div id="newGameForm">
<form id="myForm" onSubmit={handleSubmit}>
<input type="text" name="starSystem.Name" placeholder="Enter star system name:" />
<input type="text" name="starSystem.Location" placeholder="Enter star system location:" />
<input type="text" name="ship.Name" placeholder="Enter ship name:" />
<input type="text" name="ship.Type" placeholder="Enter ship type:" />
<input type="text" name="ship.MaxCrew" placeholder="Enter max crew:" />
<button type="submit">Submit</button>
</form>
</div >
)
Note the name change to match the structure of the models being sent. That way the model binder will know how to map the sent data to the intended models.
Reference Model Binding in ASP.NET Core
Based on the React Forms Refer to my below demo to post form data to controller:
import React, { Component } from 'react';
import axios from 'axios';
export class FormTest extends Component {
constructor(props) {
super(props);
this.state = {
starSystemName: "",
starSystemLocation:"",
shipName: "",
shipType: "",
shipMaxCrew:""
};
this.handleStarSystemName = this.handleStarSystemName.bind(this);
this.handleStarSystemLocation = this.handleStarSystemLocation.bind(this);
this.handleShipName = this.handleShipName.bind(this);
this.handleShipType = this.handleShipType.bind(this);
this.handleShipMaxCrew = this.handleShipMaxCrew.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleStarSystemName(event) {
this.setState({
starSystemName: event.target.value
});
}
handleStarSystemLocation(event) {
this.setState({
starSystemLocation: event.target.value
});
}
handleShipName(event) {
this.setState({
shipName: event.target.value
});
}
handleShipType(event) {
this.setState({
shipType: event.target.value
});
}
handleShipMaxCrew(event) {
this.setState({
shipMaxCrew: event.target.value
});
}
handleSubmit = (e) => {
e.preventDefault();
const data = new FormData();
data.append("starSystem.Name", this.state.starSystemName);
data.append("starSystem.Location", this.state.starSystemLocation);
data.append("ship.Name", this.state.shipName);
data.append("ship.Type", this.state.shipType);
data.append("ship.MaxCrew", this.state.shipMaxCrew);
axios({
method: 'post',
url: 'https://localhost:44301/WeatherForecast',
data: data,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});
}
render() {
return (
<div id="newGameForm" >
<form id="myForm" onSubmit={this.handleSubmit}>
<input type="text" value={this.state.starSystemName} placeholder="Enter star system name:" onChange={this.handleStarSystemName} />
<input type="text" value={this.state.starSystemLocation} placeholder="Enter star system location:" onChange={this.handleStarSystemLocation} />
<input type="text" value={this.state.shipName} placeholder="Enter ship name:" onChange={this.handleShipName} />
<input type="text" value={this.state.shipType} placeholder="Enter ship type:" onChange={this.handleShipType} />
<input type="text" value={this.state.shipMaxCrew} placeholder="Enter max crew:" onChange={this.handleShipMaxCrew}/>
<button type="submit">Submit</button>
</form>
</div >
)
}
}
Controller:
[HttpPost]
public async Task<ActionResult> ProcessForm([FromForm] CreateGame newGameEntry)

Get Selected Value of html dropdown in razor page dotnet

With the below code how can I get the value of the dropdown list using page handlers or tag helpers?
One way I've been reading is using OnChange on the dropdown, I can set the value of a hidden field with javascript then get value of hidden field from code behind. Should I even be using page handlers/tag helpers to get the dropdown value?
I have tried using Request.Form["networks"] but this just gives the ID and not the Value.
<form method="post">
#Html.DropDownList("networks",
Model.GetNetworks().Select(s => new SelectListItem()
{
Text = s.networks,
Value = s.id.ToString(),
}),
new
{
#class = "dropdown form-control",
})
<input type="hidden" id="selectedwifivalue" />
<br />
<input type="text" placeholder="enter wifi password" asp-for="Password" class="input-sm form-control" />
<br />
<button asp-page-handler="submit" class="btn btn-primary btn-sm form-control">Submit</button>
</form>
Model is
public class WifiNetworks
{
public int id { get; set; }
public string networks { get; set; }
public IEnumerable<SelectListItem> UserNetworks { get; set; }
}
Code behind in cshtml file
[BindProperty]
public string Password { get; set; }
public string networks { get; set; }
public void OnPostSubmit()
{
{
var password = Request.Form["password"];
var network = Request.Form["networks"]; <--this just gives the ID and not the value
var wifi = networks; <---this is blank
}
}
To access the form elements value, You can use Request.Form collection by passing the name of the form element.Set name property of html element and check.
Below is sample code for get form element value using name property.
View :
#using (Html.BeginForm("ReceiveValueWithRequestFormData", "ControllerAndAction"))
{
<ol>
<li>
#Html.Label("Username")
#Html.TextBox("txtUserName") : user
</li>
<li>
#Html.Label("Password")
#Html.TextBox("txtPassword") : pass
</li>
</ol>
<input type="submit" value="Login" />
}
<div id="divResult"></div>
Controller :
[HttpPost]
public ActionResult ReceiveValueWithRequestFormData()
{
string userName = Request.Form["txtUserName"];
string password = Request.Form["txtPassword"];
if (userName.Equals("user", StringComparison.CurrentCultureIgnoreCase)
&& password.Equals("pass", StringComparison.CurrentCultureIgnoreCase))
{
return Content("Login successful !");
}
else
{
return Content("Login failed !");
}
}
In the end I could have done it using ajax but using the hidden field approach it works fine like below no idea if this is a good/bad/better way to do this (I seemed to be asking those questions quite alot)
get value of dropdown using jquery "change" function (keep this outside of the
$(document).ready function as it wont fire)
$('#dnetworks').change(function () {
var selectedwifi = $('#networks option:selected').text();
$('#hiddenselectedwifivalue').val(selectedwifi); //set value of hidden field
});
Razor page
<input type="hidden" id="hiddenselectedwifivalue" asp-for="WifiNetworks.networks" />
.cshtml file
var selectedwififromdd = WifiNetworks.networks;
I used the bind for the whole class in the model page (.cshtml file)
public class WifiModel : PageModel
{
[BindProperty] public WifiNetworks WifiNetworks { get; set; }

How to pass a AJAX Response(true/false) from Controller using ASP .NET CORE

I want to retrieve the response from my ASP.NET Core Controller through AJAX. Here's the example of my code
public IActionResult Submit(ViewModel model) {
var isValid = true;
if (isValid) {
return Json(new {
success = true
});
}
return Json(new {
success = false
});
}
CSHTML part
<form asp-action="Submit" asp-controller="Home" id="formSubmit" name="formSubmit" method="post" enctype="multipart/form-data">
<input type="text" id="Name" name="Name">
<input type="text" id="Address" name="Address">
<input type="text" id="JobDescription" name="JobDescription">
</form>
$("#formSubmit").on('submit', function(e) {
var datas = {
Name: $("input[name='Name']").val(),
Address: $("input[name='Address']").val(),
JobDescription: $("input[name='JobDescription']").val()
};
var formAction = $(this).attr("action");
$.ajax({
method: "POST",
url: formAction,
data: JSON.stringify(datas),
dataType: "json",
contentType: 'application/json',
success: function(response) {
if (response.success) {
alert("Test");
return true;
} else {
alert("Invalid/Error");
e.preventDefault();
}
});
});
The problem in this code it redirect/loading to page showing the {"success":false}.
My ViewModel
public class ViewModel{
public string Name { get; set; }
public string Address { get; set; }
public string JobDescription { get; set; }
}
it seems there are a few issues present here
<form asp-action="Submit" asp-controller="Home" id="formSubmit" name="formSubmit" method="post" enctype="multipart/form-data">
You are specifying asp-action and asp-controller. Omit all of these properties. Start with just:
<form>...</form>
The reason being, when you set those attributes it uses the old-school form submission mechanism which redirects (one of the side affects you listed).
Also the name type seems to be a mismatch, you use ViewModel but in your example the type name is TFAViewModel
Try the following, above your controller (for each method) or above the method itself add
[Consumes("application/json")]
[Produces("application/json")]
public IActionResult Submit([FromBody]ViewModel model)
{
ModelState.IsValid; //use to inspect. You will also see any violations
....
}
In your JS code ensure to do the following (as has been commented)
e.preventDefault(); //stops redirect
Have you use [HttpPost] attribute on the Submit action? You need to set a specific url like "/Home/Submit" and have a reference to jquery.
Action:
[HttpPost]
[Consumes("application/json")]
[Produces("application/json")]
public IActionResult Submit(ViewModel model)
{
var isValid = true;
if (isValid)
{
return Json(new
{
success = true
});
}
return Json(new
{
success = false
});
}
View:
<form id="formSubmit" name="formSubmit" method="post" enctype="multipart/form-data">
<input type="text" id="Name" name="Name">
<input type="text" id="Address" name="Address">
<input type="text" id="JobDescription" name="JobDescription">
<input type="submit" value="Create" class="btn btn-default" />
</form>
#section Scripts{
<script src="~/lib/jquery/dist/jquery.js"></script>
<script>
$("#formSubmit").on('submit', function (e) {
var datas = {
Name: $("input[name='Name']").val(),
Address: $("input[name='Address']").val(),
JobDescription: $("input[name='JobDescription']").val()
};
e.preventDefault();
//var formAction = $(this).attr("action");
$.ajax({
method: "POST",
url: "/Home/Submit",
data: JSON.stringify(datas),
dataType: "json",
contentType: 'application/json',
success: function (response) {
if (response.success) {
alert("Test");
return true;
} else {
alert("Invalid/Error");
// e.preventDefault();
}
}
});
});
</script>
}

MVC reading multiple controls to a list - (posting elements with same name with special MVC formatting)

Screen shot of the post
I want to post multiple elements with same name to server, how to read the list to a collection, the control names names are formatted with special format found in a blog, still not able to access the data.
<input type="text" class="inputs" name="[1].SpecificationTitle" />
<input type="text" class="inputs" name="[1].SpecificationDescription" />
<input type="text" class="inputs" name="[2].SpecificationTitle" />
<input type="text" class="inputs" name="[2].SpecificationDescription" />
Reading
[HttpPost]
public ActionResult addBuyOnlinepostA(ICollection<SpecificationDetails> SpecificationDetails, FormCollection Collection)
{
}
public class SpecificationDetails
{
public string SpecificationTitle { get; set; }
public string SpecificationDescription { get; set; }
}
What if you use jquery/Ajax to get the data and then post it to server side.
<script>
$(document).ready(function () {
$("#submit").click(function () {
data = $(".inputs").map(function () { return $(this).val();});
var data2 = data.toArray();
alert(data2);
$.ajax({
type: "POST",
url: "#Url.Action("Action", "Controller")",
traditional: true,
data: {Data:data2 },
success: successFunc,
error: errorFunc
});
function successFunc(data) {
alert("success");
}
function errorFunc(data) {
alert("error");
}
});
});
<input type="text" class="inputs" name="[1].SpecificationTitle" />
<input type="text" class="inputs" name="[1].SpecificationDescription" />
<input type="text" class="inputs" name="[2].SpecificationTitle" />
<input type="text" class="inputs" name="[2].SpecificationDescription" />
<input type="button" id="submit" value="submit"/>`

AJAX Form Post - Not Passing Data

I have a form that that is not being passed to my controller.
It is hitting the controller method, but fails in passing any parameters, 'jsonString' is always NULL.
** Note: I have also tried using #razor w. model binding but was having the same issues.
Form:
<form id="CarreersForm">
<div class="form-group">
#Html.Label("Name")<br />
#Html.TextBoxFor(m => m.name)
</div>
<div class="form-group">
#Html.Label("Phone")<br />
#Html.TextBoxFor(m => m.phone)
#Html.ValidationMessage("Phone", new { #class = "text-danger" })
</div>
<div class="form-group">
#Html.Label("Email")<br />
#Html.TextBoxFor(m => m.email)
</div>
<div class="form-group">
<input type="file" id="filepath" name="filepath" value="Upload Resume" class="btn btn-default" />
<input type="submit" name="submit" id="submit" value="submit" />
</form>
JS/AJAX:
<script>
$(function () {
$("#submit").click(function (e) {
e.preventDefault();
var formData = {
"name": $("#CarreersForm #name").val(),
"phone": $("#CarreersForm #phone").val(),
"email": $("#CarreersForm #email").val(),
"filepath": $("#CarreersForm #filepath").val(),
};
var jsonString = JSON.stringify(formData);
console.log(jsonString);
$.ajax({
type: 'POST',
data: jsonString,
url: "#Url.Action("CarreersForm")",
dataType: "json",
contentType: "application/json; charset=utf-8",
cache: false,
success: function (response) {
if (response == 'True') {
alert("The form was successfully submitted.");
$("#contactUs form input").val("");
}
if (response == 'False') {
alert("There was an error submitting the form. Fill in all of the form fields with no errors.");
}
},
error: function (response) {
alert("There was an error submitting the form. Fill in all of the form fields with no errors.");
}
});
});
});
</script>
Controller:
//Current Method
[HttpPost]
public bool CarreersForm(string jsonString)
{
return false;
}
Copy of HTTP POST
NEW REQUEST
POST http://localhost:51721/Transportation/CarreersForm
REQUEST HEADERS:
Content-Type: application/json; charset=utf-8
X-Requested-With: XMLHttpRequest
Referer: http://localhost:51721/Transportation/Careers
Content-Length: 95
Cache-Control: no-cache
REQUEST BODY
{"name":"Mark","phone":"123456789","email":"email#emailaccount.com","filepath":"logo_main.png"}
CareersModel:
public class CareersModel
{
[Required]
public string name { get; set; }
public string job { get; set; }
[Required]
[EmailAddress]
public string email { get; set; }
[Phone]
public string phone { get; set; }
[Required]
public HttpPostedFileBase filepath { get; set; }
}
I have also tried passing the model directly:
[HttpPost]
public bool CarreersForm(ContactForm model)
{
if (!ModelState.IsValid){
return false;
}
return true;
}
I'm fairly certain that this is because you haven't set the correct encoding type on your form. Change it to the following to allow uploading files, this'll allow successful submission of your model.
<form id="CarreersForm" enctype="multipart/form-data">
Also: You won't be able to upload your documents using a jQuery AJAX request like that. It'd have to be either a standard post request, or using a plugin that allows ajaxified file uploads.
var formData = new FormData($("#CarreersForm")[0]);
use in ajax to data pass "data: jsonString,"
e.preventDefault() is the problem. It should come last with respect to your code arrangement as it only prevents the default action of the form from following the link provided in the form action attribute.
e.preventDefault() can prevent your form from passing the form parameters because it returns false and the rest of your commands have not been executed.
Also remember that e.preventDefault() method is supposed to be called on the form object itself, wherein you called it on the click event handler of the submit button.
Also setting request headers can prevent your Ajax from passing the form parameters to the PHP processing file.

Categories

Resources