Return multiple values from stored procedure - javascript

The idea is that each subject has multiple topics, and when I call the function getTopicsForSubject() in order to get this data to a website page, it returns only 1 of the records from the table. I'm testing this using console.log(response) in the JavaScript file to see what is being passed in from the stored procedure/api connection. I'm thinking I need to read what's being passed by the stored procedure as if it were an array, although I'm not too sure how this is done.
Stored Procedure:
USE [Capstone]
GO
/****** Object: StoredProcedure [dbo].[getTopicsForSubject] Script Date: 2/21/2021 11:30:03 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[getTopicsForSubject]
#SubjectID int
AS
BEGIN
select *
from Topic
where SubjectID = #SubjectID
return;
END
API Code
private static string ExecuteSPGetSubjectsForTopic(string queryString, string subjectID)
{
string json = "";
string connectionString = ConfigurationManager.AppSettings["dbconn"].ToString();
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
// 1. create a command object identifying the stored procedure
SqlCommand cmd = new SqlCommand(queryString, conn);
// 2. set the command object so it knows to execute a stored procedure
cmd.CommandType = CommandType.StoredProcedure;
// 3. add parameter to command, which will be passed to the stored procedure
cmd.Parameters.Add(new SqlParameter("#SubjectID", subjectID));
// execute the command
using (SqlDataReader rdr = cmd.ExecuteReader())
{
// iterate through results, printing each to console
while (rdr.Read())
{
json = (string)rdr[0].ToString() + "|" + (string)rdr[1].ToString()+ "|" + (string)rdr[2].ToString() + "|" + (string)rdr[3].ToString();
}
}
}
return json;
}
JavaScript Code
function getTopicsForSubject()
{
var postObj = {
subjectID: localStorage.getItem('myFutureCurrentSubject')
};
console.log(postObj);
var req = new XMLHttpRequest();
req.open('POST', 'https://localhost:44303/api/JSON/getTopicsForSubject', true);
req.setRequestHeader('Content-Type', 'application/json');
req.onreadystatechange = function() { // Call a function when the state changes.
if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
console.log(req.response);
}
}
req.send(JSON.stringify(postObj));
return false;
}

You're reinitializing your JSON variable each time when reading a row. Try this:
json += (string)rdr[0].ToString() + "|" + (string)rdr[1].ToString()+ "|" + (string)rdr[2].ToString() + "|" + (string)rdr[3].ToString();
This is not the right way to return data. In JS you will still get this as a string and then parse it like this to get the actual values:
var array = req.response.split('|');
for (var i = 0; i < array.length; i++) {
console.log(array[i]);
}
I would suggest you use a proper way to handle this data by return an HTTP response from API instead of a string. E.g. create a list and then populate it while reading from the reader and return it. Try this:
List<object[]> topics = new List<object[]>();
while (rdr.Read())
{
object[] row = new object[rdr.FieldCount];
for (int i = 0; i < rdr.FieldCount; i++)
{
row[i] = rdr[i];
}
topics.Add(row);
}
return Ok(new { Data = topics });

Related

I want to store data samples from an excel sheet into an array in javascript

I am using sheetJS in order to manipulate excel sheets. My goal is to extract the value of a cell and store it in an array as raw data for later statistical analysis and graphing.
Here is what the function looks like:
function getSheetData()
{
let rawData = [];
/* set up XMLHttpRequest */
var url = "test.xlsx";
var oReq = new XMLHttpRequest();
oReq.open("GET", url, true);
oReq.responseType = "arraybuffer";
oReq.send();
oReq.onload = function (e) {
var arraybuffer = oReq.response;
/* convert data to binary string */
var data = new Uint8Array(arraybuffer);
var arr = new Array();
for (var i = 0; i != data.length; ++i) arr[i] = String.fromCharCode(data[i]);
var bstr = arr.join("");
/* Call XLSX */
var workbook = XLSX.read(bstr, {
type: "binary"
});
/* DO SOMETHING WITH workbook HERE */
var sheet_name_list = workbook.SheetNames;
// var worksheet;
sheet_name_list.forEach(function(y) { /* iterate through sheets */
var worksheet = workbook.Sheets[y];
for (z in worksheet) {
/* all keys that do not begin with "!" correspond to cell addresses */
if(z[0] === '!') continue;
// console.log(z + " = " + JSON.stringify(worksheet[z].v));
rawData.push(worksheet[z].v);
}
});
/* Get worksheet */
// console.log(XLSX.utils.sheet_to_json(worksheet, {
// raw: true
// }));
console.log("raw data = " + rawData);
}
// console.log(rawData);
return rawData;
}
The console.log defined as 'raw data' shows all the numbers in one array just how I need it. However, the array named "rawData" returns as undefined by the end of the function.
I am calling the function here:
window.onload = function()
{
const data = getSheetData();
const BenfordTable = calculateBenford(data);
printAsTable(BenfordTable);
printAsGraph(BenfordTable);
}
I get data as an empty array
I have included a picture of the browser window
screenshot of console results in google chrome
data is an empty array because getSheetData() is an asynchronous function - that is to say, you are making an XMLHttpRequest call from within it. If you put console logs within your onload handler and right before your return statement, you will see that the latter runs first. The issue is that when your function returns, the call to the server will not have yet returned.
There are a few different ways of writing asynchronous code, but I think you should start off by passing a callback function to getSheetData() which will be called from within your onload handler. This callback function will be what handles rawData.
Here's roughly how you might do this. I have omitted some of the existing code for brevity, but obviously you will need it.
function getSheetData(callback)
{
let rawData = [];
// ...other code
oReq.onload = function (e) {
var arraybuffer = oReq.response;
// ...other code
callback(rawData); // <-- add this
}
// no need to return anything!
// return rawData;
}
window.onload = function()
{
getSheetData(function (data) {
const BenfordTable = calculateBenford(data);
printAsTable(BenfordTable);
printAsGraph(BenfordTable);
});
}
There are other things you could use to write such code, such as Promises, but that's probably something else to look into. We're also not doing any error handling here, which is also an important concept. The main takeaway here is that you are only handling the rawData once the call to the server has completed.

