Javascript InnerHTML Output Wrong - javascript

function test()
{
var formHTML ="";
var frmid ="test123";
var options = ["Test1", "Test2", "Test3", "Test4", "Test5"]
formHTML += "<select id='" + frmid + ">";
console.log(options);
for ( i = 0; i < options.length; i++) {
var temp = options[i];
var temp2 = "<option value='" + temp + "'>" + temp + "</option>";
console.log(temp2);
formHTML += temp2;
}
formHTML += "</select>";
console.log(formHTML);
document.getElementById("injected").innerHTML+=formHTML;
}
Above is my function to make a select element in my page, when i call this function there is a very strange issue, it only dispalys options test2,test3,test4,test5 and not one...
When i print out formHTML using console.log it shows..
<select id='test123><option value='Test1'>Test1</option>
<option value='Test2'>Test2</option>
<option value='Test3'>Test3</option>
<option value='Test4'>Test4</option>
<option value='Test5'>Test5</option>
</select>
But if you run the code and look at the source code the HTML element is not correct the first element looks like
<option value='test1'> Test1
Missing the close option tag,
I have tried debugging and changing code around but this issue has left me confused.
Is there something missing is there better way of going about this? I am trying to store it all in one string before manipulating the DOM for speed reasons.
All help is appreciated, Thanks

YOu have an error in this line
formHTML += "<select id='" + frmid + ">";
Change that to
formHTML += "<select id='" + frmid + "'>";

Related

How to get the value of an data-* attribute from a dynamically created select in a table when I change an option

