MVC Model Binding Not Working via AJAX request - javascript

Having a little trouble with MVC model binding via AJAX.
Can someone tell me why the CreateTransfereeDetails property is not binding, it always comes back as 'null'.
Model:
public class ResolveProfileSelectionRequiredModel
{
public CreateTransfereeModel CreateTransfereeDetails { get; set; }
public bool NewTransfereeSelected { get; set; }
}
public class CreateTransfereeModel
{
[Display(Name = "Transferee Name:")]
public string TransfereeName { get; set; }
}
Html:
<input type="text" id="TransfereeName" />
<input type="hidden" id="NewTrasnfereeSelected" />
JavaScript:
var createTransfereeDetails =
{
"TransfereeName": $("#TransfereeName").val()
};
$.ajax({
url: "/myurl",
dataType: "json",
traditional: true,
type: "POST",
data: {
CreateTransfereeDetails: createTransfereeDetails,
NewTransfereeSelected: $("#NewTransfereeSelected").val()
},
success: function (result) {
//
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
//
},
complete: function () {
//
}
});
Thanks!

use name attribute on input fields inside form. Name attribute's valuesare automatically assigned to model's properties.
<form method="post" id="frm">
<input type="text" name="id="TransfereeName" " id="TransfereeName" />
<input type="hidden" name="NewTrasnfereeSelected" id="NewTrasnfereeSelected" />
<input type="button" onclick="submit()" value="submit" />
</form>
and use serialize() function of jquery to pass data using ajax
function submit(){
$.ajax({
url: "/myurl",
dataType: "json",
traditional: true,
type: "POST",
data: $('#frm').serialize(),
success: function (result) {
//
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
//
},
complete: function () {
//
}
});
}

Related

Request gets overridden with other data

I'm trying to get data for autocomplete using laravel.
Controller:
public function collection_search(Request $request) {
$term = $request->search;
$serveurapObj = new Serveurap();
$result = $serveurapObj->collectionAutocomplete();
return response()->json($result);
}
Model:
public function collectionAutocomplete($term) {
$where= ['m.supprime'=>'0', 's.supprime'=>'0'];
return DB::table('serveuraps AS s')
->select(DB::raw('s.nom as hostname'))
->join('machines AS m','m.id','=','s.machine_id')
->join('typeserveurs AS t','t.id','=','m.typeserveur_id')
->where($where)
->where('hostname','like','%'.$term.'%')
->get();
}
View:
<div class="col-md-12">
<div class="form-group">
<label class="col-md-3 control-label">{!! __('script.serveur') !!}</label>
<div class="col-md-4">
<input class="form-control" type="text" name="serveur" id="relance-serveur" role="textbox" aria-autocomplete="list" aria-haspopup="true">
</div>
</div>
</div>
Jquery/Ajax:
$(document).ready(function () {
// relance serveur autocomplete textbox
$('#relance-serveur').autocomplete({
source: function (request, response) {
alert(request.term)
$.ajax({
url: '/scripts/relanceCollection/collection',
dataType: 'json',
data: {
search: request.term
},
success: function (data) {
response(data);
}
});
},
});
});
I'm getting error when accessing the search from js in controller.
Error:
I printed $request but it showed the json data from model. how would I get the search from js to controller so that I can search data based on that term ?
The key you are sending is search, not term. Either change your controller code to reflect that, or change the ajax data.
$.ajax({
...
data: {
→ search: request.term
},
...
});
public function collection_search(Request $request)
{
$term = $request->search; ←
...
}
$.ajax({
...
data: {
→ term: request.term
},
...
});
public function collection_search(Request $request)
{
$term = $request->term; ←
...
}
You aliased the wrong class. You don't want an instance of a Facade, ever. If you want an instance of something you want the underlying instance, not the facade.
use Illuminate\Http\Request;
Now, $request would be an instance of that class and not the Facade, Illuminate\Support\Facades\Request.
I got the result by adding $.map function in success function in JS. if anyone needs it, please refer below js code:
$(document).ready(function () {
var headers = {
'X-CSRF-TOKEN':'<meta name="csrf-token" content="{{ csrf_token() }}">'
};
// relance serveur autocomplete textbox
$('#relance-serveur').autocomplete({
source: function (request, response) {
$.ajax({
url: '/scripts/relanceCollection/collection',
data: {
term: request.term
},
headers: headers,
dataType: 'json',
success: function (data) {
response($.map(data, function (item) {
return {
label: item.hostname,
value: item.hostname
};
}));
}
});
},
select: function (event, ui) {
$('#relance-serveur').val(ui.item.label); // display the selected text
return false;
},
minLength: 1
});
});