Send JSON data to MySQL database?

I need to send JSON data to a MySQL database, but when I am trying to do this, my code only sends "{"0":"A" to the MySQL database.
Here is my code:
JavaScript
<span id="start_button_container">Send and start</span>
const allCards = {
'0':'A ♦','1':'A ♥','2':'A ♣','3':'A ♠',
'4':'10 ♦','5':'10 ♥','6':'10 ♣','7':'10 ♠',
'8':'K ♦','9':'K ♥','10':'K ♣','11':'K ♠',
'12':'Q ♦','13':'Q ♥','14':'Q ♣','15':'Q ♠',
'16':'J ♦','17':'J ♥','18':'J ♣','19':'J ♠'
};
let userInTable = localStorage.getItem( 'saved_user' );
if (userInTable) { // Save user and find table onclick START
saveUser.style.display = 'none';
hello.textContent = "Hi " + userInTable;
start.onclick = () => {
if (userInTable) {
let x = new XMLHttpRequest();
let url = "php/findtable.php";
let data = JSON.stringify(allCards);
let params = "cards="+data+"&user="+userInTable;
x.open("POST", url);
x.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
x.send(params);
x.onreadystatechange = () => {
if (x.readyState == 4 && x.status == 200) {
console.log(x.responseText);
}
}
}
}
}
Here is my PHP code:
if (isset($_POST["cards"],$_POST["user"])) {
$cards = $_POST["cards"];
$user = $_POST["user"];
$query = "INSERT INTO tables (u_1,all_cards) VALUES (?,?)";
if ($stmt = $conn->prepare($query)) {
$stmt->bind_param("ss", $user, $cards);
if ($stmt->execute()) {
print_r($cards);
}
}
}
What am I doing wrong?
The encodeURIComponent() function helped me a lot:
let data = JSON.stringify(encodeURIComponent(allCards));
If you/somebody still want to know why this happens, every ampersand (&) is a new input in a querystring. Meaning var1=value&var2=value&var3=value. Your JSON contains ampersands, so the parser thinks you are starting a new variable.
var1=value&var2={"a":"&2934;"}
^ This one starts a new variable
var2 contains {"a":"1 and processes 2934;"} as a new variable name.
encodeURIComponent escapes the ampersands, so the query string parser does not use it for division of variables.

