Post HTML Table to Controller - javascript

I have a form where users can dynamically add entries to a html table from a dropdownbox. Each entry is added as its own row. This is fairly easily done in javascript:
function addProduct(int type) {
var product = getProduct(type); // The method just fetches the product from the database
$('selectedProductsTable').append("<tr><td>" + product.Name +"</td><td>" + product.Quantity + "</td></tr>")
}
In a second step the contents of the table need to be posted to the controller for further processing. What is the general best practice to get the products i've added as table rows? I could iterate over the rows of the selectedProductsTable but that seems somewhat error prone.
On the other hand i would be open to another way to persist the selected items so that i can post them to the controller. Unfortunately saving them in the session or in the tempData is also not a good option since the selection takes place completely in javascript.

Only INPUT and SELECT elements get posted back to the server, so you need to store each value in hidden fields to make it back. You can use the index-based approach to post back an array, which works well. See this post.
I wrote up a blog post about dynamic client-side lists, which might be helpful. It uses Kendo Core but that would not be required.

In your method addProduct populate array with data about products:
var products=[];
function addProduct(int type) {
var product = getProduct(type); // The method just fetches the product from the database
products.push(product)
$('selectedProductsTable').append("<tr><td>" + product.Name +"</td><td>" +
product.Quantity + "</td></tr>")
}
and later send it with ajax:
$.ajax({
url: 'your url',
type: 'POST',
dataType: 'json',
success: function (data) {
//TODO
},
data: JSON.stringify(products)
});

Related

Ajax Parameter Being Received as {string[0[} in MVC Controller

First of all, I have never successfully built an AJAX call that worked. This is my first real try at doing this.
I am working on building a function to update existing records in a SQL database. I am using ASP.NET Core (.NET 6) MVC but I also use JavaScript and jQuery. I cannot have the page refresh, so I need to use ajax to contact the Controller and update the records.
I have an array that was converted from a NodeList. When I debug step by step, the collectionsArray looks perfectly fine and has data in it.
//Create array based on the collections list
const collectionsArray = Array.from(collectionList);
$.ajax({
method: 'POST',
url: '/Collections/UpdateCollectionSortOrder',
data: collectionsArray,
})
.done(function (msg) {
alert('Sent');
});
However, when I run the application and debug the code, the array is received in the Controller as {string[0]}.
Here is the method which is in the Controller, with my mouse hovered over the parameter:
Do not pay attention to the rest of the code in the controller method. I have not really written anything in there of importance yet. I plan to do that once the data is correctly transferred to the Controller.
I have tried dozens of ideas including what you see in the Controller with the serialize function, just to see if it processes the junk data that is getting passed, but it hasn't made a difference.
I have been Googling the issue & reading other StackOverflow posts. I've tried things like adding/changing contentType, dataType, adding 'traditional: true', using JSON.stringify, putting 'data: { collections: collectionsArray }' in a dozen different formats. I tried processing it as a GET instead of POST, I tried using params.
I am out of ideas. Things that have worked for others are not working for me. What am I doing wrong? I'm sure it's something minor.
UPDATE: Here is the code which explains what the collectionList object is:
//Re-assign SortID's via each row's ID value
var collectionList = document.querySelectorAll(".collection-row");
for (var i = 1; i <= collectionList.length; i++) {
collectionList[i - 1].setAttribute('id', i);
}
What I am doing is getting a list off the screen and then re-assigning the ID value, because the point of this screen is to change the sort order of the list. So I'm using the ID field to update the sort order, and then I plan to pass the new IDs and names to the DB, once I can get the array to pass through.
UPDATE: SOLVED!
I want to post this follow up in case anyone else runs into a similar issue.
Thanks to #freedomn-m for their guidance!
So I took the NodeList object (collectionList) and converted it to a 2-dimensional array, pulling out only the fields I need, and then I passed that array onto the controller. My previous efforts were causing me to push all sorts of junk that was not being understood by the system.
//Create a 2-dimensional array based on the collections list
const collectionArray = [];
for (var i = 0; i < collectionList.length; i++) {
collectionArray.push([collectionList[i].id, collectionList[i].children[1].innerHTML]);
}
$.ajax({
method: 'POST',
url: '/Collections/UpdateCollectionSortOrder',
data: { collections: collectionArray }
})
.done(function (msg) {
alert('Sent');
});
2-d array is coming through to the Controller successfully

Jquery datatable: add rows from database in a loop

I have a page that makes an Ajax call to a database on page load. It returns a list of companies that the user is following and then iterates the list trough and does another Ajax call to each company, to get some statistics about them. The statistics are then added to a Datatable which is being drawn quite a few times:
var table = $("#example").DataTable();
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "../json/stats.aspx?t=followed-companies",
dataType: "json",
success: function (data) {
for (i = 0; i < Object.keys(data).length; i++) {
$.ajax({
type: "POST",
async: true,
contentType: "application/json; charset=utf-8",
url: "../json/stats.aspx?t=company-stats" + "&n=" + data[i]
}).done(function (dataSecondary) {
var stringtest = "<tr><td>" + dataSecondary.Stats1 + "</td>" +
"<td>" + dataSecondary.Stats2 + "</td>" +
"<td>" + dataSecondary.Stats3 + "</td>" +
"<td>" + '<button type="button" id="delete" class="btn btn-danger btn-xs dt-delete">' + "Delete" + "</td></tr>";
table.row.add($(stringtest)).draw();
});
}
},
error: function (xhr) {
console.log('error', xhr);
}
});
I do not have much experience in programming, but I do know that this takes ages to load and so has a very poor performance.
Main question is, can I use the table.draw(); after I have added the rows in that loop? I guess that could save some time. I tried to draw the table after the loop is finished but the table said that there is no data to show.
Second question, is this bad practise (mainly those nested Ajax calls with loops and SQL queries), and should I try to unify as many SQL queries as possible?
JSFiddle example - Get Post Data using ajax and display in .dataTable()
Main question is, can I use the table.draw(); after I have added the rows in that loop?
Yes you can. If you look at the docs of datatables you'll see that the draw() function is made for that.
When you perform an action such as adding or deleting a row, changing
the sorting, filtering or paging characteristics of the table you'll
want DataTables to update the display to reflect these changes. This
function is provided for that purpose.
Second question, is this bad practise (mainly those nested Ajax calls with loops and SQL queries), and should I try to unify as many SQL queries as possible?
Yes it's bad practice to have many calls going to your backend. If you have control over the backend, you should aim to optimise it. For example: When you supply a list of companies, it will return the stats for all those companies specified.
Currently it will especially be a bad experience for those with a slow internet connection e.g. mobile users.
Also, this solution doesn't scale well. Imagine your website taking off and 100s of individuals are using it simultaneously. That means 100 * amount-of-followed-companies calls, while with the suggested it would be 100 calls to the backend for fetching the same data.
Have you also considered the possibility to generate a table using ajax sourced data.
UPDATE:
As for the draw() function that is not working. According to the docs, you provide the data structure without actually building the table with html yourself. Use the data returned instead where columnNameX is the name of the columns you specified. Give this a try in your .done().
var data = {
columnName1: dataSecondary.Stats1
columnName2: dataSecondary.Stats2
columnName3: dataSecondary.Stats3
}
table.row.add(data).draw();
As for generating the button. I haven't worked with them before but you can find more about them here.

