Javascript method not toggling as expected - javascript

I have a word matching exercise game that is written in javascript and html. When the user clicks add more the add_more() method adds a new key, description pair to the keys and descriptions input boxes. Then when the user clicks generate html the generate_html() method should create a new textarea box with the html to be generated.
Expected:
The user clicks add more then clicks generate html new html is generated once.
Actual:
The user clicks add more then clicks generate html new html is generated more than once.
The program is relatively simple. These are the two methods
function generate_html() {
// retrieve the keys and descriptions. Then load them into their respective arrays.
const e_inputs = document.querySelectorAll("[id^='el']");
const d_inputs = document.querySelectorAll("[id^='dl']");
let elArray = [];
let dlArray = [];
const title = document.getElementById('title_input').value;
e_inputs.forEach( i => { if(i.value) elArray.push(i.value) });
d_inputs.forEach( i => { if(i.value) dlArray.push(i.value) });
//have we added more?
if(addMore && htmlGenerated){
// then delete the old textarea.
textarea = document.getElementById("generated_html_textarea");
textarea.remove();
// delete the controls.
controls = document.getElementById("program1");
controls.remove();
}
//has the html already been generated?
if(!htmlGenerated){
//fetch the results box
results = document.getElementById("results");
//create textarea
textarea = document.createElement("textarea");
textarea.setAttribute("id","generated_html_textarea");
// initialize blank html
let html = '';
html += '<div id=\"maincontentstyle\">\n'
html += '\t<center>\n'
html += '\t\t<div id=\"boxstyle\">\n'
html += '\t\t\t<h3 id=\"title\">'+title+"</h3>\n";
//create key inputs
html += '\t\t\t\t<center>\n'
html += '\t\t\t\t\t<div class="source">\n'
for (let i = numberOfInputs; i < elArray.length+numberOfInputs; i++){
html += '\t\t\t\t\t\t<div id="s';
id = (1+i-numberOfInputs);
html += id;
html +='\" class=\"draggyBox-small\">\n';
html += `\t\t\t\t\t\t\t${elArray[i-numberOfInputs]}\n`;
html +='\t\t\t\t\t\t</div>\n';
}
html += '\t\t\t\t\t</div>\n'
html += '\t\t\t\t\t</center>\n'
//create description inputs
html += '\t\t\t\t\t<table id=\"tablestyle\">\n'
for (let i = numberOfInputs; i < dlArray.length+numberOfInputs; i++){
html +='\t\t\t\t\t\t<tr>\n'
html += '\t\t\t\t\t\t<td id="row';
id = (1+i-numberOfInputs);
html += id;
html +='">\n';
html += '\t\t\t\t\t\t\t<div id=\"t';
html += id;
html +='" class=\"ltarget\">'
html +='</div>\n'
html +='\t\t\t\t\t\t</td >\n'
html +='\t\t\t\t\t\t<td id=\"d'
html += id
html += '\">\n'
html +=`\t\t\t\t\t\t\t${dlArray[i-numberOfInputs]}\n`;
html +='\t\t\t\t\t\t\t</td >\n'
html +='\t\t\t\t\t\t</tr>\n';
}
html += '\t\t\t\t\t</table>\n';
html += '\t\t\t\t</center>\n'
html += '\t\t</div>\n'
html += '\t</center>\n'
html += '</div>'
// html generation is done.
htmlGenerated = true;
textarea.value = html;
results.appendChild(textarea);
// Generate reset, show answer, , and render html buttons
controls = document.createElement("div");
controls.setAttribute("id","program1");
controls.setAttribute("style","border: 1px solid #EB0D1B; width: 360px; font-family: courier; font-size: 100.5%; margin: 0px auto; border: 1px; text-align: center; margin-top: 5px;");
controls.innerHTML += '<button id = "renderHTMLButton" class="button" type="button" onClick="render_html()">Render html</button> <span id = "audio" style=""> <img id="bg" src="audioOff.png" height="30" width="30" style="margin-bottom:-10px; padding-bottom:-20px;"/> </span>';
results.appendChild(controls);
}
}
function add_more() {
// we've added more inputs.
addMore = true;
// set html generated to false, because new inputs have been added.
htmlGenerated = false;
// increment the number of inputs.
numberOfInputs++;
//fetch the input boxes.
inputs = document.getElementById("inputBoxes");
//create a new row for a key term.
row = document.createElement("div");
row.setAttribute("class","row");
// set the key term text.
row.innerHTML = "Key Term ";
row.innerHTML +=numberOfInputs;
row.innerHTML +=" :";
// create the input for the key.
key = document.createElement("input");
key.setAttribute("id","el"+numberOfInputs);
//add the key to the row.
row.appendChild(key);
//create a row for the new description.
row2 = document.createElement("div");
row2.setAttribute("class","row");
// set the description text.
row2.innerHTML = "Description "
row2.innerHTML+=numberOfInputs;
row2.innerHTML+=" :";
// create the description input
description = document.createElement("input");
description.setAttribute("id","dl"+numberOfInputs);
// add the description to the row.
row2.appendChild(description);
// add the rows for the key and the description to the inputBoxes.
inputs.appendChild(row);
inputs.appendChild(row2);
}
the gitub link is here.

