How to run code only inside javascript function? - javascript

I'm trying with ajax to send innerhtml. Some attributes must be deleted before sending. When I click the buttton I delete the attributes and send..., and everything works fine, but my attributes are deleted in html as well.
They should only be deleted within the function and sent, but should not be deleted in html!
HOW TO AVOID IT.
Code:
<div id="container" class="container" >
<div id="parent1" class="parent">
<div id="child1" class="child" ondrop="drop(event);" ondragover="allowDrop(event);" >same content</div>
</div>
<div id="parent2" class="parent">
<div id="child2" class="child" ondrop="drop(event);" ondragover="allowDrop(event);" >same content</div>
</div>
<div id="parent3" class="parent">
<div id="child3" class="child" ondrop="drop(event);" ondragover="allowDrop(event);" >same content</div>
</div>
</div>
<button onclick="myFunction()">Click me</button>
function myFunction() {
var divsclass = Array.prototype.slice.call(document.getElementsByClassName("parent"));
var parenthtml = "";
divsclass.forEach(function(div){
Array.from(document.querySelectorAll(".parent [ondrop]")).forEach((elem) => elem.removeAttribute("ondrop"));
Array.from(document.querySelectorAll(".parent [ondragover]")).forEach((elem) => elem.removeAttribute("ondragover"));
var parenthtmlsend = div.innerHTML;
parenthtml += "&PARENTHTML"+ n++ +"=" + parenthtmlsend;
});
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
}
};
xmlhttp.open("GET", "same-page.php? "+ encodeURI(results) + parenthtml, true);
xmlhttp.send();
}
I tried copying the code to another div and then deleting atributes, but even then the attributes in the html code were deleted.
var containercopy = document.getElementById("container").innerHTML;
document.getElementById("container-copy").innerHTML = containercopy;
My code is big so I rewrote and give a brief example, maybe along the way I made a mistake ...

I'm not sure this is good way, but you can clone deeply your element in array and then do your changes with it.
see the code
function myFunction() {
var divsclass = Array.prototype.slice.call(document.getElementsByClassName("parent"));
var parenthtml = "";
divsclass.forEach(function(div){
// clone
var clonedDiv = div.cloneNode(true);;
Array.from(clonedDiv.querySelectorAll(".parent [ondrop]")).forEach((elem) => elem.removeAttribute("ondrop"));
Array.from(clonedDiv.querySelectorAll(".parent [ondragover]")).forEach((elem) => elem.removeAttribute("ondragover"));
var parenthtmlsend = clonedDiv.innerHTML;
parenthtml += "&PARENTHTML"+ n++ +"=" + parenthtmlsend;
});
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
}
};
xmlhttp.open("GET", "same-page.php? "+ encodeURI(results) + parenthtml, true);
xmlhttp.send();
}
It seems in your code n is undefined, but i didn't change it

Related

Why is document.ready being called twice?

