I am using JQuery 3.2.1 to grab input forms. the problem is that I don't get anything out, empty object or empty string. I tried with serialize, serialize array, code from SO to get the fields and transform to json, nothing did work.
I am sure that I wrote correctly the form id because the subscription of the function is successful.
here are part of the html:
<form role="form" id="organisationform">
<div class="row col-sm-offset-1">
<div class="form-group col-sm-5">
<label for="name" class="h4">Nom Organisation</label>
<input type="text" class="form-control" id="nomOrg" placeholder="Nom de l'organisation" required>
</div>
<div class="form-group col-sm-5">
<label for="lastname" class="h4">Identificateur </label>
<input type="text" class="form-control" id="idOrg" placeholder="Entrer IDentificateur" required>
</div>
</div>
...
</form>
and here is the js code:
onSubmit('form#organisationform', function() {
send('http://localhost:8080/organisation/ajouter', 'form#organisationform');
});
in an other file:
function grabForm(formId) {
var data = {};
$(this).serializeArray().map(function(x){data[x.name] = x.value;});
return data;
}
function send(url, formId) {
var data = grabForm(formId);
$.ajax({
url: url,
...
});
}
function onSubmit(idform, fn) {
$(idform).submit(function(event) {
event.preventDefault();
fn();
});
}
the problem is on the grab thing function it's returns an empty object, but before this form it was serialize function.
in an other test, I just Copy-Paste code from SO:
$('#organisationform').submit(function () {
var $inputs = $('#organisationform :input');
// not sure if you wanted this, but I thought I'd add it.
// get an associative array of just the values.
var values = {};
$inputs.each(function() {
values[this.name] = $(this).val();
});
alert(values);
//Do stuff with view object here (e.g. JSON.stringify?)
});
same problem.
SO how can I fix this? or how can I do it?
Seems like you are wrapping the jQuery functions in a load of your own functions which don't actually seem to add any value, but are overcomplicating things, in particular making the scope uncertain and making the flow of control hard to follow.
This should be sufficient to submit the form via ajax:
$("form#organisationform").submit(function(event) {
event.preventDefault();
$.ajax({
url: "http://localhost:8080/organisation/ajouter",
data: $(this).serialize(), //serialise the form, which due to the scope can be fetched via 'this',
method: "POST", //assuming it's a POST, but set it to whatever is right for your server
success: function(data) {
console.log(data); //receive any response from the server
},
error: function(jQXHR, textStatus, errorThrown) {
console.log(errorThrown + " " + textStatus); //log any HTTP errors encountered
}
//...etc
});
});
You may need to tweak things depending on what exactly the server expects to receive.
ouch! I changed the input with name attributes instead of id, now it can grab things!
Related
I need to be able to send a list of a model back to the controller from a view but only when the input has been checked.
Using AJAX I can get it working but the page refreshes and I don't catch the data but it does show up in the URL. Example: https://localhost:44308/PlayTest/PlayTest?personName=Test+User&DevOps-rate=3&Software+Development-rate=2&Solution+Architecture-rate=1&comments=&save=Save
But when I try and use Javascript and JQuery, I'm only able to catch the "person name" not the comments or rates in the post method.
HTML
<div class="tabcontent" id="testing">
<form name="skillform"
id="skillform"
asp-action="SaveRecord"
asp-controller="YourSkills"
data-ajax="true"
data-ajax-method="post">
<h3 class="tab-title">Testing</h3>
#foreach (var item in Model.Skills)
{
#if (item.SkillGroupID == 2)
{
<div class="star-rating">
<h5 class="skill-name" id="skill-title">#item.SkillName</h5>
<input type="radio" id="#item.SkillName#item.SkillGroupID-star3" name="#item.SkillName-rate" value="3" /><label for="#item.SkillName#item.SkillGroupID-star3" title="Advanced - 3 Stars">3 Stars</label>
<input type="radio" id="#item.SkillName#item.SkillGroupID-star2" name="#item.SkillName-rate" value="2" /><label for="#item.SkillName#item.SkillGroupID-star2" title="Intermediate - 2 Stars">2 Stars</label>
<input type="radio" id="#item.SkillName#item.SkillGroupID-star1" name="#item.SkillName-rate" value="1" /><label for="#item.SkillName#item.SkillGroupID-star1" title="Beginner - 1 Star">1 Stars</label>
</div>
<br />
<br />
}
}
<div class="comments">
<h6 class="comment-name">Comments</h6>
<textarea rows="4" cols="50" name="comments" id="comment-text-area" spellcheck="true"></textarea>
</div>
<div class="buttons">
<input type="reset" value="Clear">
<button type="button" class="edit" onclick="alert('This will allow the tab to be edited')">Edit</button> <!--add cancel button when opened-->
<input type="submit" name="save" value="Save" id="btnSave" skill-group="2"/>
</div>
</form>
</div>
Post Method
public JsonResult SaveRecord(string PersonName, List<SkillsModel> skill, string comment)
{
SkillsMatrixDB database = HttpContext.RequestServices.GetService(typeof(SkillsMatrix.Models.SkillsMatrixDB)) as SkillsMatrixDB;
List<PersonModel> people = database.GetAllPeople();
PersonModel recordingPerson = FindPerson(people, PersonName);
if (skill.Count() > 1)
{
for (int i = 0; i < skill.Count(); i++)
{
RecordsModel records = new RecordsModel();
records.PersonID = recordingPerson.PersonID;
records.SkillGroupID = skill[i].SkillGroupID;
records.SkillID = skill[i].SkillID;
records.SkillLevelID = Convert.ToInt32(HttpContext.Request.Form[skill[i].SkillName + skill[i].SkillGroupID + "-rate"]);
records.Comments = HttpContext.Request.Form["comments"].ToString();
records.DateSaved = DateTime.Now;
records.YearlyQuarter = DateTime.Now.Month / 3;
//database.SaveRecord(records);
}
}
else if (skill.Count() == 1)
{
RecordsModel records = new RecordsModel();
records.PersonID = recordingPerson.PersonID;
records.SkillGroupID = skill[0].SkillGroupID;
records.SkillID = skill[0].SkillID;
records.SkillLevelID = Convert.ToInt32(HttpContext.Request.Form[skill[0].SkillName + skill[0].SkillGroupID + "-rate"]);
records.Comments = HttpContext.Request.Form["comments"].ToString();
records.DateSaved = DateTime.Now;
records.YearlyQuarter = DateTime.Now.Month / 3;
//database.SaveRecord(records);
}
return Json(recordingPerson.Name);
}
JS
$(document).ready(function () {
$("#btnSave").click(function () {
$.ajax({
contentType: 'application/json; charset=utf-8',
dataType: 'json',
type: "POST", //HTTP POST Method
url: "YourSkills/SaveRecord", //Controller/View
data: $('#skillform').serialize(),
success: function (data) {
console.log(data);
alert('You saved it!');
},
error: function (jqXHR, textStatus, errorThrown) {
console.log(textStatus);
alert('Something went wrong. save failed!');
}
});
});
});
I feel like the way I've read to make the list in JS is wrong and to catch the data is not all that correct either. If someone could help that would be great. I'm so confused why doing it without JS works and picks up the right data but for some reason, I can't.
EDIT
I have tried what Emiel Zuurbier said but I am using Visual Studio 2019 and In the console, all I am getting is the following:
Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request starting HTTP/2.0 POST https://localhost:44308/PlayTest/YourSkills/SaveRecord application/json; charset=UTF-8 235
Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request finished in 6.0162ms 404
Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request starting HTTP/2.0 POST https://localhost:44308/PlayTest/SaveRecord application/x-www-form-urlencoded 233
Failed to load resource: the server responded with a status of 404 () [https://localhost:44308/PlayTest/YourSkills/SaveRecord]
Microsoft.AspNetCore.Routing.EndpointMiddleware: Information: Executing endpoint 'SkillsMatrix.Controllers.PlayTestController.SaveRecord (SkillsMatrix)'
error
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker: Information: Route matched with {action = "SaveRecord", controller = "PlayTest"}. Executing controller action with signature Microsoft.AspNetCore.Mvc.JsonResult SaveRecord(System.String, System.Collections.Generic.List`1[SkillsMatrix.Models.SkillsModel], System.String) on controller SkillsMatrix.Controllers.PlayTestController (SkillsMatrix).
Your page is being reloaded because you are submitting the form whenever you click the the #btnSave button. What you want to do is listen for the submit event on the form itself and cancel it with event.preventDefault(). This allows you to create your own submission behavior when submitting. And prevents the form from reloading the page.
$(document).ready(function() {
$('#skillform').on('submit', function(event) {
...
event.preventDefault();
});
});
Your HTML seems to miss the #skill-id element. If you mean to include data from your form into your controller then I suggest that you use hidden input fields instead of reading attributes from your elements.
<input type="hidden" name="skill-name" value="">
<input type="hidden" name="skill-id" value="">
<input type="hidden" name="skill-group" value="">
These fields will not be visible to the user but will contain data that the server is able to read.
Then instead of use .val() to get each individual field use $('form').serialize() to extract the name and value pairs out of the form and use them in your AJAX request. This way you are sending the same data as you would with a normal submit.
$.ajax({
contentType: 'application/json; charset=utf-8',
dataType: 'json',
type: "POST",
url: "YourSkills/SaveRecord",
data: $('#skillform').serialize(); // <-- Get all values from the form.
success: function (data) { // <-- data is the response you receive from the controller.
console.log(data);
alert('You saved it!');
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Something went wrong. save failed!');
}
});
I recommend that you check the $.ajax docs to use the correct methods and notation to use the function properly.
page reloading may happens because the error occurred in js execution while you are creating skills object.as its not the right way
define skills object this way rest of the things look good.
let skills = {};
skills['SkillID'] = $("#skill-id").val();
skills['SkillGroupID'] = $(this).attr('skill-group');
skills['SkillName'] = $("#skill-title").val();
I am trying to post a form to the controller in which the controller accepts a FormCollection as a parameter. When I try to access an item within the dsCollection I get null. The only items within the FormCollection is "__RequestVerificationToken" and "dsCollection". Another thing is I am generating my forms HTML dynamically using javascript and assigning values to them at the same time.
Here is my ajax to post data to serverside:
$(document).ready(function () {
$('#postEditDatasource').click(function (event) {
alert(JSON.stringify(deletedDatapoints));
//serialise and assign json data to hidden field
$('#dsDeletedDP').val(JSON.stringify(deletedDatapoints));
//anti forgery token
//get the form
var form = $('#__dsAjaxAntiForgeryForm');
//from the form get the antiforgerytoken
var token = $('input[name="__RequestVerificationToken"]', form).val();
var URL = '/Settings/EditDatasource';
console.log(form);
//we make an ajax call to the controller on click
//because the controller has a AntiForgeryToken attribute
//we need to get the token from the form and pass it with the ajax call.
$('#__dsAjaxAntiForgeryForm').on('submit', function () {
$.ajax({
url: URL,
data: {
__RequestVerificationToken: token,
dsCollection: form.serialize()
},
type: 'POST',
success: function (result) {
alert('this worked')
if (data.result == "Error") {
ShowDatasourcePostAlert('failPost', 3000);
} else {
ShowDatasourcePostAlert('successPost', 3000);
}
},
error: function (jqXHR, textStatus, errorThrown) {
alert(jqXHR + ', ' + textStatus + ', ' + errorThrown);
}
})
return false;
})
});
})
and here is my controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EditDatasource(FormCollection dsCollection)
{
var devName = dsCollection["deviceName"];
//LoadDataToViewModel();
//Get the name of the device in which we will pass it to the XML edit helper
//In order for us to locate the
//var getEditDatasource = Convert.ToString((from ds in dsVM.devices
// where ds.deviceID == Convert.ToInt64(dsCollection["dsID"])
// select ds.deviceName));
return new EmptyResult();
}
and here is a snippet of my HTML, I have too many controls but they pretty much follow the same formatting.
<div class="form-group">
<label class="col-md-2 control-label" for="deviceName">Device Name: </label>
<div class="col-md-10">
<input id="deviceName" class="form-control" type="text" data-val="true" data-val-required="Device name is required" name="deviceName" value="TestName">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="deviceDisplay">Displayed As: </label>
<div class="col-md-10">
<input id="deviceDisplay" class="form-control" type="text" data-val="false" data-val-required="Device name is required" name="deviceDisplay" value="testDisplay">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="deviceDesc">Description: </label>
<div class="col-md-10">
<textarea id="deviceDesc" class="form-control" data-val="false" name="deviceDesc">Test desc</textarea>
</div>
</div>
If I use serializeArray() it gives me back 31 entries however the entries are "dsCollection[0][name]" "dsCollection[0][value]" with the index going all the way up to 30
serialize method transform your form fields in a query string so you should just append the token to that string instead of creating another object.
If you inspect your request today you'll see that you're posting a value like this:
_RequestVerificationToken=token&dsCollection=deviceDesc%3Dcontent1%26deviceDisplay%3Dcontent2
When you have an antifogery token in a standard form, token data is sent alongside other input data (because actually it's just an hidden input) so the correct way to send it would be:
deviceDesc=content1&deviceDisplay=content2&_RequestVerificationToken=token
Other thing is, it looks like your anti forgery token is already inside your form so you do not need to do anything else than just form.serialize.
You can do the following in your javascript code:
data: form.serialize()
I'm a newbie Javascript learner and I want to post serialized data of input checkboxes. The data are sent to the server in order to update the corresponding field in SQL table. Later, the user can review the selections he made the first time and deselect some checkboxes. If I understand well, only the selected items will be sent, not the unselected ones. How can I send all the info I need to update the newly selected items and the newly unselected ones?
The only solution I found is to make 2 updates: the first resets to 0 all the rows and the second one sets to 1 the selected items (newly selected or not) that are sent in the serialized array. Is there a more optimal way to do the job? Ideally, I would update only the data that have changed. Is it possible?
Regards,
Patrick
If I understand it correctly you can filter the checkboxes and then you can add the unselected boxes to the parameters too.
I've found the code for that here at SO. See this question.
The demo below and here a jsfiddle is doing a ajax post only if the user changed the data. Not sure if this is what you want.
(The demo at SO is a bit modified because JSONP is required to get no CORS error.)
var data = "";
$('form').submit(function (evt) {
evt.preventDefault();
//console.log($(this).serialize());
var formData = $(this).serialize();
// source from this SO question https://stackoverflow.com/questions/10147149/how-can-i-override-jquerys-serialize-to-include-unchecked-checkboxes
// include unchecked checkboxes. use filter to only include unchecked boxes.
$.each($('form input[type=checkbox]')
.filter(function (idx) {
return $(this).prop('checked') === false
}),
function (idx, el) {
// attach matched element names to the formData with a chosen value.
var emptyVal = "off";
formData += '&' + $(el).attr('name') + '=' + emptyVal;
});
console.log(formData);
if ( data != formData ) { // check if user changed the data.
$.ajax({
url: 'http://jsfiddle.net/echo/jsonp/',
type: 'POST',
//data: formData, // this will work but for jsfiddle echo the code below is required.
dataType: "jsonp",
data: {
json: JSON.stringify({
serialized: formData
}),
delay: 1
},
success: function(res) {
console.log('posted: ', res);
}
});
}
data = formData;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
<label for="first">check1</label>
<input name="first" id="first" type="checkbox" />
<label for="second">check2</label>
<input name="second" id="second" type="checkbox" />
<label for="third">check3</label>
<input name="third" id="third" type="checkbox" />
<label for="fourth">check4</label>
<input name="fourth" id="fourth" type="checkbox" />
<input type="submit" value="update" />
</form>
I am looking for a way to take input from an HTML form and store it into a JSON object for use with AJAX. I can't use the normal $('#id').val();, because, as you can see below, there are a lot of fields. Here is some sample code
Javascript/jQuery:
$(document).ready(function() {
$('.add-to-cart').click(function() {
var id = $(this).attr('id');
//var qty = $(this).attr('qty'); <- need the quantity from the field
console.log(id);
//console.log(qty);
$.ajax({
url: 'addproduct',
type: 'POST',
datazType: 'JSON',
data: {
"id": id
//"qty": qty
},
success: function(addedproduct) {
console.log(addedproduct.name);
$('#cart').append('<li>'+ addedproduct.name +'</li>');
},
error: function() {
console.log('failed to add product');
}
})
});
});
HTML:
<p class="name">{{$product->name}}</p>
<input type="number" id="qty" class="qty" name="qty">
<button type="submit" id="{{$product->id}}" class="add-to-cart">Add to cart</button>
Help me please, or at least guide me in the right direction, this HAS to happen using AJAX.
jQuery's selialize method is what you are looking for. It serializes the values of inputs in a form.
Helpful example: https://stackoverflow.com/a/6960586/4180481
I've got some code that sends an ajax request when a form is being submitted. This works the first time the form is submitted (it's a search module), but only once. I've added an effect to highlight the table when data is returned, and you can only see it once (the data changes only once as well).
When I look at the response in the chrome dev tools, I can see it contains the data of the new search query but this isn't shown. Why can I only display results once?
JS:
$(function () {
// Creates an ajax request upon search form submit
var ajaxFormSubmit = function () {
var $form = $(this);
var options = {
url: $form.attr("action"),
type: $form.attr("method"),
data: $form.serialize()
};
$.ajax(options).done(function (data) {
var $target = $($form.attr("data-nn-target"));
var $newHtml = $(data);
$target.replaceWith($newHtml);
$newHtml.effect("highlight");
});
// Prevent default action
return false;
};
$("form[data-nn-ajax='true']").submit(ajaxFormSubmit);
});
HTML:
<form method="GET" action="#Url.Action("Index", "Show")" data-nn-ajax="true" data-nn-target="#contentlist" class="form-search">
<div class="input-append mysearch">
<input type="search" class="span5 search-query" name="query" data-nn-autocomplete="#Url.Action("AutoComplete")" />
<input type="submit" class="btn" value="Search" />
</div>
</form>
<div id="contentlist">
#Html.Partial("_Shows", Model)
</div>
I think you should use html() instead of replaceWith() method:
$target.html($newHtml);
just an idea... try
$target.html(data);
instead of
$target.replaceWith($newHtml);
By replaceWith, you might actually remove the div that you want to fill your content in. Then, the second time, it doesnt find the div to insert the content into.