Issue with binding event handler to dynamically generated divs - javascript

I have a problem with displaying the id of the clicked div on the screen in an alert window. I am pretty confident this is because of the order of the controls and event handlers being added to the page, however after trying different ways I am unable to get this to work. Unfortunately I can't post reproducible code due to the div's being created from an ajax get request.
$(document).ready(function () {
$.getJSON('ClientPortal/GetSkills', function (data) {
var test = 'poo';
$.each(data, function (data) {
$('#flipContainer').append("<div class=flip id='" + this.Value + "' value='" + this.Value + "'>" + this.Text + "<//div>");
})
})
})
$(document).ready(function () {
$(".flip").on('click', function () {
alert($(this).attr("id"));
})
})

Try this :
$(document).ready(function () {
$("#flipContainer").on("click", ".flip", function () {
alert($(this).attr("id"));
})
})
You effectively have to base you click-binding on an element existing when the DOM ready event fires... But with this syntax, you delegate the binding on an existing element but it applies to another element contain in the first one...
See the jQuery documentation for on (for line "selector") : http://api.jquery.com/on/#on-events-selector-data-handlereventObject .

Related

The code in the Ajax done method doesn't recognize the code thats already loaded

So I am trying to make a dynamic system where a button changes when you click on another button. For instance, when you click on the button: "12+4", different buttons will appear at another div. I use an append method for that. But when you click on one of the "patroon" buttons, it will not execute the $(".tile").on('click', function). That is because that code is already executed before the ajax call. My code is below:
arr.forEach(function (value, key) {
$("#row2").append('<button class="dikte" data-value="' + key + '">' + value + '</button>')
});
$(".dikte").on('click', function () {
let dataVal = $(this).data('value');
// Code...
$.ajax({
url: "Api/getObjectGroepen.php",
type: 'GET',
beforeSend: function () {
// $(".spinner-border").removeClass("d-none");
},
success: function () {
// $(".spinner-border").addClass("d-none");
}
}).done(function (data) {
$("#row3").html("");
$(arrObjectGroep).each(function (key, value) {
$("#row3").append('<button class="btn tile" data-value="' + value + '">' + JSON.parse(data)[value] + '</button>')
});
});
});
// Tile section
$(".tile").on("click", function (e) {
// Prevents button from executing
e.preventDefault();
// execute code
console.log(123);
});
So the $(".tile") are all the buttons. And $(".dikte") is the "12+4" button.
Hopefully someone understands my problem about what is going on, it's maybe a bit hard to explain, but I can explain further if there are any questions. Is there a clean and simple solution for this? Rather than moving all the code to the done method.
Jquery doesn't know the button's which you appended dynamically, for that your code should be like below, and which will rescan the document to find the element with the class name
$(document).on('click','.tile',function(e){
// code
});

Grab URL parameter onclick of url.. Jquery, Javascript

I am having some trouble trying to store the url parameters of some dynamic links that I created with an ajax post response. The ajax post is working correctly and the name and subgenre vars are being properly filled from the ajax response. Now what I would like to happen is that a user clicks on one of the generated urls, the parameters inside of the urls, i.e. subgenre="blah", are going to be sent to a database and stored. The problem I am having is that a standard event click function will not work inside or outside of the document ready function.
$(document).ready(function() {
$.each(data, function() {
$('#artist-suggestions').append('<li>' + this.name + this.new + '</li>');
});
});
I then created an onclick function, as below, but I can not use the "this" query because it is outside of the document scope. I had to put the onclick function outside of the document ready function or else it would not work.
function artistGen(){
alert('dfdsf');
};
What am I missing here or what am I doing wrong?
You can pass these in the onclick function when you make each element.
$(document).ready(function() {
$.each(data, function() {
artist = this.name;
$('#artist-suggestions').append('<li>' + this.name + this.new + '</li>');
});
})
;
function artistGen(Blah1, Blah2){
saveData(Blah1, Blah2);
alert('dfdsf');
};
In jQuery for dynamic elements you can use the click event in this way
$('#artist-suggestions li').on('click', 'a', function() {
// do something
});
or you can continue with the way you did, by using a function but just add a parameter to that function
like
function artistGen(Artist){
// do something
};
You need to remove the artistGen() function from the scope of the .load()
$(window).load(function(){
$('#artist-suggestions').append('<li>jim new</li>');
});
function artistGen(){
alert('dfdsf');
}
JSFIDDLE DEMO
That's just how it is a function called in those event attributes have to be defined globally(or defined right there) not in any wrapper function. A better solution would be to attach event handlers.
$(document).ready(function() {
function artistGen(){
alert(this.href);
};
$.each(data, function() {
var $li = $('<li>' + this.name + this.new + '</li>');
$li.find('a').on('click', artistGen);
$('#artist-suggestions').append($li)
});
});