Your issue is that you are appending child nodes to the result:
211 results.appendChild = textarea;
Change this to use replaceChildren so you rather replace the content and not keep appending:
211 results.replaceChildren(textarea);

Related

Covert html in javascript to HTML tags

I'm working on the tooltips and from the backend I'll get data in with html tags. I need to show in the tooltip with its corresponding data in its respective tags. For example, I'll get hello user click here from the backend. I've to show as hello user in h1 format and click here should be a anchor. I tried with both functions and replace its not working.
With function:
<h1 id="data">
</h1>
function convertToPlain(html){
var tempDivElement = document.createElement("div");
tempDivElement.innerHTML = html;
return tempDivElement.textContent || tempDivElement.innerText || "";
}
var htmlString= "<div><h1>Bears Beets Battlestar Galactica </h1>\n<p>Quote by Dwight Schrute<a> click here<a></p></div>";
let dataVal = convertToPlain(htmlString)
document.getElementById("demo").innerHTML = dataVal;
With replace:
https://codesandbox.io/s/serene-fast-u8fie?file=/App.svelte
I made below snippet by copy-paste your code and just update return statement inside convertToPlain function, also I added href attribute to <a> in the htmlString content.
function convertToPlain(html) {
var tempDivElement = document.createElement("div");
tempDivElement.innerHTML = html;
return tempDivElement.innerHTML;
}
var htmlString = "<div><h1>Bears Beets Battlestar Galactica </h1>\n<p>Quote by Dwight Schrute<a href='#'> click here<a></p></div>";
let dataVal = convertToPlain(htmlString)
document.getElementById("demo").innerHTML = dataVal;
<h1 id="demo"></h1>

Getting the getElementId Dynamically from HTML

So I am writing a Js script that accepts a number of rows and number of columns from the HTML. This will generate an HTML template for the customer using for loops . A customer should have the ability to select a product that features on the HTML template. this will take up 2 columns on the template instead of one.
The way I am trying to allow the customer to choose where the featured product displays a table.
function featProdDisplay(column, row) {
let body;
body = `<table style = "border-collapse: collapse;">`;
for (let i = 0; i < row; i++) {
body += `<tr>`
for (let j = 0; j < column; j++) {
pos = Number(i) + Number(j);
body += `<td id = "` + pos + `onclick="Selected()">
<div>
</div>
</td>`
};
body += `</tr>`
};
body += `</table>`;
return body;
}
function DisplayTable(column, row) {
body = featProdDisplay(column, row);
document.getElementById("FeatDisplay").innerHTML = body;
}
The way i was thinking is that the customer clicks on a block and drags it down to where the he/she would like it to end. those s will then change color.
So my question is is there any way to get the position or IDs of those s that have been selected as the ID is generated Dynamically and getElementById() requires a preexisting ID? Or should I try a different approach entirely?
Thank you in advance

How can I add a span to h3 Element with javascript