$(document).ready(function() {
var page = 1;
var notEOF = true;
var client = new XMLHttpRequest();
var temp = "string";
client.open('GET', '/blog/blogdata.txt');
client.onreadystatechange = function() {
if (client.responseText != '') {
var txt = client.responseText.split("\n");
if (notEOF && txt[page * 6 - 6] != "EOF") {
var data = txt[page * 6 - 6].split("#");
document.getElementById("link1").setAttribute("href", data[0]);
document.getElementById("image1").setAttribute("src", data[1]);
document.getElementById("title1").innerHTML = data[2];
document.getElementById("text1").innerHTML = data[3];
document.getElementById("tags1").innerHTML = data[4];
document.getElementById("date1").innerHTML = data[5];
} else {
notEOF = false;
$("#article1").hide();
}
}
}
var blog_html = "/blog/page";
document.getElementById("prev").setAttribute("href", blog_html.concat((page - 1).toString()));
document.getElementById("next").setAttribute("href", blog_html.concat((page - 1).toString()));
if (page == 1) {
$("#prev").addClass("disabled tm-mr-20");
}
if (page == 2) {
document.getElementById("prev").setAttribute("href", "/blog/");
}
if (!notEOF) {
$("#next").addClass("disabled tm-mr-20");
}
client.send();
});
<script src="/blog/js/jquery.min.js"></script>
<script src="/blog/js/templatemo-script.js"></script>
<script src="https://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
This is a simplified version of a script I wrote in my blog html file to automate the blog part.
blog/blogdata.txt is a textfile consisting of lines of the form url#image url#title#text#tags#date, with the last line as just EOF. (If necessary, I can restructure this). This is the structure of a blog post (ripped from here)
<article class="col-12 col-md-6 tm-post" id="article1">
<hr class="tm-hr-primary">
<a href="post.html" class="effect-lily tm-post-link tm-pt-60" id="link1">
<div class="tm-post-link-inner">
<img src="/blog/img/img-01.jpg" alt="Image" class="img-fluid" id="image1">
</div>
<h2 class="tm-pt-30 tm-color-primary tm-post-title" id="title1">Simple and useful HTML layout</h2>
</a>
<p class="tm-pt-30" id="text1">
There is a clickable image with beautiful hover effect and active title link for each post item. Left side is a sticky menu bar. Right side is a blog content that will scroll up and down.
</p>
<div class="d-flex justify-content-between tm-pt-45">
<span class="tm-color-primary" id="tags1">Travel . Events</span>
<span class="tm-color-primary" id="date1">June 24, 2020</span>
</div>
</article>
And this is the structure of the previous and next buttons
<div class="row tm-row tm-mt-100 tm-mb-75">
<div class="tm-prev-next-wrapper">
Prev
Next
</div>
</div>
There's obviously more to the script (if there's anything necessary I'm omitting, I'll add it) but this is the important part of it.
I'm trying to run the file but it's not functioning as intended (currently, the blogdata.txt file has one non-EOF line, and thus the blog should contain exactly one post. Instead, it contains none). When I added alerts to try to debug, I observed that this script is being called twice. Why?
In your case
client.onreadystatechange = function() {
if (client.readyState === XMLHttpRequest.DONE && client.responseText != '') {
but this is better
client.open('GET', '/blog/blogdata.txt');
client.onload = function() { ... }
client.send()
Since you have jQuery
$(function() {
var page = 1;
var notEOF = true;
var temp = "string";
$.get('/blog/blogdata.txt', function(responseText) {
if (!responseText || responseText.toString().trim() === "") return
const txt = responseText.split("\n");
...
});
});

xmlHttpRequest issue

I am using Js xmlHttpRequest to display the same menu on different pages of my site. Lately I found out that some functions are not executed when the site is online, like a quiz I made.
I had also tried to use fetch, or put the scripts in different files, but the same thing kept happening.
(The quiz does work when checking locally, where the xml request cannot be satisfied.)
//load the menu
onload = function loadXMLDoc() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementsByTagName('body')[0].innerHTML +=
this.responseText;
}
};
xhttp.open("GET", "mnu.html", true);
xhttp.send();
}
//check the quiz
const checkBtn = document.getElementById('checkBtn')
checkBtn.onclick = function quizCheck() {
//right answers
var score = 0;
if (q1a1.checked) {
score = score + 1;
}
if (q2a1.checked) {
score = score + 1;
}
alert("your score: " + score);
}
<li>
Check the right answer:
<br>
<input type="checkbox" id="q1a1">Right
<br>
<input type="checkbox">Wrong
</li>
<li>
Check the right answer:
<br>
<input type="checkbox" id="q2a1">Right
<br>
<input type="checkbox">Wrong
</li>
<button id="checkBtn">Check</button>
Anybody knows why and/or has some solutions?
The problem is this line which is wrong and that's why js is not working.
document.getElementsByTagName('body')[0].innerHTML += this.responseText;
You can't just add to innerHtml like that.
Instead you should create an html element and add it to body like this:
if (this.readyState == 4 && this.status == 200) {
var p = document.createElement("p");
p.innerText = this.responseText;
document.body.appendChild(p);
}
edit: of course you want to add an html menu instead of just a text inside a <p>, so you will have to add it like this:
var nav = document.createElement('nav');
nav.innerHTML = this.responseText;
document.body.prepend(nav); // always at the top

Javascript button to show on condition