Combine two jQuery-json functions. Right way

I'm totally newbie in jQuery and i wonder if it is possible to combine these two functions.
As you can see, the first function is used to load json data to trigger a click.
The second function is used to toggle view for the list items.
Could you help me, and show me the good way to combine these functions!?
When the json file is loaded, it will be create the list elements (li), and the toggle will be able to toggle these list elements (li).
IMPORTANT: actually, my code don't work (the toggle function not work fine).
Here is the code of 1st functions :
$(document).ready(function() {
// ----------------------
// JSON INFOS
// ----------------------
$(".color-list.one li:first-child").on('click', function() {
$.getJSON("result.json", function(data) {
//Handle my response
$('ul.elements-list').html(
'<li class="elements-item"><span class="tog">' + data.name + '</span><div class="togcont hidden">' + data.info + data.size + '</div></li>');
//alert(data);
});
});
});
The code of 2nd function :
$(document).ready(function() {
// ----------------------
// TOGGLE BULLZ
// ----------------------
$(".tog").click(function(){
var obj = $(this).next();
if($(obj).hasClass("hidden")){
$(obj).removeClass("hidden").slideDown();
$(this).addClass("bounce");
} else {
$(obj).addClass("hidden").slideUp();
$(this).removeClass("bounce");
}
});
});
When you use $(".tog").click() it only binds to whatever elements match the ".tog" selector at that moment so won't work on elements that you add dynamically later. You can instead use the delegated syntax of .on() like this:
$('ul.elements-list').on("click", ".tog", function(){ ...
...which will bind the click handler to your list, but only execute your function if the click occurred on an element in that list that matches the ".tog" selector in the second parameter at the time of the click. And within the handler this will be set to the ".tog" element that was clicked.
Also you can put all your code in a single document ready handler assuming all the code is in the same file.
Also your obj variable is a jQuery object, so you can call jQuery methods on it directly like obj.hasClass() rather than wrapping it in $() again as $(obj).hasClass().
So try this instead:
$(document).ready(function() {
$(".color-list.one li:first-child").on('click', function() {
$.getJSON("result.json", function(data) {
//Handle my response
$('ul.elements-list').html(
'<li class="elements-item"><span class="tog">' + data.name + '</span><div class="togcont hidden">' + data.info + data.size + '</div></li>');
});
});
$('ul.elements-list').on("click", ".tog", function(){
var obj = $(this).next();
if(obj.hasClass("hidden")){
obj.removeClass("hidden").slideDown();
$(this).addClass("bounce");
} else {
obj.addClass("hidden").slideUp();
$(this).removeClass("bounce");
}
});
});

How to write jquery selectors for dynamically generated html elements?

I'm currently writing an object oriented module which assigns callback to dynamically generated elements.
function Instant(containerID) {
this.var1 = 0;
this.var2 = 0;
this.containerID = containerID;
// and more variables...
};
And here containerID is the id of a DIV which is dynamically generated. I populate this DIV via Ajax Request which reads a file like the following:
<!-- content.html -->
<div class="general_container">
<div class="top_container">
<!-- plenty of divs, spans etc -->
</div>
<div class="tweet_section">
<!-- plenty of divs, spans etc -->
</div>
</div>
Now the important part is, I assign all callbacks like the following:
Instant.prototype.addCallbacks = function() {
$(this.containerID + " bar").click(function() {
$(this.containerID + " bar").foo();
});
$(this.containerID + " bar").click(function() {
$(this.containerID + " bar").foo();
});
$(this.containerID+ " bar").click(function(e) {
$(this.containerID + "bar, " + this.containerID+ " bar").foo();
});
});
As you see, I always have to put this.containerID before each selector to assign events. (Therefore, I make sure I'm selecting only one element) Now, my code is full of clutter as I have plenty of this.containerIDs. I don't know if there is a smarter method to make my code easy. Any help will be appreciated.
Here is a sample JSFiddle.
Note that this is not my real module, I just made it up to make it clear!
Then you shouldn't be using IDs. You should be using classes instead.
It would take long to edit your code, but here's a hint: Add a handler to the parent. Use event delegation, like .on(). Then have it listen for all children, now or future.
Create a separate java script file and put your add callbacks function in there and just pass the containerID. That way, you can re-use it later. However, looks like you cannot get rid of containterID since you will be needing that to do your add, subtract, save etc..
in your current file shown as above,
Instant.prototype.addCallbacks = createAddCallbacks(this.ContainerID);
create addCallbacks.js
function createAddCallbacks(containerId)
{
Instant.prototype.addCallbacks = function() {
$(containerId + " bar").click(function() {
$(containerId + " bar").foo();
});
$(containerId + " bar").click(function() {
$(containerId + " bar").foo();
});
$(containerId+ " bar").click(function(e) {
$(containerId + "bar, " + containerIdD+ " bar").foo();
});
});
}
Like #JosephTheDreamer said, use Event Delegation. (Jquery.fn.on)
Using event delegation you set one handler to multiple targets. It means just one handler in memory and dynamic event handlers set.
I made a demonstration modifying your code, take a look...
Instant.prototype.addCallbacks = function () {
var selfContainer = null, // DOMElement container
me = this; // Object reference
$('body').on("click", ".selection_container .btn-add", function () { //Using event delegation
selfContainer = $(this).parents(".general_container"); //set DOMElement
selfContainer.find("input[name=currentValue]").val(++me.instantValue);
});
$('body').on("click", ".selection_container .btn-subtract", function () {
selfContainer.find("input[name=currentValue]").val(--me.instantValue);
});
$('body').on("click", ".selection_container .btn-reset", function () {
me.instantValue = 0;
selfContainer.find('input[name=currentValue]').val(0);
});
$('body').on("click", ".selection_container .btn-save", function () {
me.savedValue = me.instantValue;
});
$('body').on("click", ".selection_container .btn-load", function () {
me.instantValue = me.savedValue;
selfContainer.find('input[name=currentValue]').val(me.savedValue);
});
};
Hope it helps...
So, I think I find a better method according to this post
I wanted to limit the scope of my selector.
Firstly, I'll create a jQuery instance variable
function Instant(containerID) {
this.var1 = 0;
this.var2 = 0;
this.container= $('#'+containerID);
// and more variables...
};
and adding a new prototype like this
Instant.prototype.$ = function(selector){
return this.container.find(selector);
};
I'll only use this.$(selector) function which is better.

Getting reference to element that invoked inline function with JQuery

I am inserting elements into the DOM populated with some data I retrieved from a web service. I attached an inline click event to call a function when invoked. The problem is I am not getting a reference to the element that invoked that function.
Code that appends the new elements:
$.getJSON("/search?" + $(this).serialize(), function (data) {
if (data != null) {
$.each(data, function (index, video) {
resultItem.append("<li ><a onclick='loadNewVideo(e)' href='play?video=" + video.video_id + "'>" + "<img width='185' src='" + video.defaultImg + "'/>" + "<span class='video_left_title'>" + video.song.song_name + "<h6 class='artist_name'>" + video.artist.artist_name + "</h6></span></a>");
});
}
});
Function:
function loadNewVideo (e) {
e.preventDefault();
alert($(this).attr("href"));
}
Instead of using inline event handlers, you could delegate the clicks on all a to resultItem:
// Call this only once, when resultItem is already in the DOM
// (for example, on a document.ready callback)
resultItem.on('click', 'a', loadNewVideo);
// Proceed with your current code (slightly modified):
function loadNewVideo (e) {
e.preventDefault();
alert($(this).attr("href"));
}
$.getJSON ("/search?" + $(this).serialize(),function (data) {
if (data != null) {
$.each (data,function (index,video) {
resultItem.append("<li ><a href='play?video=" + video.video_id +"'>"
+ "<img width='185' src='"+video.defaultImg +"'/>"
+ "<span class='video_left_title'>"+ video.song.song_name
+ "<h6 class='artist_name'>"+video.artist.artist_name
+ "</h6></span></a>");
});
}
});
Inline onclick handlers don't go through jQuery, which is why you don't have access.
You can either leave those there and change the handler:
function loadNewVideo(e) {
e.preventDefault();
alert($(e.target).attr("href"));
}
Or, and more preferably, don't use the inline handlers. Just give the a elements a class of video (or whatever) and install handlers with jQuery:
...
resultItem.append("<li><a class='video' href=...'")
...
// and elsewhere
$(resultItem).on('click', 'a.video', loadNewVideo);
jQuery's event object allowed me to grab what the documentation calls the 'current DOM element within the event bubbling phase'.
var originatingElement = event.currentTarget;

Categories

Resources