Stop a js function from loading on initial page load - javascript

I am trying to stop a JS function from loading every time a page is loaded, i wanted it to work only when a button is clicked. I have tried using onclick and .addEventListener.On using onclick, the output data displays before clicking the load data button and on using .addEventListener no data loads even on clicking the button. Any help would be appreciated, Thank you!
<html>
<head>
<title> Monitoring</title>
</head>
<body>
<div id="output"></div>
<script src="./lib/mam.web.min.js"></script>
<script>
const TRYTE_ALPHABET = 'SFRRJJVGGYJI';
const asciiToTrytes = (input) => {
let trytes = '';
for (let i = 0; i < input.length; i++) {
var dec = input[i].charCodeAt(0);
trytes += TRYTE_ALPHABET[dec % 27];
trytes += TRYTE_ALPHABET[(dec - dec % 27) / 27];
}
return trytes;
};
const trytesToAscii = (trytes) => {
let ascii = '';
for (let i = 0; i < trytes.length; i += 2) {
ascii += String.fromCharCode(TRYTE_ALPHABET.indexOf(trytes[i]) + TRYTE_ALPHABET.indexOf(trytes[i + 1]) * 27);
}
return ascii;
};
const outputHtml = document.querySelector("#output");
const mode = 'public'
const provider = ''
const mamExplorerLink = ``
// Initialise MAM State
let mamState = Mam.init(provider)
// Publish to tangle
const publish = async packet => {
// alert("coming into publish");
// Create MAM Payload - STRING OF TRYTES
const trytes = asciiToTrytes(JSON.stringify(packet))
const message = Mam.create(mamState, trytes)
// alert("p2");
// Save new mamState
mamState = message.state
// alert("p3");
// Attach the payload
await Mam.attach(message.payload, message.address, 3, 9)
// alert("p4");
outputHtml.innerHTML += `Published: ${packet}<br/>`;
// alert(message.root);
return message.root
}
const publishAll = async () => {
// alert("Yes 1.3");
const root = await publish('ALICE')
return root
}
// Callback used to pass data out of the fetch
const logData = data => outputHtml.innerHTML += `Fetched and parsed ${JSON.parse(trytesToAscii(data))}<br/>`;
(async function GKpublishAll(){
const root = await publishAll();
// alert(root);
outputHtml.innerHTML += `${root}`;
})();
</script>
<form>
Publish message :
<input type="submit" onclick="GKpublishAll()">
</form>
</body>
</html>

This piece of code defines and immediately calls the GKpublishAll function, if you don't want it called on page load, you should change the code from this:
(async function GKpublishAll(){
const root = await publishAll();
// alert(root);
outputHtml.innerHTML += `${root}`;
})();
to this:
async function GKpublishAll(){
const root = await publishAll();
// alert(root);
outputHtml.innerHTML += `${root}`;
}
Then, to use it when a button is clicked, you attach it to a button's onclick handlers like so:
<button onclick="GKpublishAll()">Click me</button>

There are some unclear/uncertain/hidden parts of the code you posted. maybe you should start with a simplified version of it that shows the definitions and invocations.
for example, there is a function called logData you defined but never invoked/used. where should it be used, I didn't see any fetch here
#Ermir answer is the right answer for the question "why this piece of code works even without clicking the button?"

On the <button> tag, you may want to add a attribute instead of adding a javascript event: mouseclick="function()". If it gives an error, try click="function()". Or try onclick="function()".
Hope it helps!

Related

VSCode API: Editor.edit editbuilder.replace fails without reason (possibly due to formatting?)

