Cannot Copy Text With Dynamically Created Button - javascript

I have the following function for copying a string of text:
function copyText(str) {
console.log(str);
let tmp = $('<input type="text">').appendTo(document.body);
tmp.val(str.toString() );
tmp.select();
document.execCommand('copy');
tmp.remove();
}
This function works fine, both when called from the console and when called from a button press.
I have a function that copies a color:
function copyColor(elm) {
let hex = $(elm.parentElement).find('span').html();
console.log('copyText("' + hex + '")' );
copyText(hex);
}
This function is called when a button is pressed. The button passes itself as the parameter. I am dynamically creating the buttons (each one represents a new "color item"). Here is the HTML that is dynamically inserted with jQuery:
'<button class="btn copy-btn no-color" title="Copy" data-toggle="popover" onclick="copyColor(this);"><i class="fas fa-copy"></i></button>'
The whole thing is:
$('#' + mode + '-modal .modal-body').prepend(
'<div class="' + mode + '-item color-item">'
+ '<button class="btn open-btn no-color" title="Open Color" data-toggle="popover" onclick="openColor(this, \'' + mode + '\');"><i class="fas fa-external-link-alt"></i></button>'
+ '<input class="form-control color-name" type="text" placeholder="Name your color (optional)" value="' + name + '">'
+ '<br class="mobile-only">'
+ '<div class="color-preview" style="background-color:' + hex + ';"></div>'
+ '<span>' + hex + '</span>'
+ '<button class="btn copy-btn no-color" title="Copy" data-toggle="popover" onclick="copyColor(this);"><i class="fas fa-copy"></i></button>'
+ '<button class="btn link-btn no-color" title="Get Link" data-toggle="popover" onclick="copyColorLink(this);"><i class="fas fa-link"></i></button>'
+ '<button class="btn delete-btn no-color" title="Remove" data-toggle="popover" onclick="removeColor(this);"><i class="fas fa-trash"></i></button>'
+ '<i class="fas fa-arrows-alt" style="cursor:move;" title="Drag to Change Order" data-toggle="popover"></i>'
// + '<button onclick="copyText(\'hi\')">hi</button>'
+ '</div>'
);
where mode, hex, and name are all parameters in this function.
Every time I click to copy the color, it calls the copyColor() function, gets the correct string, calls the copyText() function, gets the correct string, and runs with no errors, however it fails to edit my clipboard. When calling this function from the console, with the exact same string, it works, and when creating a static button to copy the color, for example:
<button onclick="copyText('hi')">hi</button>
then it works fine as well. I have also tried dynamically adding one of these buttons:
+ '<button onclick="copyText(\'hi\')">hi</button>' to my code that injects HTML, and it does not work.
Other dynamically created buttons seen above also call functions and pass themselves as a parameter and work fine, for example the delete button, calling the removeColor() function with this as the parameter.
Lastly, I've tried giving the buttons dynamic IDs, by way of:
'<button id="copy-btn-'+ nextID +'" etc...
Where nextID is a value I increment, and I add the onclick listener for that specific button immedatly after creating it:
$('#copy-btn-'+nextID).click(function() {
copyText('hello');
});
nextID++;
I've tried creating a new copy function that only takes in the string, and instead of passing an element I just pass the string to be copied:
function copyColorNew(hex) {
console.log('copyText("' + hex + '")' );
copyText(hex);
}
and here is the relevant part of the inserted button code:
onclick="copyColorNew(\''+hex+'\');">
and it calls the function correctly, passes the correct arguments, and fails to copy the string.
I don't have any duplicate function names, all files are included correctly, I've hard refreshed the page, all variables are in their respective scope, and I've never got any errors. I've also omitted dozens of other rather inconclusive experiments I've done.
I am completely out of ideas, and I've spent several hours a day for several days on this problem. I am well aware how to copy a string in javascript, I'm well aware of how to create a button and append it dynamically, and I'm well aware of how to give the button an onclick listener that passes itself as a parameter. I've had no problems with these things in the past and I still do not everywhere else in this code as I've detailed above.
The only thing I can think of is it's a security problem to allow dynamically created DOM elements to call functions that access the clipboard, but I'm not even pasting the data.
Once again, buttons in the static HTML page can correctly copy 'hello world', dynamically inserted ones cannot copy 'hello world'.