What's a correct way of retrieving data?

I've posted a few questions seeking clarity in small details about the do's and don't's of javascript, ajax and html. And here's one more. I'm creating a list with javascript by the usage of an api. When making the list I get the correct values for the text. When pressing the button in the row I'm getting the alert message. But the new entry is blank.
Can I add data this way (a for loop getting info and building a string with it baked in)?
OR is it the way I retrieve and store data that is wrong?
EDIT: My data is undefined. Don't I get a string from: data.items[i].Info.drivers?
Part of javascript that talks to an api and gives drivers and cars. This segment is part of a for loop.
...+'<h5><data-title="'
+data.items[i].Info.drivers+'">'
+data.items[i].Info.drivers
+'</data></h5>'
+'<p class="subtitle"><data-title="'
+data.items[i].Info.cars+'">'
+data.items[i].Info.cars
+'</data></p>'
+ '<input class="adding"type="button" name="vehicle" value="Add book">'...
My add code (javascript in html):
$(document).on('click', '.adding',function() {
window.alert("active");
var $this = $(this);
var drivers = $(this).data('drivers');
var cars = $(this).data('cars');
alert($(this).data('drivers')); //<----gives alert, says Undefined
$.ajax({
url: 'insert.php',
type: 'POST',
data: {
'driver': drivers,
'car': cars
},
success: function(msg) {
window.alert("success triggered");
}
});
});
This is referring to the button. By putting the data attributes in the button in the same way the problem is solved.

Wikipedia API search -- Retrieve same index of each array with forEach?