I'm making a chat and I want to add an avatar pics feature so I figured it might work well with span, but the problem is I don't know how to add the span to the element.
let avatar = document.createElement("span");
let userMessage = document.createElement("H3");
avatar.setAttribute(userMessage);
userMessage.innerHTML = username + ": " + message;
//document.getElementById("chat").appendChild(avatar);
document.getElementById("chat").appendChild(userMessage);
userMessage.style.background = color;
userMessage.style.textAlign = "left";
document.getElementById("msg").value = "";
I am assuming that you have div with id="chat" and you want to append an h3 tag in a span and then append the chat div so your code will look like this
var username="zulqarnain jalil";
var message ="welcome back, have a nice day";
var color='lightgrey';
var avatar = document.createElement("span");
var userMessage = document.createElement("h3");
userMessage.innerHTML = username + ": " + message;
userMessage.style.background = color;
userMessage.style.textAlign = "left";
avatar.appendChild(userMessage);
document.getElementById("chat").appendChild(avatar);
//document.getElementById("msg").value = "";
<div id="chat">
</div>
I have created a chatbot snippet for you, here you can test it
var username="zulqarnain jalil";
function sendMessage()
{
var message =document.getElementById('messagebox').value;
if(message)
{
document.getElementById('messagebox').value='';
var color='lightgrey';
var avatar = document.createElement("span");
var userMessage = document.createElement("h3");
userMessage.innerHTML = username + ": " + message;
userMessage.style.background = color;
userMessage.style.textAlign = "left";
avatar.appendChild(userMessage);
document.getElementById("chat").appendChild(avatar);
}
else
{
// message empty
}
}
//document.getElementById("msg").value = "";
<div id="chatBox">
<div id="chat">
</div>
<div>
<input type="text" id="messagebox" />
<input type="button" onclick="sendMessage()" value="Send" />
</div>
</div>
First you need to add the span as a child of the H3 element.
I think the best approach to this problem is creating a class Message. Initializing that class creates h3 and span with unique ids stored in a variable id for future use. The class will also add the h3 as a child of it's parent element ( what ever it is ), and the span as a child of the h3 element.
var counterText = 0;
var counterAvatar = 0;
class UserMessage {
constructor(msgTxt, avatar){
// This block initializes the text message of the user
// It will also add an id to the tag for future use
let msgTxt = document.createTextNode(msgTxt);
this.messageID = 'text' + counterText;
this.message = document.createElement('h3');
this.message.appendChild(msgTxt);
this.message.setAttribute('id', this.messageID);
counterText++;
// This block creates an img element with the attributes src and id
this.avatarID = 'avatar' + counterAvatar;
this.avatar = document.createElement('img');
this.avatar.setAttribute('src', avatar);
this.avatar.setAttribute('id', this.avatarID);
counterAvatar++;
// This block appends the avatar element to the text and the text to the
// chat div.
let chat = document.getElementById('chat');
this.message.appendChild(this.avatar);
chat.appendChild(this.message);
}
}
to initialize a new instance:
var message = new UserMessage("Hello, this is a text message!",'<path/to/avatar>')
this is an object oriented aproach.
you could also just append the avatar to the message and the message to the chat.
But I think aproaching the problem in an object oriented way is much better since it will save time in the future when you're updating your app.
Markdown works fine in here.
Block-level HTML elements have a few restrictions:
They must be separated from surrounding text by blank lines.
The begin and end tags of the outermost block element must not be indented.
Markdown can't be used within HTML blocks.

Can't create tag <tbody> in <table> tag with javascript