By using the clipboard API (suggested by u/elmstfreddie on Reddit):
navigator.clipboard.writeText(hex);
I got it to work. I replaced copyText(hex); with navigator.clipboard.writeText(hex); in my copyColor() function.
Here is the link to the docs.

Related

How to pass variable into a onclick function

I am wanting to try and pass record.ItemID to my onclick = buy() function. But I am getting errors like "Uncaught SyntaxError: Unexpected end of input"
I have tried \"record.ItemID \" but that of course just passes the literal string of result.name
I have also tried (\'' + record.ItemID + '\') but get the same Syntax error
function showShop(items) {
let tableContent = "<tr class='orderTitle'><td =imgTable></td><td id = contentTable ></td></tr>\n";
let odd = true;
const addRecord = (record) => {
tableContent += odd ? "<tr class='orderOdd'>" : "<tr class='orderEven'>";
odd = !odd;
tableContent += "<td>" + "<img id = image src="+ "http://redsox.uoa.auckland.ac.nz/ms/MuseumService.svc/shopimg?id=" + record.ItemId + " />" + "</td><td id = content>" + record.Description + "<td><button onclick='buy("+ record.ItemId +")'/> Buy </button></td>";
}
items.forEach(addRecord)
document.getElementById("shop").innerHTML = tableContent;
}
function buy(item){
window.open('http://redsox.uoa.auckland.ac.nz/mss/Service.svc/buy?id='+ item,'_self');
}
I'm not sure if this will solve your problem but it looks like you're mixing up 's and "s.
onclick='buy('record.ItemId')'
You are terminating the onclick attribute right after buy(.
You may need to do something like:
onclick='buy(" + record.ItemId + ")'
Generally speaking though, if you have to build up HTML in strings, you are better off string interpolation. It makes it easier to read and is less prone to these types of issues.
Example:
const html = `<button onclick="buy(${record.ItemId})">Click</button>`;
It looks like you're trying to build up some HTML content to put into a table, and you want some behaviour attached to a button inside the table so that it opens a new window when you click on it.
There are a number of different approaches to what you're trying to do which would be safer in production code, so while you've got some answers to your specific question, please consider these alternative approaches which are more idiomatic:
You could use a link (<a>) instead of a button, and use CSS to make the link look like a button. This avoids needing a click handler at all.
You could use data attributes to store the record in a safe way, then access it from the click event, e.g. e.target.dataset.recordId.
You could use jQuery or a similar toolkit to create the button, then attach a function to the button as a click handler.
When you create HTML directly like you are doing in your question, you're opening your code up to code injection, where someone malicious could craft data that could steal private information from users of your site. It's much safer to use a library to construct your HTML directly rather than building it up in strings.
Really you're much better off separating out your inline JS and using event listeners to target classes on your elements.
Here's a quick example to show you how you might achieve that:
const records = [{ itemId: 1 }, { itemId: 2 }, { itemId: 3 }];
const imgRoot = 'https://dummyimage.com/30x30/676767/fff.png?id=';
// `map` iterates over the array and produces one element of HTML per record
// We use a class on the button to identify it, and a data attribute
// button to hold the itemId
const html = records.map(({ itemId }) => {
return `
<div class="itemWrapper">
<img class="item" src="${imgRoot}${itemId}" />
<button data-itemid="${itemId}" class="buyRecord">Buy record</button>
</div>
`;
});
document.querySelector('.root').innerHTML = html.join('');
// We grab the buttons and iterate over them attaching
// event listeners that call `handleBuy` when the button is clicked
const buyButtons = document.querySelectorAll('.buyRecord');
buyButtons.forEach(button => button.addEventListener('click', handleBuy, false));
function handleBuy(e) {
// Destructure the itemid from the dataset of the button
// click event
const { target: { dataset: { itemid } } } = e;
console.log(itemid);
}
<div class="root" />
Documentation
map
Data attributes
Template literals
Destructuring assignment
The General format of onclick is
onclick="function_name(variable)"
For this case you can do something like this:
tableContent += '<td>' + '<img id = image src="http://redsox.uoa.auckland.ac.nz/ms/MuseumService.svc/shopimg?id=' + record.ItemId + '" /></td><td id="content">' + record.Description + '<td><button onclick="buy('+record.ItemId+')"> Buy </button></td>';

jQuery Datepicker doesn't overwrite value in dynamically created input, page refresh needed

EDIT1:
So I did managed to fix this problem. But I'm not sure how.
I've been using two identical forms with different IDs for different
reasons (Add and Edit forms). In those forms I had inputs with IDs.
But for both forms I've been using the same ID for the inputs in them.
So I change those IDs to classes (how it should be). I think this was
the reason for the bug.
The second thing I've changed was removing
the first form in a moment I would click on the second form (Edit
form/button) because It was making a trouble, trouble I didn't
addresed in here and I don't think It has anything to do with my
initial problem. Just writing everything I did in any case.
I'm having a problem with jQuery Datepicker and Timepicker. I'll try to describe my situation.
I have dynamically created html for my local storage values (imagine squares with it's own data in it.)
My problem... If I simply load these squares and I want to change something, by clicking on edit button, It will create a form with pre-written values in them, by clicking on one of these inputs, a calendar shows up. And then after clicking on some date, the pre-written value changes with value of a date I've clicked on. Same for Timepicker. But! There is a problem.
If I want to create new squares with new data ( by dynamically creating form with inputs, then the data is saved to local storage) and then (without refreshing the page) clicking on edit button, bringing same old form (as described above) and clicking on some of the inputs, calendar shows up, but after clicking on some date, the value of the input doesn't change. Same with Timepicker, doesn't overwrite the pre-witten value.
But if I refresh the page and want to edit something (without creating new squares/data), Datepicker change the value without problem.
Can you help me please? I'll try to answer any question if needed.
Here is a function that show everything saved in local storage.
function fetchBookmarks() {
var bookmarks = JSON.parse(localStorage.getItem("bookmarks"));
bookmarks.sort(function compare(a, b) {
var dateA = new Date(a.date);
var dateB = new Date(b.date);
return dateB - dateA;
});
var results = document.getElementById("results");
results.innerHTML = "";
for (var i = 0; i < bookmarks.length; i++) {
var date = bookmarks[i].date;
var distance = bookmarks[i].distance;
var time = bookmarks[i].time;
results.innerHTML += '<div class="bookmarks shadow p-3 m-2 bg-light rounded">' +
'<div class="row">' +
'<div class="col">' +
'<h3>Date: </h3>' +
'<h3>Distance: </h3>' +
'<h3>Time: </h3>' +
'</h3><input onclick="editBookmarks(\'' + time + '\')" class="btn btn-outline-primary mr-1 btn-lg" id="edit" type="button" value="Edit"><input onclick="deleteBookmarks(\'' + time + '\')" class="btn btn-outline-danger btn-lg" id="deleteBookmarks" type="button" value="Delete">' +
'</div>' +
'<div class="col">' +
'<h3 class="font-weight-bold">' + date + '</h3>' +
'<h3 class="font-weight-bold">' + distance + '</h3>' +
'<h3 class="font-weight-bold">' + time + '</h3>'
'</div>' +
'</div>' +
'</div>';
};
};
And here is function after clicking on edit button...
function editBookmarks(time) {
var bookmarks = JSON.parse(localStorage.getItem("bookmarks"));
for (var i = 0; i < bookmarks.length; i++) {
if (bookmarks[i].time == time) {
$(".bookmarks").hide();
results.innerHTML += '<form class="bookmarks shadow p-3 m-2 bg-light rounded" id="editForm">' +
'<h4>Date: </h4><input class="form-control form-control-lg" id="date" placeholder="Select" value="' + bookmarks[i].date + '" type=""><br>' +
'<h4>Distance: </h4><input class="form-control form-control-lg" id="distance" placeholder="In miles" value="' + bookmarks[i].distance + '" type="text"><br>' +
'<h4>Time: </h4><input class="form-control form-control-lg" id="time" placeholder="Select" value="' + bookmarks[i].time + '" type=""><br>' +
'<input class="btn btn-success btn-lg" type="submit" value="Submit">' +
'</form>';
/* $('#date').datepicker()
$('#time').timepicker({
timeFormat: "H:mm",
hourMin: 0,
hourMax: 4
}); */
bookmarks.splice(i, 1);
};
};
$("#editForm").on("submit", function (e) {
var date = $("#date").val();
var distance = $("#distance").val();
var time = $("#time").val();
if (!distance.length || !date.length || !time.length) {
alert("Something missing!")
} else {
var bookmark = {
date: date,
distance: distance,
time: time
};
bookmarks.push(bookmark);
localStorage.setItem("bookmarks", JSON.stringify(bookmarks));
fetchBookmarks();
$("#editForm").hide();
};
e.preventDefault();
});
$("#search").hide();
};
And here is Datepicker with Timepicker
$('body').on('focus', "#date", function () {
$(this).datepicker();
});
$('body').on('focus', "#time", function () {
$(this).timepicker({
timeFormat: "H:mm",
hourMin: 0,
hourMax: 4
});
});
I know that this is quite much to ask and I'm having a problem with articulating. I'm just lost in this.
I'm thankful for any help.
Here's a link for GitHub file, I think It's better than posting the code here. My whole problem is at the bottom of the file, if you're interested.
https://github.com/ovy1448/MyRun/blob/master/js/main.js
Thanks again.
As per my understanding, since you are using onfocus event to attach datepicker/timepicker, all the event of datepicker/timepicker is not getting attached to the field. I faced similar problem 2-3 years back. What I did is that I added a function for the datepicker onSelect event which updates the field value. You can try this(as below) and let me know if it works
$('body').on('focus', "#date", function () {
$(this).datepicker({onSelect: function(dateStr){
$('body').('#date').val(dateStr);
}});
});
$('body').on('focus', "#time", function () {
$(this).timepicker({
timeFormat: "H:mm",
hourMin: 0,
hourMax: 4,
onSelect: function(timeStr){
$('body').('#time').val(timeStr);
}
});
});
So I did managed to fix this problem. But I'm not sure how. I've been using two identical forms with different IDs for different reasons (Add and Edit forms). In those forms I had inputs with IDs. But for both forms I've been using the same ID for the inputs in them. So I change those IDs to classes (how it should be). I think this was the reason for the bug.
The second thing I've changed was removing the first form in a moment I would click on the second form (Edit form/button) because It was making a trouble, trouble I didn't addresed in here and I don't think It has anything to do with my initial problem. Just writing everything I did in any case.

How to get parent element's ID?

So I got into this tricky situation. I have a variable which present table data:
row += '<td>' + c + '<button class="btn btn-success" id="' + callId + ' " onclick="handleCall()">Call</button>' + '<button class="btn btn-danger" id="' + hangupId + ' " onclick="handleHangUp()">Hangup</button>' + '</td>' ;
Latter on I will append that into my table. Now, when I click Call button, I want to get the button's Id. I have tried this way:
function handleClick() {
console.log(this);
}
but it refer to window object. Can anybody show me the way to achieve my goal? Thanks
Simply pass the elements ID as a parameter to keep it simple,
Change,
onclick="handleCall()"
to,
onclick="handleCall(this.id)"
this referring to the button in question the user is pressing.
then,
function handleClick(id) {
console.log(id);
}
Finally don't use inline event handlers as they are a pain to work with in the long run, make use of the addEventListener method.
row += '<td>' + c + '<button class="btn btn-success" id="' + callId + ' " onclick="handleCall(this)">Call</button>' + '<button class="btn btn-danger" id="' + hangupId + ' " onclick="handleHangUp()">Hangup</button>' + '</td>' ;
function handleClick(element) {
console.log(element);
//here you will have all element properties
}
There are two ways you can do this, you can do it via jQuery by using attr or if you are wanting to stay vanilla Javascript then you can use .id.
For jQuery please see code below:
console.log(jQuery('element').attr('id'));
For Javascript please see code below:
console.log(element.id);

Set value of button clicked as a Javascript variable - without using an ID/Name

Is it possible for me to carry the value of a button over to the function that that the button executes?
Simple concept, how would I get the value "5" to be carried over to my function where I can define it as a variable?
<button onclick="functionHere()" value="5">Delete</button>
Code actually looks more like:
<button onclick="functionHere()" value="' + aData[5] + '">' + 'Delete</button>
In your example you can reference the button element using this.
HTML:
<button onclick="functionHere(this)" value="' + aData[5] + '">' + 'Delete</button>
JS:
function functionHere (btn) {
var buttonValue = btn.value;
}
this references the context of the function. So in this case since the function was called by setting it as the onclick of the button, the functions context is the button element.
EDIT: I am mistaken actually this doesn't seem to be set automatically when used how you use it. Code updated. Here is a fiddle:
http://jsfiddle.net/9nv4sz6L/
You can do it like this.
<input type="button" value='Hello World' onclick='ShowValue(this)'/>
<script>
function ShowValue(btn){
alert(btn.value);
}
</script>

Uncaught ReferenceError: is not defined onclick when using character strings

I am trying to pass a variable to the onClick function using a previously stored value. I have a database setup that searches for store locations when provided with a ZIP code. For example, the following link is generated using an ajax call after a user searches for a Zip Code. The returned value "WAFHOH3" is the ID that is associated with that particular store:
Generated Link:
<input type="button" onclick="myfunction(WAFHOH1);" value="This Is My Store" data-store-code="WAFHOH3">
Based on this code:
<div class="col-sm-3"><input type="button" onclick="myfunction(' + item.store_code + ');" value="This Is My Store" data-store-code="' + item.store_code + '"></div>
My problem is that if anything other than a number is returned I get a "Uncaught ReferenceError: WAFHOH3 is not defined" console error. When a number is passed like the example below, everything works fine and I get no errors and the application continues to work as expected.
For example (This Works):
Ive tried manually changing the character string to numbers only to isolate any database related issues. My only guess is that there is something in my code that is maybe attempting to verify the input as number.
The full code is below for the ajax call.
Full Code:
function myFunction() {
var searchValue = $('#foobar').val();
if (searchValue.length > 3) {
var acs_action = 'searchCction';
$.ajax({
async: false,
url: mysearchurl.url+'?action='+acs_action+'&term=' + searchValue,
type: 'POST',
data: {
name: searchValue
},
success: function (results) {
var data = $.parseJSON(results);
$('#resContainer').hide();
var html = '';
if (data.length > 0) {
html += '<br/><br/><ul>';
for (var i = 0; i < data.length; i++) {
var item = data[i];
html += '<li>';
html += '<div class="row myclass">';
html += '<div class="col-sm-9">';
html += ' <h3>' + item.label + '</h3>' ;
html += ' <span>' + item.desc + '</span>';
html += '</div>'
html += ' <div class="col-sm-3"><input type="button" onclick="dofunction(' + item.store_code + ');" value="This Is My Store" data-store-code="' + item.store_code + '"></div>';
html += '</div>';
html += '</li>';
}
html += '</ul><br/><br/><p>This is an example message please email us at admin#admin.com for assistance.';
}
else {
html += '<br/><br/><p>This is an example message, email us at admin#admin.com for assistance.';
}
$('#foo').html(html);
$('#foo').show();
$('.foobar').hide();
}
});
} else {
$('#foo').hide();
}
}
You need to wrap the input item.store_code with quotation marks; otherwise, it tries to treat it as a variable, not a string:
html += '<div class="col-sm-3"><input type="button" onclick="noActivationCodeRegistration(\'' + item.store_code + '\');" value="This Is My Store" data-store-code="' + item.store_code + '"></div>';
Ideally, you would attach a click handler after giving the buttons a class (such as register):
html += '<div class="col-sm-3"><input type="button" class="register" value="This Is My Store" data-store-code="' + item.store_code + '"></div>';
// Later
$('.register').on('click', function() {
var storeCode = $(this).data('storeCode');
noActivationCodeRegistration(storeCode);
});
I may be late, and maybe its an absolute mistake of me, but, i have to add my answer here because i just solved exactly the same situation in about three minutes ago .
I just solved this using the most simple sollution, and the error "Uncaught ReferenceError" from the console is solved, also i have my alert(); passing the variable as i needed.
I also need to include that i did not aproove the sollution gave, about "not using" the alert function, once i searched for the sollution, not for another method for that .
So, as i am using php, and the document is html, i thinked about the apostrophe charactere to the variable, after i had been spectating the element using chrome, first moving the function alert to the parent and child elements, that not solved .
After, also in the specting element, inside chrome F12 i tryed changing the function, including '' (that i passed in php code) into variable inside the alert function as: onclick="alert(variable);" to onclick="alert('variable');" and my alert had worked .
Ok. So, i try everything to insert '' 2 single quotes '' to my variable in php, that seems impossible, even if i change all my code to " and use ' or the oposite .
Then, i decided to try the most obvious and old school method, that is about charactere representation, and i cfound that ' (single quote) is represented by ' in php. Everything inside ->> ' <<-
My php code is like this : onclick="alert(&#039'.$variable.'&#039);"
It will work! (with no Vue), ok ? :)

Categories