Razor autocomplete doesen't work when submitted

I'm having some problem with the autocomplete on my Razor project. Everytime it returns me error/failure. Maybe it could be even a stupid thing but I'm new to ASP so it would be difficult for me to notice.
Javascript Code
$(function () {
$('#searchCliente').autocomplete({
source: function (request, response) {
$.ajax({
url: '/Index?handler=Search',
data: { "term": request.term },
type: "POST",
success: function (data) {
response($.map(data, function (item) {
return item;
}))
},
error: function (response) {
alert(response.responseText);
},
failure: function (response) {
alert(response.responseText);
}
});
},
select: function (e, i) {
$("#idCliente").val(i.item.val);
$("#idFatt").val(i.item.val);
},
minLength: 3
});
});
Page Model Code
public IActionResult OnPostSearch(string term)
{
var clientefatt = (from cliente in this.context.Arc_Anagrafiche
where cliente.RagioneSociale.StartsWith(term)
select new
{
label = cliente.RagioneSociale,
val = cliente.IdAnag
}).ToList();
return new JsonResult(clientefatt);
}
HTML Code
<input asp-for="intervento.Cliente" class="form-control" id="searchCliente" />
<input asp-for="intervento.IdClienteFatturazione" class="form-control" id="idCliente" type="hidden" />
Perhaps the issue is related to the AntiForgeryToken, try to add the XSRF-TOKEN property in the request header before sending the Ajax request.
Please refer to the following samples and modify your code:
Add AddAntiforgery() service in the ConfigureServices method:
services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
In the Ajax beforeSend event, get the RequestVerificationToken from the hidden field, and set the request header:
#page
#model RazorPageSample.Pages.AutocompleteTestModel
<form method="post">
#Html.AntiForgeryToken()
<input type="text" id="txtCustomer" name="label" />
<input type="hidden" id="hfCustomer" name="val" />
<br /><br />
<input type="submit" value="Submit" asp-page-handler="Submit" />
<br />
</form>
#section Scripts{
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.10.0.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.ui/1.9.2/jquery-ui.min.js" type="text/javascript"></script>
<link href="https://ajax.aspnetcdn.com/ajax/jquery.ui/1.9.2/themes/blitzer/jquery-ui.css" rel="Stylesheet" type="text/css" />
<script type="text/javascript">
$(function () {
$("#txtCustomer").autocomplete({
source: function (request, response) {
$.ajax({
url: '/AutocompleteTest?handler=AutoComplete',
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
data: { "prefix": request.term },
type: "POST",
success: function (data) {
response($.map(data, function (item) {
return item;
}))
},
error: function (response) {
alert(response.responseText);
},
failure: function (response) {
alert(response.responseText);
}
});
},
position: { collision: "flip" },
select: function (e, i) {
$("#hfCustomer").val(i.item.val);
},
minLength: 1
});
});
</script>
}
Code in the .cshtml.cs file:
public IActionResult OnPostAutoComplete(string prefix)
{
var customers = new List<Customer>()
{
new Customer(){ ID=101, Name="Dillion"},
new Customer(){ID=102, Name = "Tom"},
new Customer(){ ID=103, Name="David"}
};
return new JsonResult(customers.Where(c=>c.Name.ToLower().StartsWith(prefix.ToLower())).Select(c=> new { label = c.Name, val = c.ID }).ToList());
}
public class Customer
{
public int ID { get; set; }
public string Name { get; set; }
}
Then, the screenshot as below:
Reference: jQuery AutoComplete in ASP.Net Core Razor Pages
Maybe you shall assign the ajax datatype property, and also change the "type" property from post to get, as below:
$.ajax({
url: '/Index?handler=Search',
data: { "term": request.term },
datatype: 'json'
type: "GET",
success: function (data) {
response($.map(data, function (item) {
return item;
}))
},
error: function (response) {
alert(response.responseText);
},
failure: function (response) {
alert(response.responseText);
}
});
Also in the Model code you can try one of the following,
as when returning json the JSONRequestBehavior property shall be specified as AllowGet:
return Json(new {clientefatt = clientefatt}, JsonRequestBehavior.AllowGet);
Change the Model code method's return type to JsonResult, as below
public JsonResult OnPostSearch(string term){
return new JsonResult(clientefatt);
}
Most probably the first options, since you're using .net core, will give you an error "ASP.NET Core - The name 'JsonRequestBehavior' does not exist in the current context"

