I'm having issues with onclick, specifically the onclick="Foo()" seen in the code below. When clicked, I'm getting undefined, yet I have included the function at the top and even out of the function.
$( document ).ready(function() {
function Foo() {
console.log('clicky click click');
document.getElementById('categoryBubble').style.display = 'none';
}
$('.mutliSelect select').on('change', function() {
var title = $(this).closest('.mutliSelect').find('option').val();
title = $(this).val() + "";
if ($(this).is(':selected')) {
// the code for if goes here
} else {
console.log('im working here #2');
var html = '<span id="categoryBubble" title="' + title + '">' + title + '</span>' + '<span onclick="Foo()" class="Xout">x</span>';
$('.multiSel').append(html);
$(".hida").hide();
}
});
});
Foo()
(which isn't a constructor function so it shouldn't be named starting with a capital letter) is locally scoped to the anonymous function you pass to ready.
Then the onclick
event handler goes looking for something called Foo
, it can't find it because it isn't in the right scope.
Don't use intrinsic event attributes, they have all sorts of nasty issues, one of which is that you're pretty much forced to use globals with them.
Generate your HTML with jQuery functions instead of mashing strings together. Bind your event handler with the jQuery on
method and not an onclick
attribute.
$(function() {
function foo() {
console.log("clicky click click");
document.getElementById("categoryBubble").style.display = "none";
}
$(".mutliSelect select").on("change", function() {
var title = $(this)
.closest(".mutliSelect")
.find("option")
.val();
title = $(this).val() + "";
if ($(this).is(":selected")) {
// the code for if goes here
} else {
console.log("im working here #2");
var span = $("<span />")
.attr("id", "categoryBubble")
.attr("title", title)
.text(title);
var other_span = $("<span />")
.on("click", foo)
.addClass("Xout")
.text("x");
$(".multiSel").append(span);
$(".multiSel").append(other_span);
$(".hida").hide();
}
});
});
Your foo
is defined inside the document).ready
- it's not on the top level, so when the inline handler tries to find a global function named Foo
to call, it fails.
Either put Foo
outside:
function Foo() {
console.log('clicky click click');
document.getElementById('categoryBubble').style.display = 'none';
}
$( document ).ready(function() {
// ...
Or, even better, avoid inline handlers entirely, and attach the listener properly using Javascript instead, allowing you to reference other variables and functions inside the current scope:
const span1 = $('<span></span>')
.prop({
id: 'categoryBubble',
title
})
.text(title);
const span2 = $('<span></span>')
.prop('class', 'xOut')
.on('click', Foo);
$('.multiSel').append(span, span2);
Also note that, in modern versions of jQuery, rather than $( document ).ready()
, you can use
$(() => {
// code here
instead. In addition, having multiple IDs in a single document is invalid HTML; appending
<span id="categoryBubble"
multiple times (if that's a possibility, given other code you may have) will not be valid. Consider using a class instead.
<span class="categoryBubble"
If you do indeed want to append a span multiple times, and you want clicking on the created span to remove the categoryBubble
associated with that span, then the ID selector won't work - instead, you can reference the span created earlier in the closure, and hide it:
const span2 = $('<span></span>')
.prop('class', 'xOut')
.on('click', () => {
span1.hide();
});