How do I loop through this mysql array without freezing the website - javascript

For my current project I fill an array by using the sql query
"SELECT names FROM students";
and throwing every response into an array named $names_array.
Then I use
foreach($names_array as $value) {
echo "<option>".$value."</option>";
}
to fill up a datalist with options so you can find a name using the list autocomplete or enter a name that is not yet found in the array.
Now here is the issue, if I click on an existent name I need to take a couple of other pieces of data from the table and fill in other input fields automatically.
So lets say the database table per student also has their age, birth, guardians number & guardians email.
How do I check if the typed in student already exists and if they do, get their additional data from the table?
If I can somehow get the entered name in PHP I could just look through the table which would be a lot faster but I've tried doing this and I can't seem to get it done.
I was using a very inefficient method where I json_encode an array gathered from the sql query
"SELECT * FROM students";
and then use
echo "<script>var names = ".$names_json."</script>";
to be able to fetch it in js. Now after parsing it and looping through it I can find my neccesary data but considering the database table already has 6000 options and is still increasing it's starting to take a while to loop through it, especially if the name I'm searching for is near the end of the array. Now this can take anywhere from 1 to 15 seconds where the website is completely frozen and it looks like it crashed until it's done and does what I need to do with the data.
I've tried using the solution offered here but that doesn't seem to change anything.
Please, does anyone know of a better way to do what I'm essentially already doing without temporarily freezing the website? Or maybe a completely different way of getting the other pieces of data? Thanks in advance.

for prevent the script loading to freeze the website load, you can add defer attribute, like so:
echo "<script defer>...some long logic....</script>";
For search easily through the array, you can sort it by the searched value, then use binary search
Also, you can store it in literal object, where the key is the name, and the value is object of all the student data. it will require some memory space, but make the search super fast

At first on server side - pagination/limit, do not "select all"
SELECT names FROM students WHERE names LIKE ? ORDER BY names LIMIT 20;
Second on client side - lazy loading via ajax, but first after, for example, user typed 3 chars of name.

