I am trying to add a click event to an element that is added dynamically to the page after document load, but it isn't working, though this seems to be a well-known problem with a clear answer. This is my code:
$('body').on('click', "#clickme", function() {
alert('clicked!', $('#cartodb_id').text());
});
The complicating factor may be that the element is inside a Mustache template that itself gets rendered dynamically into the page, by CartoDB.js:
<div id="map"></div>
<script type="infowindow/html" id="infowindow_template">
<div class="cartodb-popup">
x
<div class="cartodb-popup-content-wrapper">
<div class="cartodb-popup-content">
<h4>cartodb_id: </h4>
<p id="cartodb_id">{{content.data.cartodb_id}}</p>
<input type="submit" id="clickme" value="clickme" />
</div>
</div>
<div class="cartodb-popup-tip-container"></div>
</div>
</script>
Should this affect my ability to add an event dynamically?
Link to a JSFiddle showing the problem in full: http://jsfiddle.net/8o12v2xs/9/
Not too familiar with Carto myself, but it seems to work fine once you wait for the element to exist. http://jsfiddle.net/8o12v2xs/10/
// register events once it's available
sublayer.on('featureClick', function(e, latlng, pos, data) {
$('#clickme').on('click', function() {
alert('clicked!', $('#cartodb_id').text());
})
});
Put that underneath the initialization like in the above Fiddle.
Related
Im creating a simple JS game, which will run in the browser and will pull the files directly from the pc. Because of this needed to make a workaround the "Cross-origin" error, which went smoothly, I put all the HTML within a JS and loaded the JS from the tag in the index.html. Everything was going smoothly so far.
You click "press any key to continue" -> but then next you click "New Game" and you get event listener error "can't set property of null". Which i don't understand how it happens, because the element is already in the "DOM" , the css could pick it up, but the event listener could not? So i tried moving all scripts on top, rearranging stuff, nothing worked. Pre-loading all HTML into the index.html, without executing it will definitely work, but how can i achieve this exactly? My Configuration atm is:
index.html (root folder)
/components/main_menu.js
/components/character_creation.js
function MainMenu()
{/*
<div id="mm_wrapper_grid">
<div id="mm_subgrid1">
</div>
<div id="mm_subgrid2">
<div id="mm_subgrid2_image"></div>
<div id="mm_new_game"><p id="mm_new_game_p" class="grow">New Game<p></div>
<div id="mm_load_game"><p id="mm_load_game_p" class="grow">Load Game</p></div>
<div id="mm_options"><p id="mm_options_p" class="grow">Options</p></div>
<div id="mm_credits"><p id="mm_credits_p" class="grow">Credits</p></div>
</div>
</div>
*/}
function CharacterCreation()
{/*
<div> Character Creation test
</div>
*/}
<div id ="game">
<div id="loading_screen">Press Any Key To Continue</div>
</div>
<script type="text/javascript">
document.getElementById("loading_screen").addEventListener("click", function() {callback("game", MainMenu)});
document.getElementById("mm_new_game_p").addEventListener("click", function() {callback("game", CharacterCreation)});
function callback(arg1, func)
{
var html = func.toString();
var htmlstart = html.indexOf('/*');
var htmlend = html.lastIndexOf('*/');
var html = html.substr(htmlstart+2, htmlend-htmlstart-2);
document.getElementById(arg1).innerHTML = html;
}
</script>
You have the problem because you are trying to add the second listener for getElementById("mm_new_game_p") when this element doesn't exist on the page. I suggest you to add the follwing line of code to make sure, that it's true:
<script type="text/javascript">
document.getElementById("loading_screen").addEventListener("click", function() {callback("game", MainMenu)});
console.log('#mm_new_game_p', document.getElementById("mm_new_game_p"));
document.getElementById("mm_new_game_p").addEventListener("click", function() {callback("game", CharacterCreation)});
...
You have to add this listener after this element will be created (after calling of MainMenu() function).
To tell the truth, I can see such storing of html templates in js functions for the first time. It's hard to support your code and I've modified it a little bit below. This is not the best way to implement it, but my goal is show you a solution based on your code. What you can see here:
all the templates for pages are in html (not in JS);
you can add listeners from html code using HTML attribute onclick - and in this case you can be sure, that element exists on the page.
If you want to add listeners from JS, than you have to create own functions for each pages which you have and after HTML template of a page will be added to #game container you will need to create event listeners for the buttons which are on the created page.
openPage("game", "loading_screen");
function openPage(parentDOMElementId, name) {
console.log('openPage:', name);
var pageHtml = document.getElementById("page_" + name).outerHTML;
document.getElementById(parentDOMElementId).innerHTML = pageHtml;
}
<div id="game"></div>
<div class="templates" style="visibility: hidden;">
<div id="page_loading_screen" onclick="openPage('game', 'main_menu')">
Press Any Key To Continue
</div>
<div id="page_main_menu">
<div id="mm_subgrid1">
</div>
<div id="mm_subgrid2">
<div id="mm_subgrid2_image"></div>
<div id="mm_new_game">
<p id="mm_new_game_p" class="grow" onclick="openPage('game', 'character_creation')">New Game
<p>
</div>
<div id="mm_load_game">
<p id="mm_load_game_p" class="grow">Load Game</p>
</div>
<div id="mm_options">
<p id="mm_options_p" class="grow">Options</p>
</div>
<div id="mm_credits">
<p id="mm_credits_p" class="grow">Credits</p>
</div>
</div>
</div>
<div id="page_character_creation">
Character Creation test
</div>
</div>
Essentially creating a trivia game and having issues implementing jQuery .hide() and .show() functions. I've been reviewing other questions here on SO and my code looks correct, so I'm confused as to why all my divs are still visible, with no response from button clicks. I've tried to condense my code by leaving out the details the divs I'm trying to hide and show, just to focus on that current problem. I just left out the actual question data and timer function.
//Problematic functions
$( document ).ready(function(){
$("#mainbox").hide();
$("#beginning").click(function(){
$("#begin").hide();
$("#mainbox").show();
startTime();
})
Divs I'm trying to hide
<div id="begin" class="unhidden">
<h1>Trivia Game</h1>
<h2>Don't run out of time!</h2>
<p>
<button id="beginning">Start</button>
</p>
<br>
</div>
<div id = "mainbox" class="hidden">
<h2>Answer the following:</h2>
<h2 id="timer">Remaining Time: </h2>
</div>
Is it a scope / ordering issue?
You're missing a set of closing braces. You're closing your click event handler function, but not your ready function.
Here is an example of your code running with the additional closing brace. Make sure you write your code cleanly and indent properly to make these kind of typos easier to notice. Also, run you code through a validator or "linter" to make sure the code you've written is free of errors.
$(function() {
$("#mainbox").hide();
$("#beginning").on('click', function(){
$("#begin").hide();
$("#mainbox").show();
startTime();
}); // close click handler
}); // close ready
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="begin" class="unhidden">
<h1>Trivia Game</h1>
<h2>Don't run out of time!</h2>
<p>
<button id="beginning">Start</button>
</p>
</div>
<div id="mainbox" class="hidden">
<h2>Answer the following:</h2>
<h2 id="timer">Remaining Time: </h2>
</div>
Also note that you don't need $(document).ready(function() { ... }); anymore. The equivalent is simply $(function() { ... });. Additionally, you should use .on() to create event handlers.
Here is the template whose DOM elements I am trying to control:
<template name='libraryTemplate'>
<div class="container-fluid library_container">
<div class="row">
<div class="col-sm-6">
<h1 id='maglens_library_header'>MY LIBRARY</h1>
<div id='library_page_break'></div>
<div id='folders_text'>
Folders:
</div>
</div>
<div class="col-sm-6">
<a class='button-text btn' id='add_new_button'>ADD NEW</a>
</div>
</div>
<div class="row">
<div class="col-sm-3 folders" id='google_drive_thumbnail'></div>
</div>
</div>
</template>
And here is the jQuery Im using to do so. My $('body') selector works fine, and my log statement just inside $(document).ready() behaves correctly, but why can't I target the selector $('.folders')? Upon inspection of the DOM, I can see exactly where the code is, but it's like jQuery thinks it doesnt exist?
$(document).ready(function(){
console.log('document ready');
$('.folders').on('click', function(){
console.log('folders clicked');
})
// $('body').on('click', function(){
// console.log('body clicked');
// })
});
I don't see any selectors named folders.
I do see <div id='folders_text'>.
That's why your body event fires but your other one doesn't.
Secondly, you should be using template events, you're working with Meteor now.
Template.libraryTemplate.events({
'click .folders': function() { console.log('clicked') }
})
I'd definitely recommend using the meteor events as everyone else suggested.
What you had actually works, it is just since the div with the "folders" class has no content, the div is very small (unless you have a height attribute on ".folders" or "#google_drive_thumbnail") and thus very hard to click on. Inspect element on the div and you'll see the size
I have the following HTML code, and i am currently trying to add the 'selected' class when a photo is clicked, and to remove the class when it is clicked again.
<div id="container">
<h1>Photo Gallery</h1>
<div id="gallery">
<div class="photo">
<img src="photos/skyemonroe.jpg">
<div class="details">
<div class="description">The Cuillin Mountains, Isle of Skye, Scotland.</div>
<div class="date">12/24/2000</div>
<div class="photographer">Alasdair Dougall</div>
</div>
</div>
//Repetitions of the photo class.....
</div>
<a id="more-photos" href="pages/1.html">More Photos</a>
</div>
I am currently using the following jquery code to bind an event handler to the photo's ancestor so that when more pictures are appended to the page when clicking the more photos button, the jquery code will still work with these newly added pictures.
jQuery
$('#gallery').on('click','.photo',function(){
$(this).toggleClass('selected');
});
The jQuery code above DOES NOT work when i try using the #gallery, NOR does it work when i try using #container.However, the code works when i use $(document) for the event delegation.
I can't seem to figure out why binding the event handlers to the parent elements do not work, but binding it to the document itself makes it work.
Would appreciate any insights into the matter
EDIT: Added the jsfiddle here http://jsfiddle.net/744cX/ ( The code works in the fiddle, but does nothing on my laptop, and i can't seem to figure out why)
You can listen event on '.photo' class
<div class="photo" onclick="$(this).toggleClass('selected');">
I forked your fiddle and as can be seen here:
http://jsfiddle.net/6Qz8C/1/
$('#gallery').on('click','.photo',function(){
$(this).toggleClass('selected');
});
I did:
when the nextpage event is fired, append a new photo.
add the event delegation when the document is ready.
set the delegator to the #gallery
Is it possible to copy javascript with javascript? For example:
<div class="copyThis">
<script language="javascript">
$(function()
{
$("#click").click(function(e){
$('.copyThis').clone().appendTo('#copyArea');
e.preventDefault();
});
});
</script>
CONTENT CONTENT CONTENT CONTENT CONTENT CONTENT CONTENT CONTENT CONTENT
<div style="width: 200px; height: 50px; background-color: gray;">
<a id="click" href="">click here to copy</a>
</div>
<div id="copyArea">
Put here:
</div>
</div>
But this doesn't copy the tag and its content. At least, not that I know of.
NOTE:
I came upon this question in relationship to a different question I had posted here: Infinite-loop question: Is it possible to make a "Copy this code to share", with a "copy this code to share" inside of it?
I hope it's ok to post this question separately as it's sort of a curiosity thing.
EDIT: I think this is what you want. This (demo) will fill a textarea for easy copying:
<div id="copyThis">
<script language="javascript">
$(function()
{
$("#click").click(function(e){
$('#copyArea').val($('#copyThis').html());
e.preventDefault();
});
});
</script>
CONTENT CONTENT CONTENT CONTENT CONTENT CONTENT CONTENT CONTENT CONTENT
<div style="width: 200px; height: 50px; background-color: gray;">
<a id="click" href="">click here to copy</a>
</div>
<textarea rows="10" cols="40" id="copyArea"></textarea>
</div>
You were doing DOM manipulation before ready. Use:
<script language="javascript">
$(function()
{
$("#click").click(function(e){
$('#copyThis').clone().appendTo('#copyArea');
e.preventDefault();
});
});
</script>
See the demo.
I think in a round about way what your trying to do is covered by jquery's live methods.
<div class="copy">
<a class="click-me">click me</click>
</div>
<script type="text/javascript">
$('.click-me').live('click',function(e){
$(e).parent().clone().appendTo('#copyArea');
})
</script>
Using Live will re-bind the new element to the click handler without having to copy a javascript block
If you want the click event to be cloned also, you need to set the withDataAndEvents argument to true in clone
$('.copyThis').clone(true).appendTo('#copyArea');
Note: this answer is to a question different from the one actually asked :-) I'll leave it here as a historical curiosity however.
The problem is very likely to be that your <script> tags are just not being executed. If what you want to happen is that your cloned <div> have the same "click" handler, however, you should really go about it in a totally different way:
Use a "class" instead of an "id" to mark the <div> elements that should be affected; say, "cloneMe"
Use the jQuery .live() or (better) .delegate() facilities to set up the handler so that it operates off of bubbled events, and can therefore handle clicks on cloned <div> blocks.
(then in your Javascript somewhere: )
$(function() {
$('body').delegate("div.cloneMe", "click", function(ev) {
$(this).clone().appendTo('#copyArea');
ev.preventDefault();
});
});
Now you should be able to clone to your heart's content, and you don't have to worry about that bad old Javascript jammed so obtrusively into your code.
edit — ah - I now see that I was completely confused about what it was that was getting clicked. If the clicking is happening on a separate button (or <a> or whatever), then there's really no need to have the script stuck in the middle of the page at all; the whole thing should just be a simple event handler setup.