Update DOM with responses from several XMLHttpRequest

I am building a simple open source Chromium extension that retrieve some data from several urls and then update the DOM. I could find another way to do this than by adding the line to update the DOM inside the callback http1.onreadystatechange
My XMLHttpRequest requests were often stuck on http1.readyState = 3 so I have added a 3rd parameter to http1.open("GET"); to make the request synchronous like this:
http1.open("GET", url, false);
But I am still getting these errors:
results[1].join is not a function at XMLHttpRequest.http.onreadystatechange
annot read property 'join' of undefined at XMLHttpRequest.http.onreadystatechange
Even thought they don't prevent the script from running, I think this isn't the right way to do what I want. So here is my question: how to update the DOM with the responses from several XMLHttpRequest request? Let's say I need to retrieve and compare all the data before updating the DOM. Then is there a way to process all the data at once after we have retrieve all of them (cf my comment on the last line)?
Here is the relevant part of my script, the full script is available here:
var urls = [
["https://www.cnrtl.fr/morphologie/" + keyword, "vtoolbar", "morf_sound"], //best for plural
["https://www.cnrtl.fr/synonymie/" + keyword, "syno_format"],
]
// for test set keyword to any of this word : hibou, tribal, aller, lancer
var resultdiv = document.getElementById("result")
resultdiv.innerText = "requete en cours";
var results = [];
var errors = [];
urls.forEach((item, index) => {
var http = new XMLHttpRequest();
http.onreadystatechange = function () {
if (http.readyState == 4 && http.status == 200) {
parser = new DOMParser();
var ulr1response = parser.parseFromString(http.responseText, "text/html");
if (index == 0) {
//retrieve the data needed, save then in a list and push this list to the main list result
} else if (index == 1) {
//retrieve the data needed, save then in a list and push this list to the main list result
}
// update the DOM
if (results[1] == "") {
resultdiv.innerHTML = results[0].join(", ") + "</br></br>Pas de synonymes trouvés"
} else {
resultdiv.innerHTML = "<b>" + results[0].join(", ") + "</br></br>Synonymes:</b></br>● " + results[1].join('</br>● ')
}
} else {
errors.push(index);
resultdiv.innerText = "Erreur: " + index + " " + http.readyState + " " + http.status;
}
}
http.open("GET", item[0], false);
http.send(null); // null = no parameters
});
// it would be simplier if I could update the DOM here and not in http.onreadystatechange
If you want to execute some code once all requests have succeeded, you can try using Promise.all together with Fetch.
let keyword = "beaucoup";
let parser = new DOMParser();
let urls = [
["https://www.cnrtl.fr/morphologie/" + keyword, "vtoolbar", "morf_sound"], //best for plural
["https://www.cnrtl.fr/synonymie/" + keyword, "syno_format"]
];
let fetchPromises = urls.map(
item => fetch(item[0]).then(
response => parser.parseFromString(response.text(), "text/html")
)
);
Promise.all(fetchPromises).then(
results => {
// code in here executes once all fetchPromises have succeeded
// "results" will be an array of parsed response data
console.log(results);
}
).catch(console.error);

How can I retrieve plane text data from one local ip to another in javascript?

