Problem pulling json content with variable url - javascript

I hope someone can help me out with this one
My question is why does this code do exactly what I need?
var wfComponent;
fetch("https://nube-components.netlify.app/navbar01.json")
.then((res) => res.text())
.then((data) => (wfComponent = data))
.then(() => console.log(wfComponent));
document.addEventListener("copy", function (e) {
e.clipboardData.setData("application/json", wfComponent);
e.preventDefault();
});
document.getElementById("navbar01").onclick = function () {
document.execCommand("copy");
};
And this one does not do the copy to clipboard part?
$(".button.copy-button").on("click", function () {
let tag = $(this).attr("id");
console.log(tag);
var wfComponent;
fetch("https://nube-components.netlify.app/" + tag + ".json")
.then((res) => res.text())
.then((data) => (wfComponent = data))
.then(() => console.log(wfComponent));
document.addEventListener("copy", function (e) {
e.clipboardData.setData("application/json", wfComponent);
e.preventDefault();
});
document.getElementById(tag).onclick = function () {
document.execCommand("copy");
};
});
Now as you can see what I need is to "automate" that JSON location and target button part where I need each button to target a different URL. So I am now lost in this area where I manage to pull that id and apply it to the URL but the content does not get copied to the clipboard.
I am not a JS expert at all so please feel free to pinpoint anything I might be doing wrong or any ways to do this completely differently
Thanks