I'm trying to create a table showing file information for members after uploading. However, for some reasons, the tag causes the layout to be deflected.
When I open the F12 window, my code is as shown below:
The problem lies in the tag and the tag conjoined together.
Now, I just edit it by adding a space marker or a line delimiter:
Immediately, it creates another tag and contains the entire , tag inside. Interface restored, no more errors!
Here is my entire source code:
<table id="files" class="files table table-striped" width="100%"></table>
var isSuccess = true;
if(data['result'][0]['error'] != null)
{
isSuccess = false;
}
var html = ''; // I tried adding the <tbody></tbody> tag here but
// it still needs a space or line break -> not working!
html += '<tr class="template-download';
if(isSuccess == false)
{
html += ' errorText';
}
html += '" ';
if(isSuccess == true)
{
html += 'onClick="return showAdditionalInformation(this);"';
}
html += '>';
if(isSuccess == true)
{
html += data['result'][0]['success_result_html'];
}
else
{
html += data['result'][0]['error_result_html'];
}
html += '</tr>';
function handleUrlUploadSuccess(data)
{
isSuccess = true;
if(data.error != null)
{
isSuccess = false;
}
html = '';
html += '<tr class="template-download';
if(isSuccess == false)
{
html += ' errorText';
}
html += '" onClick="return showAdditionalInformation(this);">'
if(isSuccess == false)
{
// add result html
html += data.error_result_html;
}
else
{
// add result html
html += data.success_result_html;
// keep a copy of the urls globally
fileUrls.push(data.url);
fileDeleteHashes.push(data.delete_hash);
fileShortUrls.push(data.short_url);
}
html += '</tr>';
$('#rowId'+data.rowId).replaceWith(html);
if(data.rowId == urlList.length-1)
{
// show footer
$('#urlUpload .urlFileListingWrapper .processing-button').addClass('hidden');
$('#urlUpload .fileSectionFooterText').removeClass('hidden');
// set additional options
sendAdditionalOptions();
// setup copy link
setupCopyAllLink();
}
}
The start of your loop or javascript should just be the open tag and not the close. At the end of the loop/javascript you should have the close tag. They should be wrapping all of the table row tags being created.
I'd look at using a single string for your row template then use replace to update it
var html = '';
//Template for our row
var row = "<tr class='template-download{{additionalClasses}} {{onClick}}>{{data}}</tr>"
//Dummy Data
var isSuccess = true;
var data = {
result : [{
success_result_html: "<td>Success</td>",
error_result_html: "<td>Fail</td>"
}]
};
//Populate row depending on condition
if(isSuccess)
{
html = row.replace("{{additionalClasses}}","")
.replace("{{onClick}}", "onClick='return showAdditionalInformation(this);'")
.replace("{{data}}", data['result'][0]['success_result_html']);
}
else
{
html = row.replace("{{additionalClasses}}"," errorText")
.replace("{{onClick}}", "")
.replace("{{data}}", data['result'][0]['error_result_html']);
}
//Add the row to the tbody
document.querySelector("#files tbody").innerHTML = html;
<table id="files" class="files table table-striped" width="100%">
<!-- Add tbody here-->
<tbody>
</tbody>
</table>

Simple ToDo-List doesn't work

My ToDo List dont wanna work the way i want. I've just been working with JavaScript for 2 weeks sthis is very new to me, therefor the code maybe doesnt look that nice.
The result comes out wrong. If I type in "buy food" the first line gonna show just that, but the next time I wanna add "walk the dog", then it displays
buy food
buy food
walk the dog
I hope you understand my problem. It also ends the unordered list tag after the first click and adds the rest of the things in another.
Here's the JavaScript:
var taskList = [];
var text = "<ul>"
function addToList() {
var task = document.getElementById("toDoTask").value;
taskList.push(task);
for(i = 0; i < taskList.length; i++){
text += "<li>" + taskList[i] + "</li>" ;
}
text += "</ul>";
document.getElementById("todoList").innerHTML = text;
}
The issue is you're closing the ul tag after adding each item. Instead of concatenating raw HTML, consider using element objects and appending, and using a text node object to handle the user input - this removes the possibility of a DOM Based XSS vulnerability.
window.onload = function() {
var taskList = [];
var container = document.getElementById("todoList");
document.getElementById("add").onclick = addToList;
function addToList() {
var task = document.getElementById("toDoTask").value;
taskList.push(task);
var ul = document.createElement('ul');
var li;
for (i = 0; i < taskList.length; i++) {
li = document.createElement('li');
li.appendChild(document.createTextNode(taskList[i]))
ul.appendChild(li);
}
container.innerHTML = '';
container.appendChild(ul);
}
};
Task:
<input id="toDoTask" /> <input type="button" id="add" value="Add" />
<div id="todoList">
</div>
You should not use the innerHtml. This replace all the text of your content. You should just add the li to your ul.
You can do that by using the append function by jquery Append
your <ul> must contain an id like this <ul id="toDoList">
then you make $("#toDoList").append("yourTask");
yourTask must contains the li.
With this, you don't need to iterate on all your element list
Not sure, but you seem to keep adding to text the second time, so text will be something like <ul><li>buy food</li></ul><li>buy food</li><li>walk the dog</li></ul>, which is invalid HTML by the way, but gets outputted anyway...
On each call of function addToList() you should reset the variable text.
For example:
function addToList() {
var task = document.getElementById("toDoTask").value;
taskList.push(task);
text="";
for(i = 0; i < taskList.length; i++){
text += "<li>" + taskList[i] + "</li>" ;
}
text += "</ul>";
document.getElementById("todoList").innerHTML = text;
}
The whole list of items in array will appends to variable text on each call.

Categories