I am using an ESP32 Wifi module as a master to host a webpage displaying the values of a number of binary data points in a table as either OK or FAILED. I need to have this device retrieve data from another ESP32 client on a local IP i.e 192.168.138.50/readVal1 this address will display simply plane text either OK or FAILED. I would like to take this value and display it in the table produced by my master module. How should I go about doing this?
I have tried using an HTTP get request as follows in the Arduino code.
void runTest6(){
String payload;
HTTPClient http;
http.begin("192.168.137.50/readBatt1");
int httpCode = http.GET();
if(httpCode > 0) {
payload = http.getString();
Serial.println(payload);
}else{
Serial.println("HTTP request error");
}
http.end();
String batt6val = payload;
server.send(200, "text/plane", batt6val);
}
Here is my Javascript on the root that handles the updates\
function getData(){
try{
console.log("Getting Data...");
for(var i = 1;i<=NUMOFUNITS;i++){
(function (i){
setTimeout(function () {
console.log("(debug msg)in loop #: " + i)
var xhttp = new XMLHttpRequest();
var current = "batt" + i + "val";
var dataRead = "readBatt" + i;
xhttp.onreadystatechange = function(){
if (this.readyState == 4 && this.status == 200){
console.log("updating innerHTML for data value: " + i);
document.getElementById(current).innerHTML = this.responseText;
}else if(this.readyState == 4 && this.status == 404){
console.log("no battery # " + i);
document.getElementById(current).innerHTML = "None found";
}
};
xhttp.open("GET", dataRead, true);
xhttp.send();
if(i == 1){
updateTime();
console.log("Updated times.")
}
}, 400*i);
})(i);
};
console.log("Data update complete.");
}
catch(err){
alert(err.name);
throw err;
getData(); //try to get data again
}
finally{
console.log("DONE");
}
}
Using and HTTP server I am able to send the information between ESP32's. Using the WebServer I have set server.on("/status/{}", sendData); where the {} hold the pathArg aka a number representing which data is being asked for. The function senData() takes the pathArg and sends the appropriate data as follows.
void sendData(){
String battString = server.pathArg(0);
Serial.println("Sending Data... PathArg= " + battString);
int battNum = battString.toInt();
int arrayNum = battNum - 1;
server.send(200, "text/plane", battStatus[arrayNum]);
}
Here an array called battStatus holds the status of each.

Callback isn't called as many times as expected

Employee webpage makes Ajax calls to the node.js web server in a loop. Code as given. All data values are correct. I expect the callback UpdateTeamArr to be called n times where n is equal to the loop max - document.getElementById("deptSelect").options.length. But its called only once. Thanks for your effort and support.
Client side code:
for (var i = 1; i < document.getElementById("deptSelect").options.length; i++) {
var objJSON = {
"deptid": document.getElementById("deptSelect").options[i].dataset.id,
"empid": selectedEmployeeId
}
var strJSON = JSON.stringify(objJSON);
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("post", "../../GetEmployeesTeams", true);
xmlhttp.onreadystatechange = function() {
if(xmlhttp.readyState === XMLHttpRequest.DONE && xmlhttp.status === 200) {
UpdateTeamArr(xmlhttp);
}
}
xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
xmlhttp.send("strJSON=" + strJSON);
}
}
function UpdateTeamArr(xmlhttp) {
}
Server code:
app.post('/GetEmployeesTeams', function(req, res) {
var connection = mysql.createConnection({
host : "127.0.0.1",
port : 3306,
user : "root",
password : "root",
database : "lighting"
});
var strJSON = req.param('strJSON');
var objJSON = JSON.parse(strJSON);
connection.connect();
connection.query("SELECT db_teamemp.teamid, db_department.id AS deptid FROM lighting.db_teamemp, lighting.db_department, lighting.db_team WHERE db_teamemp.empid='" +
objJSON.empid + "' AND db_department.id='" + objJSON.deptid + "' AND db_teamemp.teamid=db_team.id AND db_team.dept=db_department.id;",
function(err, result, fields) {
if (err)
throw err;
else {
connection.end();
res.status(200);
return res.send(result);
}
});
});
Ah, you are using a var here for xmlhttp. A var is not block scoped, it's hoisted - that means this single var is used by all calls to UpdateTeamArr. I believe you are calling the function N times, but with the last response every time.
An easy test of this theory is simply changing var to let on that line.
Why don't you try to perform just a single request to the server by creating a uniq JSONArray with a list containing all Employees id's inside your 'deptSelect'?
This way you send a response with also a list containing the other attributes for the employees in another JSONArray format, that you can iterate in the UpdateTeamArr function

Categories

Resources