Because you use addEventListener inside the other. But either way, there is another (possibly hacky) way to achieve this.
$(".copy-button").on("click", function(e) {
let tag = $(this).attr("id");
fetch("https://nube-components.netlify.app/" + tag + ".json")
.then((res) => res.text())
.then((data) => (wfComponent = data))
.then(() => {
let copyFrom = document.createElement("textarea");
document.body.appendChild(copyFrom);
copyFrom.textContent = wfComponent;
copyFrom.select();
document.execCommand("copy");
copyFrom.remove();
console.log('COPIED!');
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="navbar01" class="copy-button">copy navbar01</button>
<button id="navbar02" class="copy-button">copy navbar02</button>

Related

Cant Copy Text To Clipboard

I am using hadlerbars as the view engine for express and i want the text in the variable code to be copied to the clipboard i tried many solutions . This is my current code
function copyLink() {
var copytext = document.getElementById('alcslink').innerHTML
let code = copytext.split(":- ").pop() /*formatted */
code.select();
code.setSelectionRange(0, 99999); /* For mobile devices */
/* Copy the text inside the text field */
navigator.clipboard.writeText(code.value);
}
when i run this it gives me this error in the web console
TypeError: code.select is not a function
This is how I use it:
Note, it does not work in the snippet engine. You will need to add it to your code.
Sorry.
const writeToClipboard = async (txt) => {
const result = await navigator.permissions.query({ name: "clipboard-write" });
if (result.state == "granted" || result.state == "prompt") {
await navigator.clipboard.writeText(txt);
console.log('Copied to clipboard');
}
};
document.querySelector('button').addEventListener('click', async () => {
const el = document.querySelector('div');
await writeToClipboard(el.innerHTML);
});
<div>copy me</div>
<button>Click</button>

How to benchmark a function in VueJs Store?

I have the following script in my VueJs2 Store Config, and I suspect that the if statement below is causing extra load, even if not triggered, but I'm unsure:
if(response.status === 204) {
addToastMessage(I18n.t('library.withdrawal.errors.already_noted'), 'is-info');
createDiv();
const btn = document.createElement("button");
addBtnAttributes(btn);
btn.addEventListener("click", function()
{
commit('changeBookLoading', true);
fetchNextTicket(response);
commit('changeBookLoading', false);
});
}
Being new to testing in JS in general, I would like to hear suggestions as to the best methods of benchmarking and debugging this further, any tips appreciated.
Full function:
function loadBook(commit, dispatch, method, id=null) {
commit('changeBookLoading', true);
dispatch(method, id)
.then((response) => {
if(response.status === 204) {
addToastMessage(I18n.t('library.withdrawal.errors.already_noted'), 'is-info');
createDiv();
const btn = document.createElement("button");
addBtnAttributes(btn);
btn.addEventListener("click", function()
{
commit('changeBookLoading', true);
fetchNextTicket(response);
commit('changeBookLoading', false);
});
}
const bookId = response.data[0].localBook.id;
if (bookId !== locationBookId()) {
history.pushState({}, `Book ${bookId}`, `/lib/book/${bookId}`);
}
commit('changeCurrentBookId', ticketId);
commit('changeBookEi', null);
commit('changeCurrentBook', null);
})
.catch((err) => {
// show some global error
})
.finally(() => commit('changeLibraryLoading', false));
}
You can measure time of the execution of any block of code with:
console.time('some measure');
......
......
console.timeEnd('some measure');
And you will got console output like: some measure: 0.0126953125 ms
You just need to put you code between time and timeEnd calls.

How can I run javascript file after dom manipulation made in another js file?

When I run my rails application and enter likeButton into the console it gives me Uncaught ReferenceError: likeButton is not defined
at :1:1
(anonymous) # VM1591:1
I tried moving the script in html to head and body. I am currently trying to use DOMContentLoaded but it seems I'm missing something. My overall goal is to change the color of the button once pressed and also keep the color after page refresh. I am using sessionStorage for this process. I just want to make sure that likeButton variable is declared after html is loaded. If its possible to done in javascript only.
//first js file
const BASE_URL = "http://localhost:3000"
const GPUS_URL = `${BASE_URL}/gpus`
const USERS_URL = `${BASE_URL}/users`
const gpuCollection = document.querySelector('#gpu-collection')
let wish = sessionStorage.getItem('wish');
class Gpu {
constructor(gpuAttributes) {
this.title = gpuAttributes.title;
this.price = gpuAttributes.price;
this.features = gpuAttributes.features;
this.link = gpuAttributes.link;
this.image = gpuAttributes.image;
this.id = gpuAttributes.id;
}
render() {
let div = document.createElement('div');
div.classList.add('card');
let h = document.createElement('h2');
let t = document.createTextNode(`${this.title} ($${this.price})`);
h.appendChild(t);
div.appendChild(h);
let h1 = document.createElement('h1');
h1.classList.add('gpu-cat');
h1.innerHTML = `${this.features}`;
div.appendChild(h1);
let button = document.createElement('button');
button.classList.add('list_btn');
button.innerHTML = '♡';
div.appendChild(button);
let a = document.createElement('a');
let img = document.createElement('img');
a.href = `${this.link}`;
a.target = '_blank';
img.src = `${this.image}`;
img.classList.add('gpu-image');
a.appendChild(img);
div.appendChild(a);
gpuCollection.appendChild(div);
}
}
//second js file
document.addEventListener("DOMContentLoaded", function (){
let likeButton;
SignUp();
logInUser();
logOutUser();
function putGpusOnDom(gpuArray){
gpuArray.forEach(gpu => {
let newGpu = new Gpu(gpu)
newGpu.render()
});
likeButton = document.querySelector("button");
}
function fetchGpus(){
fetch(GPUS_URL)
.then(res => res.json())
.then(gpus => putGpusOnDom(gpus))
}
const enableWish = () => {
console.log(likeButton)
sessionStorage.setItem('wish', 'red')
}
gpuCollection.addEventListener('click', function (){
wish = sessionStorage.getItem('wish');
if(wish !== 'red'){
enableWish();
}else{
disableWish();
}
});
})
//html file
...
<body>
<div id = "gpu-collection"></div>
<script type="text/javascript" src="src/Gpu.js"></script>
<script type="text/javascript" src="src/index.js" ></script>
</body>
</html>
As I mentioned in a comment the like button is not available on DOMContentLoaded if it is added dynamically. You need to wait until the button has been placed in the DOM
Use something like the following, I'm making some guesses here as there are some gaps in your code
document.addEventListener("DOMContentLoaded", function (){
//document.querySelector("button"); not yet available
//NOTE: The likeButton variable will ONLY be in scope INSIDE the event listener function
// You will not be able to access directly in the console.
let likeButton;
SignUp();
logInUser();
logOutUser();
function putGpusOnDom(gpuArray){
gpuArray.forEach(gpu => {
let newGpu = new Gpu(gpu)
newGpu.render()
});
//Now you have rendered the button it is available
//CAUTION: querySelector("button") will grab the first button on the page
// and ONLY the first button
likeButton = document.querySelector("button");
//Log like button to console while it is still in scope.
console.log(likeButton);
}
function fetchGpus(){
fetch(GPUS_URL)
.then(res => res.json())
.then(gpus => putGpusOnDom(gpus))
}
const enableWish = () => {
console.log(likeButton)
sessionStorage.setItem('wish', 'red')
}
})

Event delegation not working on dynamic buttons

No matter what I try, the .onclick or addEventListener 'click' will not work on my dynamically created buttons and I can't figure out why. As I was looking for solutions, I came across Event Delegation and I looked through 3 different websites and looked at the examples. I was sure this was going to solve my problem and I tried to mimic the examples but still it isn't working. I posted a question on here earlier but it was immediately removed because apparently it was too similar to another question (that was 12 years old!) but when I looked at that question they were using jQuery. I'm still a beginner in JS so I would prefer to understand how to resolve this in plain JS and I'm hoping this won't be removed.
This is my code:
document.addEventListener('DOMContentLoaded', function() {
userData();
document.querySelector('.list-group').addEventListener('click', function(e) {
if(e.target && e.target.nodeName == "BUTTON"){
console.log(e.target.id);
}
});
})
function userData() {
fetch("https://jsonplaceholder.typicode.com/users")
.then(response => response.json())
.then(users => {
const h6 = document.createElement("h6");
h6.innerText = "List of Users";
const userList = document.createElement("div");
userList.className = "list-group";
users.forEach(function(user) {
const userButton = document.createElement("button");
userButton.className = "list-group-item list-group-item-action";
userButton.id = `${user.id}`;
userButton.innerHTML = `
<strong>${user.name}</strong><br>
${user.email}<br>
${user.address.city}<br>
`;
userList.appendChild(userButton);
});
const container = document.querySelector('#response');
container.appendChild(h6);
container.insertBefore(userList, h6.nextSibling);
});
}
function userSelect(user_id) {
fetch(`https://jsonplaceholder.typicode.com/users/${user_id}`)
.then(response => response.json())
.then(user => {
console.log(user);
});
}
What I have now is a list of users and ultimately I want to be able to click on a user and bring up the full details of that user. At first I was trying to use the onclick function to redirect to the userSelect function but when that failed I looked around and found Event Delegation and still no luck. I tried to move the document.querySelector('.list-group) section down at the end of the userData function and still no luck. When I click on a button nothing shows up in console, if I use the userSelect function directly in console a user object appears. I'm at a real loss on how to get this to work. Please help!
Since function userData is making asynchronous call, the issue seems to be that you are adding the click event handler before the element with class '.list-group' got created.
You should use something like this to add click handler
document.addEventListener('DOMContentLoaded', function () {
userData().then(response => {
document.querySelector('.list-group').addEventListener('click', function (e) {
if (e.target && e.target.nodeName == "BUTTON") {
console.log(e.target.id);
}
})
});
})
Try below snippet:
document.addEventListener('DOMContentLoaded', function() {
userData().then(response => {
document.querySelector('.list-group').addEventListener('click', function(e) {
if (e.target && e.target.nodeName == "BUTTON") {
console.log(e.target.id);
}
})
});
})
function userData() {
return fetch("https://jsonplaceholder.typicode.com/users")
.then(response => response.json())
.then(users => {
const h6 = document.createElement("h6");
h6.innerText = "List of Users";
const userList = document.createElement("div");
userList.className = "list-group";
users.forEach(function(user) {
const userButton = document.createElement("button");
userButton.className = "list-group-item list-group-item-action";
userButton.id = `${user.id}`;
userButton.innerHTML = `
<strong>${user.name}</strong><br>
${user.email}<br>
${user.address.city}<br>
`;
userList.appendChild(userButton);
});
const container = document.querySelector('#response');
container.appendChild(h6);
container.insertBefore(userList, h6.nextSibling);
});
}
<div id="response">
</div>
or you can move the addEventListener code to end of userData

Why my IPC communication doesn't work properly?

This's a simple video duration check program built with Electron. However, it doesn't work as expected; I also tried to use Electron IPC communication in others projects, but always fails.
I can upload a video successfully and submit it, after that nothings happens, any errors or advices. Debugger shows nothing too. I built a new project from zero and have same issue. Path value is also not showed on console
main.js:
const electron = require('electron'),
app = electron.app,
BrowserWindow = electron.BrowserWindow
const ffmpeg = require('fluent-ffmpeg')
const ipc = require('electron').ipcMain
let mainWindow
app.on('ready', () => {
mainWindow = new BrowserWindow({})
mainWindow.loadFile('./index.html')
})
ipc.on('video:submit', (event, path) => {
ffmpeg.ffprobe(path, (metadata) => {
event.returnValue = metadata.format.duration
})
})
index.html:
<html>
<head>
</head>
<body>
<form id="form">
<h1>Video Info</h1>
<div>
<label>Select a video</label>
<input type="file" accept="video/*" id="input">
</div>
<button type="submit" id="sb">Get info</button>
<div id="result"></div>
</form>
</body>
<script>
require('./renderer.js')
</script>
</html>
renderer.js:
const ipc = require('electron').ipcRenderer,
form = document.querySelector('#form')
let result = document.querySelector('#result')
console.log(path)
form.addEventListener('submit', () => {
const path = document.querySelector('#input').files[0].path
let reply = ipc.sendSync('video:submit', path)
result.innerHTML = 'Video is' + reply + 'seconds!'
})
EDIT
I made some changes on main and renderer to use asynchronous send and reply. I don't get what I want, but after submit some content, it's name is replaced with "No file chosen". Path value stills not printed.
changes on main.js:
ipc.on('video:submit', (event, path) => {
ffmpeg.ffprobe(path, (metadata) => {
let duration = metadata.format.duration
event.reply('duration', duration)
})
})
changes on renderer.js:
form.addEventListener('submit', () => {
const path = document.querySelector('#input').files[0].path
ipc.on('duration', (event, duration) => {
console.log(duration)
})
ipc.send('video:submit', path)
result.innerHTML = 'Video is' + duration + 'seconds!'
})
The code looks good but I guess the problem lies in your form submission. The page should be reloading on submit and it does not reach the IPC send
call. Try preventing default action for the form.
form.addEventListener('submit', (e) => {
e.preventDefault()
const path = document.querySelector('#input').files[0].path
ipc.on('duration', (event, duration) => {
console.log(duration)
})
ipc.send('video:submit', path)
result.innerHTML = 'Video is' + duration + 'seconds!'
})
Solved! There were 3 main errors so I don't know what exactly happened. But here are they:
1 - ipc functions were made wrong way. This is the right one (asynchronous reply):
renderer.js:
ipc.on('duration', (event, duration) => {
result.innerHTML = `Video is ${duration} seconds!`
})
ipc.send('video:submit', path)
main.js:
ipc.on('video:submit', (event, path) => {
ffmpeg.ffprobe(path, (err, metadata) => {
let duration = metadata.format.duration
console.log(duration)
event.reply('duration', duration)
})
})
2 - DOM wasn't getting submit button or event so "addEventListiner" was getting null... I changed submit button to input button with same id then cheanged submit event to simple click event. I query selected the input button rather the form at all. That's what I get finally:
renderer.js:
const ipc = require('electron').ipcRenderer,
suBtn = document.querySelector('input#sb')
let result = document.querySelector('div#result')
suBtn.addEventListener('click', (event) => {
event.preventDefault()
const path = document.querySelector('input#file').files[0].path
ipc.on('duration', (event, duration) => {
result.innerHTML = `Video is ${duration} seconds!`
})
ipc.send('video:submit', path)
})
3 - On ffprobe process on main.js, I was calling method with wrong params. It's necessary to pass the err param first, then data param, this way:
main.js:
ffmpeg.ffprobe(path, (err, metadata) => {
let duration = metadata.format.duration
console.log(duration)
event.reply('duration', duration)
})

Categories