In my extension I want to edit the document on a few specific document edits.
My actual use case is a bit complicated so I have created a minimal example. The code below listens for any document edit. If the word "hello" exists in the edit (i.e. the user pasted some code that contains the word "hello") then we replace the change range with the pasted text but just make it upper case.
We also console.log if the edit was successful, and any potential reason the edit was rejected.
vscode.workspace.onDidChangeTextDocument(event => {
for (const change of event.contentChanges) {
if (change.text.includes("hello")) {
activeEditor.edit(editBuilder => {
editBuilder.replace(change.range, change.text.toUpperCase());
}).then(
value => console.log("SUCCESS: "+value),
reason => console.log("FAIL REASON: "+reason),
);
}
}
});
A working example would be selecting some text in a document and pasting in the text const hello = 5;. As expected, the extension replaces the text with CONST HELLO = 5; and logs SUCCESS: true.
But when I paste in some text that automatically get formatted I run into problems. If I were to paste in:
const hello = 5;
const lol = 10;
const lmao = 20;
Including all the whitespaces/tabs, then vscode wants to "format" or correct my lines, i.e. remove the whitespace. So the resulting text will be:
const hello = 5;
const lol = 10;
const lmao = 20;
The extension tries to make it uppercase still but only prints SUCCESS: false. No reason is logged at all; the reject function is not executed.
Why does the edit not succeed? Should I await the other edits somehow or keep re-trying the edit until it succeeds? Am I logging the rejection incorrectly?
In case it helps, here is code I use - I found it better to have the editBuilder outside the loop. I think you can adapt it for your purposes:
editor.edit( (editBuilder) => {
// put your for (const change of event.contentChanges) {} here
for (const match of matches) {
resolvedReplace = variables.buildReplace(args, "replace", match, editor.selection, null, index);
const matchStartPos = document.positionAt(match.index);
const matchEndPos = document.positionAt(match.index + match[0].length);
const matchRange = new vscode.Range(matchStartPos, matchEndPos);
editBuilder.replace(matchRange, resolvedReplace);
}
}).then(success => {
if (!success) {
return;
}
if (success) { ... do something here if you need to }
});
One solution is just to "keep trying again". I do not like this solution, but it is a solution nevertheless, and it currently works for my use-case.
async function makeReplaceEdit(range: vscode.Range, text: string, maxRetries = 10) {
for (let i = 0; i <= maxRetries; i++) {
const editor = vscode.window.activeTextEditor;
if (!editor) return;
const success = await editor.edit(editBuilder => {
editBuilder.replace(
range,
text
);
}, { undoStopBefore: false, undoStopAfter: false });
if (success) break;
}
};
vscode.workspace.onDidChangeTextDocument((event) => {
// See if any change contained "hello"
let foundHello = false;
for (const change of event.contentChanges) {
if (change.text.includes("hello")) {
foundHello = true;
}
}
if (foundHello) {
console.log("inside1");
const editor = vscode.window.activeTextEditor;
if (!editor) return;
makeReplaceEdit(editor.document.lineAt(0).range, "Change");
}
});

Async JS validation issues for html textarea