How can I serialize a form in JavaScript asp.net

I am using some javascript to post my form but I dont want to have to submit each form field is there a way I can serlize this to an object in .net so that it will bring in all the form contents.
section Scripts {
<script>
function confirmEdit() {
swal({
title: "MIS",
text: "Case Created your Case Number is " + $("#Id").val(),
icon: "warning",
buttons: true,
dangerMode: true,
}).then((willUpdate) => {
if (willUpdate) {
$.ajax({
url: "/tests/edit/" + $("#Id").val(),
type: "POST",
data: {
Id: $("#Id").val(),
Name: $("#Name").val()
},
dataType: "html",
success: function () {
swal("Done!", "It was succesfully edited!", "success")
.then((success) => {
window.location.href = "/tests/index"
});
},
error: function (xhr, ajaxOptions, thrownError) {
swal("Error updating!", "Please try again", "error");
}
});
}
});
}
</script>
}
asp.net core will automatically bind json data using the [FromBody] attribute.
data: {
id: $("#Id").val(),
name: $("#Name").val()
},
and then in your controller
[HttpPost("/tests/edit/")]
public IActionResult Process([FromBody] MyData data){ ... }
where MyData is
public class MyData
{
public string Id {get;set;}
public string Name {get;set;}
}
section Scripts { function confirmEdit() {
swal({ title: "MIS", text: "Case Created your Case Number is " + $("#Id").val(), icon: "warning", buttons: true, dangerMode: true, }).then((willUpdate) => { if (willUpdate) {
var obj = { Id: $("#Id").val(), Name: $("#Name").val() }
$.ajax({ url: "/tests/edit/" + $("#Id").val(), type: "POST", data: JSON.Stringify(obj), dataType: "html", success: function () { swal("Done!", "It was succesfully edited!", "success") .then((success) => { window.location.href = "/tests/index" }); }, error: function (xhr, ajaxOptions, thrownError) { swal("Error updating!", "Please try again", "error"); } }); } }); } }
in c# use
public ActionResult FormPost(MyData obj)
Please refer to the following methods to submit the form data to action method:
using the serialize() method to serialize the controls within the form.
#model MVCSample.Models.OrderViewModel
<h4>OrderViewModel</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Showsummary" asp-controller="Home" method="post" class="signup-form">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="OrderId" class="control-label"></label>
<input asp-for="OrderId" class="form-control" />
<span asp-validation-for="OrderId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="OrderName" class="control-label"></label>
<input asp-for="OrderName" class="form-control" />
<span asp-validation-for="OrderName" class="text-danger"></span>
</div>
<div id="packages">
#for (int i = 0; i < Model.Packages.Count; i++)
{
<div class="form-group">
<label asp-for="#Model.Packages[i].Pid" class="control-label"></label>
<input asp-for="#Model.Packages[i].Pid" class="form-control" />
<span asp-validation-for="#Model.Packages[i].Pid" class="text-danger"></span>
<br />
<label asp-for="#Model.Packages[i].PackageTitle" class="control-label"></label>
<input asp-for="#Model.Packages[i].PackageTitle" class="form-control" />
<span asp-validation-for="#Model.Packages[i].PackageTitle" class="text-danger"></span>
</div>
}
</div>
</form>
</div>
</div>
<div>
<input type="button" id="summary" value="Summary" />
<div id="page_3">
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
$(function () {
$("#summary").click(function () {
console.log("calling summary");
event.preventDefault();
$.ajax({
type: "POST",
url: "/Home/Showsummary", //remember change the controller to your owns.
data: $("form.signup-form").serialize(),
success: function (data) {
console.log(data)
},
failure: function (response) {
console.log(response.responseText);
},
error: function (response) {
console.log(response.responseText);
}
});
});
});
</script>
Code the the action method:
[HttpPost]
public PartialViewResult Showsummary(OrderViewModel model)
{
try
{
//...
return PartialView("OrderSummary", model);
}
catch
{
return PartialView("OrderSummary", model);
}
}
After clicking the button, the result like this:
As we can see that, we could get the element's value in the form and even the nested entity.
Note: Only "successful controls" are serialized to the string. No submit button value is serialized since the form was not submitted using a button. For a form element's value to be included in the serialized string, the element must have a name attribute. Values from checkboxes and radio buttons (inputs of type "radio" or "checkbox") are included only if they are checked. Data from file select elements is not serialized.
Create a JavaScript object, and post it to action method.
Change the JavaScript script as below:
$(function () {
$("#summary").click(function () {
console.log("calling summary");
event.preventDefault();
//create a object to store the entered value.
var OrderViewModel = {};
//using jquery to get the entered value.
OrderViewModel.OrderId = $("input[name='OrderId']").val();
OrderViewModel.OrderName = $("input[name='OrderName']").val();
var packages = [];
//var count = $("#packages>.form-group").length; //you could use it to check the package count
$("#packages>.form-group").each(function (index, item) {
var package = {}
package.Pid = $(item).find("input[name='Packages[" + index + "].Pid']").val();
package.PackageTitle = $(item).find("input[name='Packages[" + index + "].PackageTitle']").val();
packages.push(package);
});
//add the nested entity
OrderViewModel.Packages = packages;
$.ajax({
type: "POST",
url: "/Home/Showsummary", //remember change the controller to your owns.
data: OrderViewModel,
success: function (data) {
console.log(data)
$('#page_3').html(data);
},
failure: function (response) {
console.log(response.responseText);
},
error: function (response) {
console.log(response.responseText);
}
});
});
});
By using the above code, I could also get the submit entity, you could refer to it.

