Call javascript from appended content - javascript

I have a problem calling ajax from appended content.
Let's show you my example (An example calling ajax request from appended content, and other call ajax request from none appended content):
https://jsfiddle.net/r7f3zo92/
$(document).ready(function() {
new AjaxUpload("#change", {
action: 'verifImg',
name: 'uploadfile',
onSubmit: function(file, ext) {
if (!(ext && /^(png|jpeg|jpg|bmp|gif)$/.test(ext))) {
return false;
}
},
onComplete: function(file, response) {
$("#imagechange").html(response);
}
});
$(document).on('click', '#test', function(ev) {
$('body').find('#show').remove();
var modal =
'<div class="modal fade" id="show" tabindex="-1" role="dialog" aria-labelledby="show">' +
'<div class="modal-dialog" role="document">' +
'<div class="modal-content">' +
'<div class="modal-header">' +
'<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>' +
'<h4 class="modal-title" id="myModalLabel">Test</strong></h4>' +
'</div>' +
'<div class="modal-body">' +
'<div class="row">' +
'<div class="form-group">' +
'Change Image' +
'<br/>' +
'<div id="imagechange"></div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>';
$('body').append(modal);
$('#show').modal({
show: true
});
return false;
});
});
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="http://www.phpclasses.org/browse/download/1/file/51812/name/ajaxupload.3.5.js"></script>
<strong>Example with appended content:</strong>
<br/>
An example to test
<br/>
<br/>
<strong>Direct example:</strong>
<br/>
<div class="form-group">
Change Image
<br/>
<div id="imagechange"></div>
</div>
In JSFIDDLE it's work fine, but locally no ! strange !
Can you find the problem related to this example ? Thank's

From what I gathered from the ajaxupload.js source code, it seems like it expects one element (or id of element) available on load. On the onload event, it binds a whole lot of stuffs to it, using mousemove, etc. instead of simple click events. it was done for a reason (handle differences in browsers), but it means that:
ajaxupload is only bound to one html element, which must be available on load
it is not possible (or highly complicated) to simulate a click event on the #change button from code, since we don't know exactly what type of event and parameters it requires.
So, in my opinion, you have the following choices:
create a hidden input that you bind to a second AjaxUpload, then move it into your form every time it shows
change the library you use
To be clearer upon the first choice, here is a working jsfiddle. The idea is:
on load, you create a button #choice2 which is hidden
everytime you create your modal, you move (not clone) your button inside the modal
upon modal close, you put back the button inside the body and hide it
your button is ready for the next modal call.
Of course, this approach is a dirty fix and works only when you are sure only one component at a time needs the hidden button.

Related

Cannot Copy Text With Dynamically Created Button

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.

Why is this regex replace function creating line breaks in my html body?

I want to replace hashtags in the body of an html page with a Bootstrap4 Modal.
Sometimes, this function causes line breaks right after the replaced text link. Sometimes it doesn't. I don't understand why.
function replaceBlank() {
document.body.innerHTML = document.body.innerHTML.replace(/#blank/g, '' +
'<a data-target="#blankMod" data-toggle="modal" href="#">' +
'Blank' +
'</a>' +
'<div class="modal fade" id="blankMod">' +
'<div class="modal-dialog">' +
'<div class="modal-content">' +
'<div class="modal-header">' +
'<h4 class="modal-title">' +
'Blank' +
'</h4>' +
'<button type="button" class="close" data-dismiss="modal">' +
'x' +
'</button>' +
'</div>' +
'<div class="modal-body">' +
'Blank Text Body' +
'</div>' +
'</div>' +
'</div>' +
'</div>');
}
Do you ever run it more than once on the same page?
The text you are inserting contains the string you are replacing (the data-target="#blankMod" bit).
You are using the /g flag, so multiple replaces in one step will still work fine; but the second time you call it, it is bound to go a bit crazy.
If that is the problem, you could either stop using that data-target name, or you could capture a bit more context of where "#blank" appears in your document. (lookbehind/lookahead regex asserts are ideal for this, but require the latest versions of JavaScript, so may give browser compatibility issues.)
I discovered that the line breaks only occurred within paragraph <p> tags.
The replacement text was ending the <p> tag, and everything after it was considered a new paragraph.

Fire the same modal with different content at page load