I'm trying to replicate the code in this article:
https://depth-first.com/articles/2020/08/24/smiles-validation-in-the-browser/
What I'm trying to do different is that I'm using a textarea instead of input to take multi-line input. In addition to displaying an error message, I also want to display the entry which doesn't pass the validation.
The original validation script is this:
const path = '/target/wasm32-unknown-unknown/release/smival.wasm';
const read_smiles = instance => {
return smiles => {
const encoder = new TextEncoder();
const encoded = encoder.encode(`${smiles}\0`);
const length = encoded.length;
const pString = instance.exports.alloc(length);
const view = new Uint8Array(
instance.exports.memory.buffer, pString, length
);
view.set(encoded);
return instance.exports.read_smiles(pString);
};
};
const watch = instance => {
const read = read_smiles(instance);
document.querySelector('input').addEventListener('input', e => {
const { target } = e;
if (read(target.value) === 0) {
target.classList.remove('invalid');
} else {
target.classList.add('invalid');
}
});
}
(async () => {
const response = await fetch(path);
const bytes = await response.arrayBuffer();
const wasm = await WebAssembly.instantiate(bytes, { });
watch(wasm.instance);
})();
For working with a textarea, I've changed the watch function to this and added a <p id="indicator"> element to the html to display an error:
const watch = instance => {
const read = read_smiles(instance);
document.querySelector("textarea").addEventListener('input', e => {
const { target } = e;
var lines_array = target.value.split('/n');
var p = document.getElementById("indicator");
p.style.display = "block";
p.innerHTML = "The size of the input is : " + lines_array.length;
if (read(target.value) === 0) {
target.classList.remove('invalid');
} else {
target.classList.add('invalid');
}
});
}
I'm not even able to get a count of entries that fail the validation. I believe this is async js and I'm just a beginner in JavaScript so it's hard to follow what is happening here, especially the part where the function e is referencing itself.
document.querySelector("textarea").addEventListener('input', e => {
const { target } = e;
Can someone please help me in understanding this complicated code and figuring out how to get a count of entries that fail the validation and also printing the string/index of the same for helping the user?
There is a mistake in you code to count entries in the textarea:
var lines_array = target.value.split('\n'); // replace /n with \n
You are asking about the function e is referencing itself:
The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables. You can find more informations Mdn web docs - Destructuring object

How to make react stop duplicating elements on click

The problem is that every time I click on an element with a state things appear twice. For example if i click on a button and the result of clicking would be to output something in the console, it would output 2 times. However in this case, whenever I click a function is executed twice.
The code:
const getfiles = async () => {
let a = await documentSpecifics;
for(let i = 0; i < a.length; i++) {
var wrt = document.querySelectorAll("#writeto");
var fd = document.querySelector('.filtered-docs');
var newResultEl = document.createElement('div');
var writeToEl = document.createElement('p');
newResultEl.classList.add("result");
writeToEl.id = "writeto";
newResultEl.appendChild(writeToEl);
fd.appendChild(newResultEl);
listOfNodes.push(writeToEl);
listOfContainers.push(newResultEl);
wrt[i].textContent = a[i].data.documentName;
}
}
The code here is supposed to create a new div element with a paragraph tag and getting data from firebase firestore, will write to the p tag the data. Now if there are for example 9 documents in firestore and i click a button then 9 more divs will be replicated. Now in total there are 18 divs and only 9 containing actual data while the rest are just blank. It continues to create 9 more divs every click.
I'm also aware of React.Strictmode doing this for some debugging but I made sure to take it out and still got the same results.
Firebase code:
//put data in firebase
createFileToDb = () => {
var docName = document.getElementById("title-custom").value; //get values
var specifiedWidth = document.getElementById("doc-width").value;
var specifiedHeight = document.getElementById("doc-height").value;
var colorType = document.getElementById("select-color").value;
parseInt(specifiedWidth); //transform strings to integers
parseInt(specifiedHeight);
firebase.firestore().collection("documents")
.doc(firebase.auth().currentUser.uid)
.collection("userDocs")
.add({
documentName: docName,
width: Number(specifiedWidth), //firebase-firestore method for converting the type of value in the firestore databse
height: Number(specifiedHeight),
docColorType: colorType,
creation: firebase.firestore.FieldValue.serverTimestamp() // it is possible that this is necessary in order to use "orderBy" when getting data
}).then(() => {
console.log("file in database");
}).catch(() => {
console.log("failed");
})
}
//get data
GetData = () => {
return firebase.firestore()
.collection("documents")
.doc(firebase.auth().currentUser.uid)
.collection("userDocs")
.orderBy("creation", "asc")
.get()
.then((doc) => {
let custom = doc.docs.map((document) => {
var data = document.data();
var id = document.id;
return { id, data }
})
return custom;
}).catch((err) => {console.error(err)});
}
waitForData = async () => {
let result = await this.GetData();
return result;
}
//in render
let documentSpecifics = this.waitForData().then((response) => response)
.then((u) => {
if(u.length > 0) {
for(let i = 0; i < u.length; i++) {
try {
//
} catch(error) {
console.log(error);
}
}
}
return u;
});
Edit: firebase auth is functioning fine so i dont think it has anything to do with the problem
Edit: This is all in a class component
Edit: Clicking a button calls the function createFileToDb
I think that i found the answer to my problem.
Basically, since this is a class component I took things out of the render and put some console.log statements to see what was happening. what i noticed is that it logs twice in render but not outside of it. So i took the functions out.
Here is the code that seems to fix my issue:
contain = () => {
const documentSpecifics = this.waitForData().then((response) => {
var wrt = document.getElementsByClassName('writeto');
for(let i = 0; i < response.length; i++) {
this.setNewFile();
wrt[i].textContent = response[i].data.documentName;
}
return response;
})
this.setState({
docs: documentSpecifics,
docDisplayType: !this.state.docDisplayType
})
}
As for creating elements i put them in a function so i coud reuse it:
setNewFile = () => {
const wrt = document.querySelector(".writeto");
const fd = document.querySelector("#filtered-docs");
var newResultEl = document.createElement('div');
newResultEl.classList.add("result");
var wrtEl = document.createElement('p');
wrtEl.classList.add("writeto");
fd.appendChild(newResultEl);
newResultEl.appendChild(wrtEl);
}
The firebase and firestore code remains the same.
the functions are called through elements in the return using onClick.

How/When to remove child elements to clear search result?

Trying to clear my search result after I submit a new API call. Tried implementing gallery.remove(galleryItems); at different points but to no avail.
A bit disappointed I couldn't figure it out but happy I was able to get a few async functions going. Anyway, here's the code:
'use strict';
const form = document.querySelector('#searchForm');
const gallery = document.querySelector('.flexbox-container');
const galleryItems = document.getElementsByClassName('flexbox-item');
form.addEventListener('submit', async (e) => {
e.preventDefault();
const userSearch = form.elements.query.value; // grab user input
const res = await getRequest(userSearch); // async func that returns a fully parsed Promise
tvShowMatches(res.data); // looks for matches, creates and appends name + image;
form.elements.query.value = '';
});
const getRequest = async (search) => {
const config = { params: { q: search } };
const res = await axios.get('http://api.tvmaze.com/search/shows', config);
return res;
};
const tvShowMatches = async (shows) => {
for (let result of shows) {
if (result.show.image) {
// new div w/ flexbox-item class + append to gallery
const tvShowMatch = document.createElement('DIV')
tvShowMatch.classList.add('flexbox-item');
gallery.append(tvShowMatch);
// create, fill & append tvShowName to tvShowMatch
const tvShowName = document.createElement('P');
tvShowName.textContent = result.show.name;
tvShowMatch.append(tvShowName);
// create, fill & append tvShowImg to tvShowMatch
const tvShowImg = document.createElement('IMG');
tvShowImg.src = result.show.image.medium;
tvShowMatch.append(tvShowImg);
}
}
};
Thanks
Instead of gallery.remove(galleryItems); consider resetting gallery.innerHTML to an empty string whenever a submit event occurs
Like this:
form.addEventListener('submit', async (e) => {
e.preventDefault();
gallery.innerHTML = ''; // Reset here
const userSearch = form.elements.query.value; // grab user input
const res = await getRequest(userSearch); // async func that returns a fully parsed Promise
tvShowMatches(res.data); // looks for matches, creates and appends name + image;
form.elements.query.value = '';
});
I believe this will do it.. you were close.
const galleryItems = document.getElementsByClassName('flexbox-item');
// to remove
galleryItems.forEach(elem => elem.remove() );

How do you call a asynchronous function using setInterval?

I get a random word and then use the word to generate a GIF.
My code here runs for only one time. I want it to generate another word and get another image without refreshing the browser.
So,I have used setInerval();by passing the the function that gets the image using fetch()
const section = document.getElementById('main');
const text = document.querySelector('.word');
let wordurl = 'https://random-word-api.herokuapp.com/word?number=1&swear=0';
let giphyapikey = '*****************';
//Setinterval
setInterval(wordgif(), 5000);
//make WordGIF call
function wordgif() {
wordGIF().then(results => {
text.innerHTML = results.word;
section.innerHTML = `<img src=${results.imgurl}>`;
}).catch(err => console.error(err))
}
//Async/await
async function wordGIF() {
let fetchword = await fetch(wordurl);
let word = await fetchword.json();
console.log(word)
let fetchgif = await fetch(`http://api.giphy.com/v1/gifs/search?q=${word}&api_key=${giphyapikey}&limit=1`);
let gif = await fetchgif.json();
console.log(gif)
let imgurl = gif.data[0].images['fixed_height_small'].url;
return {
word: word,
imgurl: imgurl
}
}
As far as my understanding shouldn't
setInterval(wordgif(), 5000);
be called every 5 seconds and generate a new word and image?
How do you setInterval with asynchronus function?
setInterval(wordgif(), 5000);
This code will call wordgif, then pass the result of that function to setInterval. It is equivalent to:
const wordgifResult = wordgif();
setInterval(wordgifResult, 5000);
Since wordgif doesn't return a value, calling setInterval has no real effect.
If you want setInterval to call wordgif, then you need only pass a reference to the function as the argument:
setInterval(wordgif, 5000);
I've updated your code a little bit.
You should clear the interval regularly.
You don't need to return anything from the async function, just do what you want to do inside the function.
Must check if the gif file available before rendering it.
const section = document.getElementById('main');
const text = document.querySelector('.word');
let wordurl = 'https://random-word-api.herokuapp.com/word?number=1&swear=0';
let giphyapikey = '62urPH2PxR2otT2FjFFGNlvpXmnvRVfF';
wordGIF(); // can load first gif before interval
//Setinterval
let interval;
if (interval) clearInterval(interval);
interval = setInterval(wordGIF, 5000);
//Async/await
async function wordGIF() {
let fetchword = await fetch(wordurl);
let word = await fetchword.json();
let fetchgif = await fetch(`https://api.giphy.com/v1/gifs/search?q=${word}&api_key=${giphyapikey}&limit=1`);
let gif = await fetchgif.json();
console.log('Gif available: ' + (gif && Object.keys(gif.data).length > 0));
if (gif && Object.keys(gif.data).length > 0) {
let imgurl = gif.data[0].images['fixed_height_small'].url;
text.innerHTML = word;
section.innerHTML = `<img src=${imgurl}>`;
}
}
.as-console-wrapper {
max-height: 20px !important;
}
<div id="main"></div>
<div class="word"></div>

Categories

Resources