I am trying to make the button visible only when there's a table shown, but it doesn't seem to be working, the button is not hiding.
PS: Sorry for not clarifying, my javascript runs onload
HTML:
var DLFunc = document.getElementsByTagName("table");
var DLButtons = document.getElementById("tableToCsv");
if (DLFunc == "") {
DLButtons.style.visibility = 'hidden';
} else if (DLFunc != "") {
DLButtons.style.visibility = 'visible';
}
<div id="view-container">
<main ng-view></main>
</div>
<div id="tableToCsv">
<button class="btnCSV">CSV file</button>
</div>
Full HTML:
<body ng-controller="DataController">
<header ng-include="'FixedPages/header.html'"></header>
<div ng-include="'FixedPages/mapAHH.html'"></div>
<div id="view-container">
<main ng-view></main>
</div>
<div id="tableToCsv">
<button class="btnCSV">CSV file</button>
</div>
<footer ng-include="'FixedPages/footer.html'"></footer>
<script src="js\DownloadCSV.js"></script>
</body>
Check if there is a table shown by counting the number of table tags. Instead of checking empty string, check for the length of the array:
var DLFunc = document.getElementsByTagName("table");
var DLButtons = document.getElementById("tableToCsv");
if (DLFunc.length == 0) {
DLButtons.style.visibility = 'hidden';
} else {
DLButtons.style.visibility = 'visible';
}
Also check when the code runs (maybe add an alert) as the tables may not have been created at the time your JS is running.
UPDATE:
Your JS won't pick up the table as it is run on page load, whereas AngularJS probably creates the elements later.
You can add something like the following to your DLButtons HTML:
<button class="btnCSV" *ngShow="hasTable()">CSV file</button>
Then in your Angular Component.ts/js:
hasTable() {
return document.getElementsByTagName("table").length > 0;
}
You can do the following;
// you can check directly in the condition
const DLFunc = document.getElementsByTagName("table");
const DLButtons = document.getElementById("tableToCsv");
if (DLFunc)
{
DLButtons.style.visibility = 'hidden';
}
else
{
DLButtons.style.visibility = 'visible';
}
Try this:
var DLFunc = document.getElementsByTagName("table");
var DLButtons = document.getElementById("tableToCsv");
if (DLFunc.length == 0) {
DLButtons.style.visibility = 'hidden';
} else {
DLButtons.style.visibility = 'visible';
}
<div id="view-container">
<main ng-view></main>
</div>
<div id="tableToCsv">
<button class="btnCSV">CSV file</button>
</div>

Run function for multiple items in JS

I have a function that is responsible for updating the values in some <div>, the code looks like this:
file.js
window.onload = function makeRequest() {
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
calcPreco(xmlHttp.responseText);
}
xmlHttp.open("GET", "_config/buscar_valor.php?id="+document.getElementsByName("cloud")[0].getAttribute("cloudid")+"&periodicidade=monthly", true); // true para asynchronous
xmlHttp.send(null);
}
function calcPreco(preco) {
console.log(preco);
preco = preco.replace(",", ".");
preco -= document.getElementsByName("cloud")[0].getAttribute("desconto");
document.getElementsByClassName("mostrar_valor").textContent = preco;
}
index.php
<div name="cloud" cloudid="1" desconto="5">
<span class="mostrar_valor"></span>
</div>
<div name="cloud" cloudid="2" desconto="10">
<span class="mostrar_valor"></span>
</div>
<div name="cloud" cloudid="3" desconto="15">
<span class="mostrar_valor"></span>
</div>
Note that only the cloudid anddesconto attributes are changed in each <div>, the remainder remains the same.
The script will only do a calculation by searching for the value in "buscar_valor.php", through the cloudid attribute, which is the ID of each plan.
The desconto attribute is the amount it will subtract from the account.
The problem is that it is doing this only for the first <div>, how can I make it work for all <div>?
You have to loop over all cloud elements as:
for(const cloud of Array.from(document.getElementsByName("cloud"))) {
To then retrieve the related preco from the API I would use the new fetch method as that is way more easy to handle:
fetch("_config/buscar_valor.php?id=" + cloud.getAttribute("cloudid")+ "&periodicidade=monthly")
.then(res => res.text())
.then(preco => {
Now the desconto can be applied to preco:
preco -= cloud.getAttribute("desconto");
To get the mostrar_valor insode that cloud, just use querySelector:
const valor = cloud.querySelector(".mostrar_valor");
then you can change the textContent of that element.

Getting All Same IDs with Java Script

The java script only get the first id. The 2nd id ignores the code. Are there anyway to make both IDs using the same java script ?
Add Item
List Items
<div id="add_item" class="tabcontent">
<div id="subcatchooser"></div>
<div id="list_item" class="tabcontent">
<div id="subcatchooser"></div>
Java Script here
function showsubcat(str) {
if (str.length == 0) {
document.getElementById("subcatchooser").innerHTML = "";
return;
} else {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("subcatchooser").innerHTML = this.responseText;
}
};
xmlhttp.open("GET", "ajax.php?action=showsubcat&parent_id=" + str, true);
xmlhttp.send();
}
}
</script>
That is the main difference between classes and IDs. Classes are designed to be used multiple times, while IDs are designed to be unique. So you can change the divs to look like this:
<div class="subcatchooser"></div>
And then change the JavaScript to look like this:
var elements = document.getElementsByClassName("subcatchooser");
for (var i = 0; i < elements.length; i++) {
elements[i].innerHTML = "";
}

Categories