I guess I should answer this question if anyone else ends up stumbling onto the same issue.
I change the foreach loop slightly by adding the ID as a data-id to the options
foreach($names_array as $value) {
echo "<option data-id='".$value['names_id']"'>".$value['names_name']."</option>";
}
Through js (and jquery) you can obtain the id of the chosen student like this:
currentVal = $("#inputID").val();
currentID = $("#listID option[value='" + currentVal + "']".attr('data-id');
now you can find the index of the chosen student in the namesArray doing this:
if (currentID != undefined || currentVal != "" || currentVal != " ") {
arrayIndex = namesArray.findIndex(x => x.names_id == currentID);
currentArray = namesArray[arrayIndex];
}
where namesArray is the var 'names' json parsed which I echo in the script seen in the question and the if block prevents it from even checking the array if the id is undefined or the input is empty.

Related

Display foreign key description instead of value with AJAX / Multiple sql statements in output

In general I work with 3 different tables (3 Levels) and they each have a reference to the previous table with a foreign key. Second Level table has a foreign key which references the previous and also the third level table which references the 2nd table.
I'm currently displaying all these values in multiselect dropdowns. The third level multiselect dropdown is currently displaying the foreign key value from the 2nd level multiselect dropdown. All I want to do is change the foreign key value to display the description which is inside the 2nd level table.
This is how it currently looks with the foreign key values in optgroup:
(https://imgur.com/a/4LPnit1)
Up to now I always did this by creating another sql statement which selects the the description based on the id from the 2nd level table. I'm not sure how I can do this since currently I have a javascript with a multiselect function which is accessing a php file over ajax which includes the sql statement with the output.
To provide a better overview I attached the important code parts:
//Javascript
$('#idsecondlevel').multiselect({
onChange:function(option, checked){
//Store selected value in array format in selected variable
var selected = this.$select.val();
if(selected.length > 0){
$.ajax({
url:"http://localhost:8080/fetch_xx.php",
method:"POST",
data:{selected:selected},
success:function(data){
$('#idthirdlevel').html(data);
$('#idthirdlevel').multiselect('rebuild');
}
})
}
}
});
//fetch_xx.php
include 'dbconnect.php';
if(isset($_POST["selected"])){
$id = join("','", $_POST["selected"]);
$sql= "SELECT * FROM 3rdlevel WHERE foreign_key_2ndlevel IN ('".$id."')";
$res=mysqli_query($conn, $sql);
$output = '';
foreach($res as $row){
$output .= '<optgroup label="'.$row["foreign_key_2ndlevel"].'"><option value="'.$row["primary_key_3rdlevel"].'">'.$row["desc_3dlevel"].'</option></optgroup>';
}
echo $output;
}
Do I need to make another sql statement before the isset function and add it to the output where I currently have $row["foreign_key_2ndlevel"]? Or do I need to make another sql statement in the output which chooses the description of the 2ndlevel based on the id, which would make it very messy? I currently have no idea where to add this statement.
A possible sql statemtent would be:
$sql= SELECT desc_2ndlevel FROM 2ndlevel WHERE primary_key_2ndlevel = foreign_key_2ndlevel;
Just to make sure I'm getting this right: The contents of 2nd and 3rd level are appearing dynamically, based on the selected value(s) from its parent table. So basically, you want the user to select something/multiple things on 2nd-level table, and then make him go into more detail on the 3rd level?
In your screenshot you marked the 1, 2 etc. You want to display the description of the selected id from the parent table there?
If so, to avoid another SELECT-statement you could use JOINS. Looking at your code, you might want to use INNER JOIN. To give you an example of a third-level SELECT, check pseudo-code below. You might want to display the classification history in a URL-like way (like 'abc/xyz' as title with 3rd-level options below), therefore you'd need the first level description as well. In case you don't, just remove the respective columns. To integrate with your php, just compare against the id of your selected option.
SELECT a.id, a.description, b.id, b.foreign_key_firstlevel, b.description, c.id, c.foreign_key_secondlevel, c.description
FROM first_level_table AS a
INNER JOIN second_level_table AS b ON a.id = b.first_level_foreignkey
INNER JOIN third_level_table AS c ON b.id = c.second_level_foreignkey;
Another thing that comes to mind: The contents of level 1 - 3 are pretty static right, so why not use a View? Of course this comes with limitations, but since you only seem to select values this shouldn't bother you. Joins require a lot of computation and slow down your calculation if done excessively. You could get around that using a prepared View. Since I don't know your database structure, pseudocode could look something like this:
CREATE VIEW view_allselectoptions AS
SELECT a.id, a.description, b.id, b.foreign_key_firstlevel, b.description, c.id, c.foreign_key_secondlevel, c.description
FROM first_level_table AS a, second_level_table AS b, third_level_table AS c
WHERE a.id = b.foreign_key_firstlevel
AND b.id = c.foreign_key_secondlevel;
You could use JOINS in the view as well. Code would be similiar to the one above.

Qualtrics: Loop over embedded data fields?

I have a large set of embedded data fields that are called rnd1, rnd2, rnd3 etc. In a certain question block, I stored to each of these a certain value (each a different random number).
I also have a Loop and Merge question block, and in each round, I would like to access the stored data of a different field (i.e. in the 1st round I'd like to access whatever is in rnd1, in the 2nd round access rnd2 etc.) Can this be done in Qualtrics?
I tried something like:
Qualtrics.SurveyEngine.addOnload(function()
{
var trialNum = this.questionId.split('_')[0]; // getting the loop's current round number
var EDname = "rnd"+trialNum; // name of desired EF field
var rndNum = "${e://Field/" + EDname + "}"; // this is where I'd like stored the right ED value
// some more code that uses rndNum
});
but this does not work. It seems that while EDname gets the right string, I cannot access the value of that embedded field this way (though var rndNum = "${e://Field/rnd1} does work and returns the right value, so the problem seems to be in the looping strucutre).
If I cannot loop over the different fields in the JS code for some reason, is there another clever way to get that done in Qualtrics? For example, I thought it may be possible to use the different field names in the Loop and Merge section as "Field 2", but this seem to require me setting manually each and every ED field name.
Thanks.
Piped embedded data fields are resolved on the server before the page gets sent to your browser. So, it is impossible to dynamically create an embedded data field name and resolve it on the client side with JavaScript.
The way you are doing it with a loop & merge field is the best way.

csv to multi-dimensional array

I'm far from good at javascript. I'm cobbling together a page to analyze a csv file and created a page with results.
So I'm using papaparse.js for csv parsing and the stepFn to process each line, to eliminate records using various selection criteria.
I've also included moment.js to handle dates and times.
so there's 3 pieces of data I want to work with. (I'm simplifying).
[fundraising] team, amount, and date (which I'll store as a unix time integer).
I've been trying to see if outdata[teamname] exists, and if it does, update the amount. And if the amount >= goalamount, then populate date (if it's not already populated).
basically my web page allows them to define selection criteria, a goal, and to choose whether the challenge was [who gets their first]/sort on date, or [who got the most] sort on amount. [where total can actually be a count or
if the team isn't in the outdata array, add it, and place in it the total and a date (which of course I have to check for goal-reaching).
I've tried
var exists = typeof outdata[thisteamname];
if (exists == undefined)
{
outdata.push({ team: thisteamname, total: usevalue, adate: 0 });
}
else
{
var z = outdata[thisteamname]['total'];
//---->>> Cannot read property 'total' of undefined
outdata[thisteamname]['total'] += usevalue;
}
etc .. but i think I'm going about it all wrong. Suggestions? I will also need to sort the outdata array by eithe date or total, and loop through it for a top-ten style list at the end to write html.
all help appreciated, I know my javascript looks rather BASICy.

JavaScript using an array to display data

I'm working on a score system that shows per question block, I'm using PHP to retrieve the data from a table and the javascript below to calculate the score. The problem is I want several score labels underneath each question block. So clearly I need an array to make this work, but currently I'm using this line to write the data onto document.getElementById("score_label[0]").innerHTML=""+current_score.toFixed(1);
so this only applies to the first entry in the array. How do I make it loop through the entire array(score_label[]) and increase it's value so the code reads document.getElementById("score_label[0]").innerHTML=""+current_score.toFixed(1);
document.getElementById("score_label[1]").innerHTML=""+current_score.toFixed(1);
this is the element javascript is writing to
echo "your total score: <span id='score_label[0]' name='score_board['".$score_board."']'></span>";
if there is need for I can post the entire function but I think it's mostly my lack of knowledge on arrays that's the issue here
If I'm reading your question correctly (current_score is the same for all elements???):
for (var i = 0; i < score_label.length; ++i)
document.getElementById("score_label[" + i + "]").innerHTML=""+current_score.toFixed(1);
I should mention that the id attribute of the form score_label[N] may be confusing.
Try to use foreach function to loop through the whole score_label array.
need to loop through a PHP array in JavaScript

How to generate a unique code

I connect up to my DB and a user submit their email address. This is stored in the DB. This is something I have grabbed from a turorial.
I'd like a user-unique code generated through JS on document load..
Format should be 6 digits in length and only using only A-Z and 0-9. ie: F4DRB6
Once that is done I'd need to store that unique code for that user in the DB.
The generator should check if the unique code exists in the DB, to ensure it is actually unique.
The trouble I am having is; I don't know how to create the unique code in the above format, checking if it is unique from the DB, and then storing it in the DB corresponding to that user. I'd assume another column to match the row somehow?
Thanks!
EDIT: I have attempted with this.. if there is any error please do point it out. Thanks
function genRandomString() {
$length = 5;
$characters = '1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$string = '';
for ($p = 0; $p < $length; $p++) {
$string .= $characters[mt_rand(0, strlen($characters))];
}
return $string;
}
do {
$random_string = $this->genRandomString();
} while (mysql_num_rows(mysql_query("SELECT referralcode FROM ".coming_soon_emails." WHERE rand_string='{$random_string}'")));
$q = "INSERT INTO ".coming_soon_emails." SET referralcode='{$random_string}'";
$result = mysql_query($q);
why you need that to be created in client-side? Why can't you just create the code when the client submits the "final" form?
You can create this code randomly and you put the column that handles the code as unique. If you get a violation error, you generate another and try again.
Well, this is one of the ways to do...
Its simple math,
6^36 is large enough that creating a random id is mostly unique.
If you wanna be 100% sure use AJAX to check the generated ID in database and recreate if existing.
In a causal way, a simple walk-through would be:
write a function/SP in mysql :
First, generate a random code, as AbiusX said, depends on your user pool size, the new code is probably rarely used.
This will generate one Hex character for you and should get you started.
SELECT conv(FLOOR((RAND() * 16)),10,16);
Then you will need to check if this code has been used already.
`
SELECT * FROM usertable where code =
generatedcode
if so, generate a new one.
In a more robust setting, I always pre-generate the unique codes, and store them in a table "unused code" etc, so I can just grab any code off there and ensure it is unique and not used.

Categories