I have a modal, which I feed its content information through variables.
<div id="myModal">
<div id="outer">
<div id="inner">
<div id="top">Headline</div>
<span><img class="btnClose bCancel" src="#"></span>
<div class="modalCnt"></div>
<div class="btn">
<span class="btnText">OK</span>
</div>
</div> <!-- Inner -->
</div> <!-- Outer -->
</div> <!-- Close myModal -->
My problem is that I use the same modal for all different messages that needs to popup. And at page load I have to messages that needs to popup, but only one shows up, which is the last modal that is called. Is there a way to que up the calls so that first modal is shown and then the second one?
$( document ).ready(function() {
modalHead.html("<h3>Headline 1</h3>");
modalContent.html("<p>Content 1</p>");
modal.show();
modalHead.html("<h3>Headline 2</h3>");
modalContent.html("<p>Content 2</p>");
modal.show();
});
Please revisit the following official documentation:
https://v4-alpha.getbootstrap.com/components/modal/#varying-modal-content
It is quite clear and elegant solution.
<script>
$('#myModal').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget)
var header = button.data('header')
var content = button.data('content')
var modal = $(this)
modal.find('.modal-title').text(header)
modal.find('.modal-modalCnt').val(content)
})
</script>
And pass data-header="your_header" data-content="your_content" when you trigger the modal.
Plus add a class tittle to your header. Hope I was clear.
Try:
function new_modal(head, content){
var random = Math.floor(1000 + Math.random() * 9000);
var modal_html = '<div id="myModal_'+ random +'">' +
'<div id="outer">' +
'<div id="inner">' +
'<div id="top">'+head+'</div>' +
'<span><img class="btnClose bCancel" src="#"></span>' +
'<div class="modalCnt">'+content+'</div>' +
'<div class="btn">' +
'<span class="btnText">OK</span>' +
'</div>' +
'</div> <!-- Inner -->' +
'</div> <!-- Outer -->' +
'</div>';
$('body').append(modal_html);
return 'myModal_' + random;
}
$( document ).ready(function() {
modal1 = new_modal("<h3>Headline 1</h3>", "<p>Content 1</p>");
$('#' + modal1).show();
modal2 = new_modal("<h3>Headline 2</h3>", "<p>Content 2</p>");
$('#' + modal2).show();
});
Hope it Helps
what you are doing is calling the same function with 2 diffrent modal data at once . So if we go by the flow of function , it will finish the execution at the last line. So thats why its showing last modal, So what you can do is use if - else condition,
if modal1 {
modalHead.html("<h3>Headline 1</h3>");
modalContent.html("<p>Content 1</p>");
modal.show();
}
else if modal 2 {
modalHead.html("<h3>Headline 2</h3>");
modalContent.html("<p>Content 2</p>");
modal.show();
}
else {
//default part
}

How to auto hide multiple alerts one by one. first in - first out?

I have a notification area in a webpage, which can contain multiple bootstrap alerts.
<div class='notification-area> </div>
I am trying to display multiple alerts as they come, and make the oldest ones auto close after 5 seconds, first one first out.
Here's what I have so far. note: it closes everything all at once.
showNotification(header: string, text: string, alertAttribute: string) {
var notificationBoxID: string = "notificationBox" + $('.notification-area').children().length;
//Appends this html into the notification-area class
$('.notification-area').append(
'<section id="' + notificationBoxID + '" class="alert alert- dismissible" role="alert">' +
'<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>' +
'<p style ="font-weight: bold;" class="notification-message-header"></p>' +
'<p class="notification-message-body"></p>' +
'</section>'
);
// Selects the children of the notificationBoxId section.
var notificationSel = '#' + notificationBoxID;
//set the notification: header, body and css style dynamically
$(notificationSel + ' > .notification-message-header').text(header);
$(notificationSel + ' > .notification-message-body').text(text);
$(notificationSel).addClass(alertAttribute);
// Auto hides alerts, oldest first
$(".alert").show(() => {
setTimeout(() => {
$(".alert").fadeTo(500, 1).slideUp(500, () => {
$(notificationBoxID).hide();
})
}, 5000)
});
Anyone knows how I can approach this issue? I have tried everything. Thanks so much.
toastr has timeouts, so they are handled fifo.
<script src="toastr.js"></script>
var options = {
"preventDuplicates": true,
"timeOut": 5000
};
toastr.options = options;
toastr.warning('this is the message, 'Warning:');

jquery on click event doesn't work when using ajax

I am doing an ajax to pull information from a spreadsheet on my google drive, and then using the following code to display them in HTML:
I have this HTML:
<section class="p-booking" id="booking">
<div class="container">
<div class="row">
<div class="event-box">
<!-- caixas puxados do drive -->
</div>
</div>
</section>
And this JS:
$.getJSON(url, function (data) {
var caixasEvento = [];
caixasEvento.push('<div class="col-md-3">');
caixasEvento.push('<div data-id="' + something + '" class="box">');
caixasEvento.push('<h1 class="day">' + something + '</h1>');
caixasEvento.push('<h1 class="local">' + something + '</h1>');
caixasEvento.push('<img class="local-img" src="' + image + '">');
caixasEvento.push('</div>');
caixasEvento.push('</div>');
$('.event-box').append(caixasEvento.join(''));
});
And then I need an alert every time someone clicks the box:
$('.box').on('click', function() {
alert('test')
});
I'm using a script link tag in the bottom of my html document.
the box is normally appearing with all the drive information.
It does not work. I believe that is a problem related to the ajax, because if I create a div with the 'box' class, the alert works.
I'm guessing this is happening because the box element doesn't exist on the page when you try to setup the listener. Try this:
$('.event-box').on('click', '.box', function() {
// do stuff here
});
Try this:
$('.box').each(function()
{
$(this).click(clickHandler);
});
function clickhandler()
{
alert('test')
}

Categories