I want to get the value of an data-* attribute from a dynamically created select in a table when I change an option. I am getting an "Uncaught ReferenceError: index is not defined".
The creating HTML is:
html += "<td style='width : 1%; white-space: nowrap;'><select name='parRating'>"
for (let i = 0; i <= paraArray; i++) {
html += "<option name='parRatingOption' data-index='" + i + "' value='" + parIdArray[i] + "'>" + parRatingArray[i] + "</option>"
};
html += "</select></td>";
The option change catch is:
$('#showPatientPARForm').on( 'change', 'select[name="parRating"]', function (e) {
e.preventDefault();
alert("this.value: " + this.value);//works
alert("this.data-index: " + this.data-index);//Uncaught ReferenceError: index is not defined
});
I have also tried:
alert("this.attr('data-index'): " + $(this).attr("data-index")); //undefined
You need to make sure to target the data-attribute correctly,
the value of the option gets returned from the parent selector (select), but the option itself needs to be accessed differently.
Use dataset to target data attributes.
let paraArray = ['one','two','three'];
let parIdArray = ['idOne','idTwo','idThree'];
let parRatingArray = [1,2,3];
let html = '';
html += "<td><select name='parRating'>";
for (let i = 0; i < paraArray.length; i++) {
html += "<option name='parRatingOption' data-index='" + i + "' value='" + parIdArray[i] + "'>" + parRatingArray[i] + "</option>";
}
html += "</select></td>";
$('#showPatientPARForm table').append(html);
$('#showPatientPARForm').on( 'change', 'select[name="parRating"]', function (e) {
e.preventDefault();
alert("this.value: " + this.value);//works
// select the data attribute correctly:
//alert(this.options[this.options.selectedIndex].dataset.index);
alert(this.options.selectedIndex)
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="showPatientPARForm">
<table></table>
</div>

How can i put data from parsed csv to select boxes?

I used JS to parse the csv file.
Example of csv :
Year,Model,Mileage,Color,Vin,Image
2012,BUICK LACROSSE FWD V6 FFV 4D SEDAN LEATHER,113046,BROWN,1G4GC5E34CF177752,https:imagelink
And the code of parser
$(document).ready(function(){
$('#load_data').click(function(){
$.ajax({
url:"Cars.csv",
dataType:"text",
success:function(data)
{
var cars_data = data.split(/\r?\n|\r/);
var table_data = '<table class="table table-bordered table-striped">';
for(var count = 0; count<cars_data.length; count++)
{
var cell_data = cars_data[count].split(",");
table_data += '<tr>';
for(var cell_count=0; cell_count<cell_data.length; cell_count++)
{
if(count === 0)
{
table_data += '<th>'+cell_data[cell_count]+'</th>';
}
else
{
table_data += '<td>'+cell_data[cell_count]+'</td>';
}
}
table_data += '</tr>';
}
table_data += '</table>';
$('#cars_table').html(table_data);
}
});
});
});
Example of select boxes
<select>
<option value="0">Model</option>
<option value="1">HERE COMES THE MODEL FROM PARSED CSV</option>
</select>
So how can i put data from this parsed csv to select boxes on the html ?
Since your question wasn't clear to me, I added two solutions. The first solution one takes the Model column and offers a selectbox for this column. You can change the column to use as a select box if you change the select_column_index (to use the Year for example, set select_column_index = 0).
I created the addTable(data) function. This is equal to your success:function(){...}, but for testing I cannot use ajax. Your code is then
$(document).ready(function(){
$('#load_data').click(function(){
$.ajax({
url:"Cars.csv",
dataType:"text",
success:addTable,
});
);
});
The code takes the column with the select_column_index and uses the first cell (in the first row in the select_column_index-th column) as the label. The following cells (in each row in the select_column_index-th column) are the options for the select.
Note that one should not use the label as the first option from the select box as you did in your example. This makes it possible for users to select the mode Model which makes no sense. This is more complicated for users and leads to mistakes. Also you have to check the result on the server side which is more unnecessary code.
You can check the output in the following snippet. The second solution is added below.
// for demo only
let csv =
"Year,Model,Mileage,Color,Vin,Image\n" +
"2012,BUICK LACROSSE FWD V6 FFV 4D SEDAN LEATHER,113046,BROWN,1G4GC5E34CF177752,\n" +
"2013,Lincoln MKZ 3.7L AWD,113046,Lincoln,,\n";
// for demo only
$(document).ready(function(){
addTable(csv);
});
function addTable(data){
var cars_data = data.split(/\r?\n|\r/);
var table_data = '<table class="table table-bordered table-striped">';
// use model for the select
var select_column_index = 1;
var label_data = "<label for='csv-select'>";
var select_data = "<select id='csv-select'>";
for(var count = 0; count<cars_data.length; count++){
var cell_data = cars_data[count].split(",");
table_data += '<tr>';
for(var cell_count=0; cell_count<cell_data.length; cell_count++){
if(count === 0){
table_data += '<th>'+cell_data[cell_count]+'</th>';
}
else{
table_data += '<td>'+cell_data[cell_count]+'</td>';
}
if(cell_count == select_column_index){
if(count == 0){
label_data += cell_data[cell_count];
}
else{
select_data +=
"<option value='" + cell_data[cell_count] + "'>" +
cell_data[cell_count] +
"</option>";
}
}
}
table_data += '</tr>';
}
table_data += '</table>';
label_data += "</label>";
select_data += "</select>";
$('#cars_table').html(table_data);
$('#select-wrapper').html(label_data + " " + select_data);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="cars_table"></div>
<div id="select-wrapper"></div>
The second solution takes all the columns and adds a select box for each column. Note that I did not add the table, you can just use your code.
This is basically the same code but I am saving the options to another variable. After all options of all columns are present, they are pasted (replace the %options%) in the select boxes.
// for demo only
let csv =
"Year,Model,Mileage,Color,Vin,Image\n" +
"2012,BUICK LACROSSE FWD V6 FFV 4D SEDAN LEATHER,113046,BROWN,1G4GC5E34CF177752,\n" +
"2013,Lincoln MKZ 3.7L AWD,113046,Lincoln,,\n";
// for demo only
$(document).ready(function(){
addSelects(csv);
});
function addSelects(data){
var cars_data = data.split(/\r?\n|\r/);
var select_options = [];
var select_html = "";
for(var count = 0; count < cars_data.length; count++){
var cell_data = cars_data[count].split(",");
for(var cell_count = 0; cell_count < cell_data.length; cell_count++){
if(count == 0){
select_html +=
"<div class='select-line'>" +
"<label for='select-" + cell_count + "'>" +
cell_data[cell_count] +
"</label>" +
"<select id='select-" + cell_count + "' name='" + cell_data[cell_count] + "'>" +
"%options%" +
"</select>" +
"</div>";
}
else{
if(select_options.length < cell_count){
select_options.push("");
}
select_options[cell_count] +=
"<option value='" + cell_data[cell_count] + "'>" +
cell_data[cell_count] +
"</option>";
}
}
}
for(var i = 0; i < select_options.length; i++){
select_html = select_html.replace("%options%", select_options[i]);
}
$('#selects').html(select_html);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="selects"></div>

$.getJSON and for loop with an array and how to get them to work together - for loop completes before JSON is returned

I am trying to cycle through an array and with each value in the array, use $.getJSON to return some JSON and populate an HTML table with the return values.
I have been following this post, but seem not get this to work:
$.getJSON calls misbehaving inside a for loop
Here is my function:
$("#selectProviderTop").click(function() {
var restURL = window.location.protocol + "//" + window.location.hostname + (window.location.port == "" ? "" : (":" + window.location.port)) + "/restGetProvider/";
var selected = [];
var providerKey;
var providerID;
var providerLegacyID;
var providerName;
var finalURL;
var tr;
// First, create an array from the User Provider Keys...
var userProviderKeys = $("#hiddenUserProviderKeys").val();
selected = userProviderKeys.split(",");
console.log("selected: " + selected);
var tableHTML = "";
var focus = $("<div></div>"); // either match an existing element or create one: '<div />'
var arrayLength = selected.length;
for (var i = 0; i < arrayLength; i++) {
(function(i) {
console.log("i: " + i);
providerKey = selected[i];
console.log("providerKey: " + providerKey);
// Get that provider and populate the table...
finalURL = restURL + providerKey;
console.log("finalURL: " + finalURL);
focus.queue('apicalls', function(next) {
$.getJSON(finalURL, function(jsonObject) {
tableHTML += "<tr>";
tableHTML += "<td><a href=\"#\" onclick='selectProvider(\"" + providerKey + "\")'>" + jsonObject["providerName"] + "</a></td>";
tableHTML += "<td>" + jsonObject["providerID"] + "</td>";
tableHTML += "<td>" + jsonObject["providerLegacyID"] + "</td>";
tableHTML += "</tr>";
console.log("tableHTML: " + tableHTML);
next();
});
});
})(i);
}
// Replace table’s tbody html with tableHTML...
console.log("final tableHTML: " + tableHTML);
$("#tableProviderSelect tbody").html(tableHTML);
$('#modalSelectProviderForPTP').modal('show');
});
The userProviderKeys value is 0be32d8057924e718a8b6b4186254756,2dc5f826601e4cc5a9a3424caea4115f
The code never makes the $.getJSON call it just completes the for loop.
How do I update this code to get the first value in the array, grab the JSON, create the HTML, and then cycle through the loop?
I have tried setTimeout but that didn't help me out.
If you have some ideas, could you update my existing code - I understand better when I see the code itself. Thanks.
I don't know why you're doing this using queues. But you are, so I'm not going to rewrite your code to do it some other way.
The last few lines need to be called after all the queued functions have run, which means they should be called asynchronously. (Yes, you could make the whole thing synchronous as Marcus Höglund suggested, but that's no way to write scalable applications in javascript.) You could do this by adding another function to the queue containing these lines. Like this:
$("#selectProviderTop").click(function() {
var restURL = window.location.protocol + "//" + window.location.hostname + (window.location.port == "" ? "" : (":" + window.location.port)) + "/restGetProvider/";
var selected = [];
var providerKey;
var providerID;
var providerLegacyID;
var providerName;
var finalURL;
var tr;
// First, create an array from the User Provider Keys...
var userProviderKeys = $("#hiddenUserProviderKeys").val();
selected = userProviderKeys.split(",");
console.log("selected: " + selected);
var tableHTML = "";
var focus = $("<div></div>"); // either match an existing element or create one: '<div />'
var arrayLength = selected.length;
for (var i = 0; i < arrayLength; i++) {
(function(i) {
console.log("i: " + i);
providerKey = selected[i];
console.log("providerKey: " + providerKey);
// Get that provider and populate the table...
finalURL = restURL + providerKey;
console.log("finalURL: " + finalURL);
focus.queue('apicalls', function(next) {
$.getJSON(finalURL, function(jsonObject) {
tableHTML += "<tr>";
tableHTML += "<td><a href=\"#\" onclick='selectProvider(\"" + providerKey + "\")'>" + jsonObject["providerName"] + "</a></td>";
tableHTML += "<td>" + jsonObject["providerID"] + "</td>";
tableHTML += "<td>" + jsonObject["providerLegacyID"] + "</td>";
tableHTML += "</tr>";
console.log("tableHTML: " + tableHTML);
next();
});
});
})(i);
}
focus.queue('apicalls', function(next) {
// Replace table’s tbody html with tableHTML...
console.log("final tableHTML: " + tableHTML);
$("#tableProviderSelect tbody").html(tableHTML);
$('#modalSelectProviderForPTP').modal('show');
next();
});
});
Edit: Sunshine has pointed out that the linked stackoverflow post has mysterious references to the .dequeue method. In the accepted answer, this method is called explicitly after the tasks have been queued. I don't know whether this was necessary or not. I had thought that the problem was that the $.json bit wasn't happening until after the $("#tableProviderSelect tbody").html(tableHTML); part. But now I realise you wrote: "The code never makes the $.getJSON call it just completes the for loop." In that caseSunshine may have been right, and you need to add focus.dequeue('apicalls'); just after the last focus.queue(...);.

How to make dropdown based one JSON, and selected parameter taken from another?

So I got this JS code, which suppose to make list of statuses in dropdown:
$.getJSON('/statuses', {
ajax: 'true'
}, function (data) {
var html;
var len = data.length;
html += '<select id="status" class="form-control selectpicker" width="150" style="width: 150px">';
for (var i = 0; i < len; i++) {
html += '<option value="' + data[i].id + '">'
+ data[i].name + '</option>';
}
html += '</select>';
$('#status').html(html);
});
This part is working, but now I have to make sure that selected option is equals to other JSON. I tried something like this in other getJSON:
status += '<select id="status" class="form-control selectpicker" width="150" style="width: 150px">';
status += '<option value="' + data.status + '" selected="selected">' + data.status + '</option>';
status += '</select>'
...it selects it, but also duplicates the status. How can I make it proper way?
On the second bit of code you are parsing new HTML, that is why you get duplicate. To just select an option try this:
$('#status option[value="'+ data.status +'"]').prop('selected', true);

How to render search results in a different page with Ajax

I have a web page configured with the search form in one php page and the table with search results in another and I have the following javascript function that renders the table with the search results:
function createRestaurantsTable() {
var table = document.createElement('table');
var str = '<table cellspacing="1" class="tablesorter">';
str += '<thead><tr><th>Nome</th><th>Morada</th><th>Distancia</th></tr></thead>';
for ( var i=0; i< restaurantArr.length; i++){
str += '<tr><td><center class="IDcell">' + restaurantArr[i].name + '</center></td><td><center>' + restaurantArr[i].address + '</center></td><td><center>' + restaurantArr[i].distance.toFixed(2) + ' m</center></td></tr>';
}
str += '</table>';
str += "<div id='pager' class='pager'>";
str += "<form>"
str += "<img src='Tools/jquery.tablesorter/addons/pager/icons/first.png' class='first'/>";
str += "<img src='Tools/jquery.tablesorter/addons/pager/icons/prev.png' class='prev'/>"
str += "<input type='text' class='pagedisplay'/>";
str += "<img src='Tools/jquery.tablesorter/addons/pager/icons/next.png' class='next'/>";
str += "<img src='Tools/jquery.tablesorter/addons/pager/icons/last.png' class='last'/>";
str += "<select class='pagesize'>"
str += "<option selected='selected' value='5'>5</option>"
str += "<option value='10'>10</option>";
str += "<option value='15'>15</option>";
str += "<option value='20'>20</option>";
str += "<option value='25'>25</option>";
str += "<option value='30'>30</option>";
str += "<option value='35'>35</option>";
str += "<option value='40'>40</option>";
str += "<option value='45'>45</option>";
str += "<option value='50'>50</option>";
str += "</select>";
str += "</form>";
str += "</div>";
document.getElementById('restaurants_table').innerHTML = str;
$("table").tablesorter({headers: { 0:{ sorter: false }, 1:{ sorter: false }, 2: { sorter: false }}, widthFixed: true ,widgets: ['zebra']}).tablesorterPager({container: $("#pager")});
$('tr').click(function(event) {
var id = $(this).find(".IDcell").html();
if(id) {
window.location = "index.php?action=register_details&details_view_id=" + id + "&operation=v";
}
});
}
I have a lot more JavaScript code but i think this is enough to show my problem.
How do i render the table if the search form is in another php page?
Thanks in advance!
Firstly, you might want not to mix three techniques and try to use just one:
Writing HTML as string can be replaced with JQuery. For instance:
$("<div>").attr("id", "pager").append(...)
Addressing element by Id by native javascript can be replace with JQuery. (The first technique is faster, but this is rather about simplicity and using one technique instead of mixing them. For inst.:
$("#restaurant_table).html(insertedHtml);
You might event want to generate your pager like this:
$("<div>").attr("id", "pager").append(...).appendTo("#restaurant_table");
I guess you should address the tablesorter at least by its class:
$("table.tablesorter")
If you generate the structures on-the-fly, you might rather use "live" binder instead of the click binder - the click binder will address only those, which are already constructed by the browser:
$("table.tablesorter tr").live("click", function(event) {...});
You would probably pass the table/form to the other page with a POST.

Categories