Form.serialize() seems to return null - javascript

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()

Related

Ajax: Send a model to controller from list iterated by foreach loop

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();

grabbing form with jquery not working

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!

Using AJAX to submit form

I have developed a Python API and am now integrating it with a HTML template I have downloaded. It is a simple one page HTML template with a form to accept a album name and artist name. I am looking to process the form using AJAX. So once the form has been successfully submitted, it is replaced with a message returned by the API.
The (simplified) html snippet is:
<div class="form">
<form role="form" action="form.php" id="signup">
<div class="form-group">
<label>Artist Name</label>
<input type="text" name="artist" id="artist">
</div>
<div class="form-group">
<label>Tracking Number</label>
<input type="text" name="album" class="album">
</div>
<button type="submit" class="btn">Submit!</button>
</form>
</div>
Then I have a JS file I import at the beginning of the html file. Below is the JS file.
$(function() {
var form = $('#signup');
var formMessages = $('#form-messages');
$(form).submit(function(e) {
e.preventDefault();
var formData = {
'artist' : $('input[name=artist]').val(),
'album' : $('input[name=album]').val(),
};
// process the form
$.ajax({
type : 'POST',
url : 'form.php',
data : formData,
dataType : 'json'
})
.done(function(data) {
var content = $(data).find('#content');
$("#result").empty().append(content);
});
});
I think the issue is with the .done(function(data)) however, the website I found the code on wasn't clear.
form.php returns a JSON string. At the moment when I use the form, it sends the information to the Python API and the Python API returns a JSON message. But I cannot access the JSON message. It is in contains
'code': X, 'message':'returned messaged...'
ideally I would like to do a if/else statement. So
if code = 1:
display: Success
etc but I have no idea where to start with it in PHP/JS.
I was able to get it working eventually after seeing a few other stack overflow answers and another website.
I added one div to the html file under the button before the end of the form to make:
<form>
...
...
<button type="submit" class="btn">Submit!</button>
<div id="thanks" style="display:none;"></div>
</form>
Then, in the JS file I amended .done(function(data)) to be:
.done(function(data) {
if (data.result == '1') {
$('#thanks').show().text("Success!");
$('input[type="text"],text').val('');
} else if (data.result == '2') {
$('#thanks').show().text("Album and Artist already exists");
} else {
$('#thanks').show().text("Uh Oh. Something has gone wrong. Please try again later or contact me for more help");
}
});

Retrieving strings in Parse

I am trying to retrieve two strings from my Parse Customers class. I want to compare these strings (usernameAdmin, and passwordAdmin respectively) with the input field entered by the user, and if they matched it will take them to a specific page.
I am taking this approach for a particular reason, and would appreciate feedback.
$scope.logIn = function(form) {
var Customer = Parse.Object.extend("Customers");
parseAdminUsername = Customer.get('usernameAdmin');
parseAdminPassword = Customer.get('passwordAdmin');
if (form.lusername == parseAdminUsername && form.lpassword == parseAdminPassword) {
window.location = 'adminSelect.php'
} else {
alert('error');
}
};
The html code looks as follow:
<form role="form" ng-show="scenario == 'Sign up'">
<h4 id="wrongCredentials"></h4>
<input id="signupformItem" ng-model="user.lusername" type="email" name="email" placeholder="Email Address"> <br>
<input id="signupformItem" ng-model="user.lpassword" type="password" name="password" placeholder=" Password"> <br>
<br>
<button id="signupbuttonFinal" ng-click="logIn(user)" class="btn btn-danger"> Sign In</button>
</form>
I receive the following error on console:
undefined is not a function
at Object.$scope.logIn
below is the line
parseAdminUsername = Customer.get('usernameAdmin');
You are better off using Parse in built users instead of creating a separate object and then you would use Parse.User.logIn.
If you were to use your table instead. Customer.get('usernameAdmin') is used to return a field after you have performed a query to return records/s. You are best to perform a find query to check the username and password like so:
var Customer = Parse.Object.extend("Customers");
var query = new Parse.Query(Customer);
query.equalTo("usernameAdmin", form.lusername);
query.equalTo("passwordAdmin", form.lpassword);
query.find({
success: function(results) {
if (results.length > 0) {
window.location = 'adminSelect.php';
}
},
error: function(error) {
// The object was not retrieved successfully.
// error is a Parse.Error with an error code and message.
}
});
I'd recommend not to use window and instead $window so that you can unit test your code. Better yet use angular routing and create a Single page app.

Parse Data and Javascript/HTML Form

I'm using the Data module from Parse. I'm using HTML to create an email form. I use Javascript to get the form data (email), and then generate a username from the email address. This information is then saved to the Parse database.
Here's the HTML form code:
<form method="post" class="center">
<input id="email" name="email" type="email" placeholder="Type your email to create a Mail Link" />
<button id="submit" onclick="formSubmit();">Create</button>
</form>
Here's the Javascript:
function formSubmit() {
var emailValue = document.getElementById("email").value;
var userValue = emailValue.substr(0, emailValue.indexOf('#'));
Parse.initialize("---KEY---", "---KEY---");
var Users = Parse.Object.extend("Users");
var users = new Users();
users.save({username: userValue}).then(function(object) {
alert("Saved user");
});
users.save({email: emailValue}).then(function(object) {
alert("Saved email");
});
}
The problem is that the console is showing that the values are saved, however the data isn't saved into Parse.
Any ideas would be greatly appreciated!
In can make button a simple button, no need to change the button to a button as mention in the link you've mentioned, your code'll work fine.
You've written .then() method after saving the user data, but actually it's called to run the callbacks when the promise is fulfilled.
But here you're using simple Parse.Object, so either you've to use Parse.Promise, or if you want to use only simple Parse.Object when something like:-
users.save({
username: "Jake Cutter"
}, {
success: function(userObject) {
alert('The save was successful');
},
error: function(userObject, error) {
// The save failed. Error is an instance of Parse.Error.
// Do something if you want to do on error
}
});
For details you can check:-
https://www.parse.com/docs/js/symbols/Parse.Object.html#save
https://www.parse.com/docs/js/symbols/Parse.Promise.html#then
Okay, I awarded Indra the bounty, but here's the full answer for more context. This is an annoying problem, but you can solve it.
First, the form should use onsubmit.
<form method="post" onsubmit="formSubmit();">
Second, your function should use Indra's method to save data. But, you need event.preventDefault(); before it.
event.preventDefault();
userList.save({
username: "Peter Adams"
}, {
success: function(userList) {
alert('Success');
},
error: function(userList, error) {
alert('Failed to create new object, with error code: ' + error.message);
}
});
You can use jquery to store the form values and create a sub class of your parse class and also a new parse object to store the values in parse.
Example:
<form id="contact-form" >
First name:<br>
<input type="text" name="firstname" id="firstname">
<br>
Last name:<br>
<input type="text" name="lastname" id="lastname">
email:<br>
<input type="text" name="email" id="email">
<input type="submit" value="Get Access" />
</form>
Javascript code:
Parse.initialize("--KEY--", "--KEY--");
var Subscribers = Parse.Object.extend('Subscribers'); //create local parse object from your Parse class
$('#contact-form').submit(function(e) {
//on form submit
e.preventDefault();
//get data from form
var data = {
firstname: $("#firstname").val(),
lastname: $("#lastname").val(),
email: $("#email").val()
};
//create new Parse object
subscribers = new Subscribers();
//match the key values from the form, to your parse class, then save it
subscribers.save(data, {
//if successful
success: function(parseObj) {
alert(subscribers.get('firstname') + " " + subscribers.get('lastname') + " " + subscribers.get('email') + " saved to Parse.")
}
,
error: function(parseObj, error) {
console.log(parseObj);
console.log(error);
}
});
});

Categories