Jquery FormData can append array to upload on net core?

I writed this code to upload file using Jquery
and I ready a model to maaping this ajax return
$("input[name='ResolutionAttachedFile']")
.each(function () {
var ReadyToUpload = $(this)[0].files;
if (ReadyToUpload.length > 0) {
$.each(ReadyToUpload, function (i, file) {
data.append("ResolutionAttachedFile", file);
});
}
});
test.append('MyIFormFile', data);
jQuery.ajax({
url: '/Home/DocumentPage',
data: test,
cache: false,
contentType: false,
processData: false,
type: 'POST',
success: function (data) {
alert(data);
}
});
and this is my controller and data model
public class test
{
public testArea MyIFormFile { get; set; }
public class testArea
{
public List<IFormFile> ResolutionAttachedFile { get; set; }
}
}
[HttpPost]
public IActionResult DocumentPage(test _test)
{
return View();
}
but this model can't mapping value.
and I don't want to change model structure.
so how can I do let it can working?
For binding to MyIFormFile.ResolutionAttachedFile, you need to pass with MyIFormFile.ResolutionAttachedFile.
Make a test with ajax below:
<div>
<input type="file" multiple name="ResolutionAttachedFile" />
</div>
#section Scripts{
<script type="text/javascript">
$("input[name='ResolutionAttachedFile']")
.change(function () {
var data = new FormData();
$("input[name='ResolutionAttachedFile']").each(function () {
var ReadyToUpload = $(this)[0].files;
if (ReadyToUpload.length > 0) {
$.each(ReadyToUpload, function (i, file) {
data.append("MyIFormFile.ResolutionAttachedFile", file);
});
}
});
jQuery.ajax({
url: '/DocumentPage',
data: data,
cache: false,
contentType: false,
processData: false,
type: 'POST',
success: function (data) {
alert(data);
}
});
});
</script>
}
Note
As my test, it will fail when the project is under netcoreapp2.1, it fail to bind when there is no extra properties in testArea. It only works when there is additionl properties like Name and set the name value from ajax.
For resolving this issue, you could migrate your project to netcoreapp2.2.
Here is my working .csproj
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<UserSecretsId>aspnet-IdentityCore-85ED30A8-40E9-4BD5-A9D2-EAF6BCF0D5F1</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0-preview3-35497" PrivateAssets="All" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.1.5" PrivateAssets="All" />
</ItemGroup>
</Project>