I'm working on a project for freeCodeCamp and I've been stuck on this part all day. I'm pulling data from the Wikipedia API and I'm able to work with it, yet I'm not sure how the syntax should look for what I'm trying to achieve. Here is a link to an example of the data I'm working with. Wikipedia API Search.
Now, in my HTML I have a bootstrap modal that appears after the user inputs something into a form, with a listed group inside with the returned data from the search.
This is the code I have so far.
$(document).ready(function () {
$('#searchForm').on('submit', function(e) {
e.preventDefault();
$('#wikiSearch').modal('show');
var usersearch = document.getElementById('userinput').value;
var apiURL = "https://en.wikipedia.org/w/api.php?
action=opensearch&search="
+ usersearch + "&format=json&callback=?";
$.ajax({
url: apiURL,
contentType: "application/json; charset=utf-8",
dataType: 'json',
type: 'GET',
success: function (data) {
data[1].forEach(function(item) {
$('#results').append("<tr><td><a href='#'>"+item+"</a></td></tr>")
});
data[2].forEach(function(item) {
$('#brief').append("<tr><td>"+item+"</td></tr>")
})
}
});
});
});
For each group in my modal of my HTML I want to display 1 result from the search. I figured I would be able to use a nested forEach but it's not returning the results I wanted. I've tried using map, and also tried creating a long nested for loop and feel like I might be doing more harm than good when it comes to learning since I'm only getting confused now lol. Thanks for any input.
To show the first row from the search results use the first key of the nested array:
$('#results').append("<tr><td><a href='#'>" + data[1][0] + "</a></td></tr>")
$('#brief').append("<tr><td>" + data[2][0] + "</td></tr>")
Don't forget to add a check for the possible undefined value inside the data array.

Collecting Row IDs in an Array using Jquery and then Querying those values for a new table

I'm trying to set up a function using jquery/php where a user selects a checkbox in a row with a specific ID (the id matches the primary key of the row data in my database), stores each row ID into an array, and then upon clicking the "compare selected rows" button passes it to a new page where a table of results is displayed with only those selected rows.
each input looks like this
<input type='checkbox' id='$id' class='compareRow'></input>
I am pretty novice at jquery and was planning to use a variation of a previous script I had put together to display dynamic row data in a modal. I am not sure if this code is relevant at all but it also passes the row id to another php page in order to query the database. Mind you this has only been used for single queries in the past where this new function would need some sort of foreach statement at the query level in order to process the array of IDs, im sure.
Heres the script I've been trying to tweak
$(function(){
$('.compareRow').click(function(){
var ele_id = $(this).attr('id');
$.ajax({
type : 'post',
url : 'query.php', //query
data : 'post_id='+ ele_id, // passing id via ajax
success : function(r)
{
other code?
});
}
});
});
});
I know that there is much more needed here but this is just what I have so far, any help would be greatly appreciated.
Update, so I've created the page and have the following:
in my compareSelected.php I have the following code:
if(isset($_POST['post_id'])){
$compare_received = $_POST['post_id'];
}
print_r($compare_receive);
It returns undefined index.
I also modified the code to change to that page after like so:
$('.compareRowButton').click(function(){
var ids = [];
//loop to all checked checkboxes
$('.compareRow:checked').each(function(){
//store all id to ids
ids.push($(this).attr('id'));
});
$.ajax({
type : 'post',
url : 'compareSelected.php', //query
data : {post_id:ids}, // passing id via ajax
success : function(r)
{
window.location = 'compareSelected.php';
}
});
});
Not sure why it won't pick up the array values.
If you're set on your current implementation, you could maintain a reference to the data returned by each ajax call in the rows array. Later, you could implement a button that fires a function to append the row data to your table. Of course, you may need to parse the data returned by the request prior to appending.
$(function(){
var rows = [];
$('.compareRow').click(function(){
var ele_id = $(this).attr('id');
$.ajax({
type : 'post',
url : 'query.php', //query
data : 'post_id='+ ele_id, // passing id via ajax
success : function(data){
rows.push(data);
}
});
});
$('.displayTable').click(function(){
// append to table or divs
});
});
I would suggest you avoid a page reload here. Or, if you must, make the Ajax request on the following page. You want to avoid tightly coupling your logic between different jQuery modules. Ajax should be utilized to load data asynchronously, without requiring a page reload.
On your code. your sending ajax request everytime you click the checkbox.
better to make another button or something before sending ajax request.
$('SOME_ELEMENT').click(function(){
var ids = [];
//loop to all checked checkboxes
$('.compareRow:checked').each(function(){
//store all id to ids
ids.push($(this).attr('id'));
});
$.ajax({
type : 'post',
url : 'query.php', //query
data : {post_id:ids}, // passing id via ajax
success : function(r)
{
other code?
});
}
});
});

Categories