How to send ViewModel and a file in single Ajax POST request, in MVC 5?

I have an ASP.NET MVC 5 application. And I'm trying to send a POST request with the Model data, and also include user selected files.
Here is my ViewModel (simplified for clarity):
public class Model
{
public string Text { get; set; }
public long Id { get; set; }
}
Here is the controller Action:
[HttpPost]
public ActionResult UploadFile(long userId, Model model)
{
foreach (string file in Request.Files)
{
// process files
}
return View("Index");
}
Html input element:
<div>
<input type="file" name="UploadFile" id="txtUploadFile" />
</div>
And the JavaScript code:
$('#txtUploadFile').on('change', function (e) {
var data = new FormData();
for (var x = 0; x < files.length; x++) {
data.append("file" + x, files[x]);
}
data.append("userId", 1);
data.append("model", JSON.stringify({ Text: 'test text', Id: 3 }));
$.ajax({
type: "POST",
url: '/Home/UploadFile',
contentType: false,
processData: false,
data: data,
success: function (result) { },
error: function (xhr, status, p3, p4) { }
});
});
The problem is that when the Request reaches controller action, I have files and 'userId' populated, but 'model' parameter is always null. Am I doing something wrong when populating FormData object?
Here is what I test using with MVC5 and IE11 / chrome
View
<script>
$(function () {
$("#form1").submit(function () {
/*You can also inject values to suitable named hidden fields*/
/*You can also inject the whole hidden filed to form dynamically*/
$('#name2').val(Date);
var formData = new FormData($(this)[0]);
$.ajax({
url: $(this).attr('action'),
type: $(this).attr('method'),
data: formData,
async: false,
success: function (data) {
alert(data)
},
error: function(){
alert('error');
},
cache: false,
contentType: false,
processData: false
});
return false;
});
});
</script>
<form id="form1" action="/Home/Index" method="post" enctype="multipart/form-data">
<input type="text" id="name1" name="name1" value="value1" />
<input type="hidden" id ="name2" name="name2" value="" />
<input name="file1" type="file" />
<input type="submit" value="Sublit" />
</form>
Controller
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(HttpPostedFileBase file1, string name1, string name2)
{
var result = new List<string>();
if (file1 != null)
result.Add(string.Format("{0}: {1} bytes", file1.FileName, file1.ContentLength));
else
result.Add("No file");
result.Add(string.Format("name1: {0}", name1));
result.Add(string.Format("name2: {0}", name2));
return Content(string.Join(" - ", result.ToArray()));
}
}
Thanks to Silver89 for his answer

Categories