JavaScript: binding click handler to object instance throws undefined error - javascript

Suppose I have an object oTodo that has two functions:
let oTodo = {
getTodoList: function() {
alert('test');
}
displayPageNums: function() {
for(let i = 1; i <= 3; i++) {
$('#next').before(`<li class="page-item">
<button onclick="oTodo.getTodoList()" class="page-link">${i}</button>
</li>`);
}
},
}
How can I use the getTodoList() function inside the onclick event? It throws an error saying that the function is not defined.
Any idea how can I fix this?
I also tried this which also fails:
<button onclick="${oTodo.getTodoList()}" class="page-link">${i}</button>

As you're using jQuery, consider using jQuery to bind the click event to your li elements, rather than to use inline event binding (via onclick) as you currently are.
Taking this approach would give you the ability to directly access the oTodo object and call the corresponding getTodoList() function as your click event handler like this:
let oTodo = {
getTodoList: function(event) {
const value = event.currentTarget.dataset.value;
alert(value);
},
displayPageNums: function() {
for (let i = 1; i <= 3; i++) {
/* Create list element wrapped with jquery */
const li = $(`<li class="page-item" data-value="${i}">
<button class="page-link">${i}</button>
</li>`);
/* Attach oTodo.getTodoList function as handler for click event */
li.click(oTodo.getTodoList);
/* Add li element before next */
$('#next').before(li);
}
}
}
/* Test */
oTodo.displayPageNums();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.0/jquery.min.js">
</script>
<div id="next"></div>

well unfortunately you are trying to combine javascript with html it is not possible with jQuery its not jsx . usage of $ requires script tag
better will be you assign the nested obj fucn to a variable as
const someVariable = oTodo.displayPageNums;
and then you can use it with onclick as
<button onclick="someVariable()" class="page-link"></button>
For ${i} you have to bind it with Jquery and inject it with the $.html() function

Related

How to generate dynamically events in jquery?

I'm trying to set event attributes on a group of drop-down generated dynamically but for some reason the events aren't working.
Heres's my code.
$(document).ready(function () {
var idRoomTypesList = $("#idRoomTypesList").attr('value').split("_");
for (var i = 0; i < idRoomTypesList.length; i++) {
$("#roomTypeID-" + idRoomTypesList[i] + "_nRentedRooms").attr("onchange", generatePrice);
}
});
var generatePrice = function () {
alert(this.value().toString());
}
I think this must work for you
$(document).ready(function () {
var idRoomTypesList = $("#idRoomTypesList").attr('value').split("_");
for (var i = 0; i < idRoomTypesList.length; i++) {
$("#roomTypeID-" + idRoomTypesList[i] + "_nRentedRooms").on("change", generatePrice);
}
});
var generatePrice = function () {
alert($(this).val());
}
And have a look at this:
How to use the jQuery Selector in this web application?
HTML:
<select class="dynamicSelects">
....
</select>
JS:
var generatePrice = function () {
alert(this.value);
};
$(document).ready(function () {
$('body').on('change', '.dynamicSelects', generatePrice);
});
This is an example of using the on method provided by jQuery and delegating the events. This means that even if those drop downs are not in the DOM yet you can still attach the event to it and whenever they exist in the DOM the event will fire. It basically says attach these events to body but fire on elements with the class dynamicSelects. This covers adding any other dynamically generated drop downs with this class later as well.
Setting attributes to attach events, while it may work, should really be done using the on method or in plain JS the addEventListener, in my opinion.
Also when operating on plain DOM elements the value property is not a function so no value() is needed. Just this.value. And you don't need to convert it to a string because value returns a string. If it were a jquery object then you can do $(this).val() which is a function.
I only suggest this change of course because if you are going to use a library like jQuery at least take advantage of the things it offers.
Did you search into the jQuery documentation?
$(document).ready(function () {
var $idRoomTypesList = $("#idRoomTypesList").attr('value').split("_");
for (var i = 0; i < idRoomTypesList.length; i++) {
$("#roomTypeID-" + idRoomTypesList[i] + "_nRentedRooms").attr("onchange", generatePrice);
}
$( "#idRoomTypesList" ).change(generatePrice());
});
var generatePrice = function () {
alert(this.value().toString());
}

pass through current target name to function

I'd like to dynamically create event listeners for multiple buttons, and subsequently, show a particular frame label depending on the button clicked, but I'm unsure what to pass through (FYI, this is will be used for HTML5 canvas in Flash CC, but principally the same should apply to a web page for showing divs etc). I currently have this:
var butTotal = 4;
var selfHome = this;
function createListeners () {
for (var i=0; i<butTotal; i++) {
selfHome["btn" + i].addEventListener('click', openPop);
}
}
function openPop () {
alert("test");
selfHome.gotoAndPlay("pop"+event.currentTarget.name.substr(3));
}
createListeners();
It creates the listeners fine, but I don't really know where to start with passing through the current button instance name to tell it which frame label to gotoAndPlay.
Based on the code that you have, I'd simply change the .addEventListener() to call a generic function (rather than openPop, directly), and pass it the reference to the button. So, this:
selfHome["btn" + i].addEventListener('click', openPop);
. . . would become this:
selfHome["btn" + i].addEventListener('click', function() {
openPop(this);
});
At that point, you would then have to update openPop to accept a parameter for the reference to the element that triggered it . . . something like:
function openPop (currentButton) {
At that point, you could reference the clicked button, by using currentButton in the openPop logic.
I'm not sure I totally understand your question. However if you just need to pass the button instance (in you case "selfHome["btn" + i]") you could call an anonymous function in your event handler which calls openPop() with the button instance as an arugment. Would this work for you?
var butTotal = 4;
var selfHome = this;
function createListeners () {
for (var i=0; i<butTotal; i++) {
var currentBtn = selfHome["btn" + i];
currentBtn.addEventListener('click', function(){openPop(currentBtn);} );
}
}
function openPop (btn) {
alert("test");
selfHome.gotoAndPlay(/*use button instance 'btn' to find frame*/);
}
createListeners();
When the event is triggered the this keyword inside the handler function is set to the element is firing the event EventTarget.addEventListener on MDN. If the button have the data needed to be retrieved just get it from the this keyword:
function openPop (btn) {
alert(this.name);
/* ... */
}
It looks like you expect it to contain the function gotoAndPlay() as well as the btn elements (which contain both an ID (of btn[number]) and a name with something special at substr(3) (I assume the same as the id). If those things were all true, it should work in chrome... in other browsers you'll need to add event to the openPop() method signature.
function openPop (event) {
alert("test");
selfHome.gotoAndPlay("pop"+event.currentTarget.name.substr(3));
}
I believe this is what you are looking for and adding that one word should fix your problem (assuming some things about your dom and what selfHome contains):
JSFiddle
You could also leave out the event from openPop() and replace event.currentTarget with this:
function openPop () {
alert("test");
selfHome.gotoAndPlay("pop"+this.name.substr(3));
}
JSFiddle

Defining a single jQuery function for separate DOM elements

I have several jQuery click functions- each is attached to a different DOM element, and does slightly different things...
One, for example, opens and closes a dictionary, and changes the text...
$(".dictionaryFlip").click(function(){
var link = $(this);
$(".dictionaryHolder").slideToggle('fast', function() {
if ($(this).is(":visible")) {
link.text("dictionary ON");
}
else {
link.text("dictionary OFF");
}
});
});
HTML
<div class="dictionaryHolder">
<div id="dictionaryHeading">
<span class="dictionaryTitle">中 文 词 典</span>
<span class="dictionaryHeadings">Dialog</span>
<span class="dictionaryHeadings">Word Bank</span>
</div>
</div>
<p class="dictionaryFlip">toggle dictionary: off</p>
I have a separate click function for each thing I'd like to do...
Is there a way to define one click function and assign it to different DOM elements? Then maybe use if else logic to change up what's done inside the function?
Thanks!
Clarification:
I have a click function to 1) Turn on and off the dictionary, 2) Turn on and off the menu, 3) Turn on and off the minimap... etc... Just wanted to cut down on code by combining all of these into a single click function
You can of course define a single function and use it on multiple HTML elements. It's a common pattern and should be utilized if at all possible!
var onclick = function(event) {
var $elem = $(this);
alert("Clicked!");
};
$("a").click(onclick);
$(".b").click(onclick);
$("#c").click(onclick);
// jQuery can select multiple elements in one selector
$("a, .b, #c").click(onclick);
You can also store contextual information on the element using the data- custom attribute. jQuery has a nice .data function (it's simply a prefixed proxy for .attr) that allows you to easily set and retrieve keys and values on an element. Say we have a list of people, for example:
<section>
<div class="user" data-id="124124">
<h1>John Smith</h1>
<h3>Cupertino, San Franciso</h3>
</div>
</section>
Now we register a click handler on the .user class and get the id on the user:
var onclick = function(event) {
var $this = $(this), //Always good to cache your jQuery elements (if you use them more than once)
id = $this.data("id");
alert("User ID: " + id);
};
$(".user").click(onclick);
Here's a simple pattern
function a(elem){
var link = $(elem);
$(".dictionaryHolder").slideToggle('fast', function() {
if (link.is(":visible")) {
link.text("dictionary ON");
}
else {
link.text("dictionary OFF");
}
});
}
$(".dictionaryFlip").click(function(){a(this);});
$(".anotherElement").click(function(){a(this);});
Well, you could do something like:
var f = function() {
var $this = $(this);
if($this.hasClass('A')) { /* do something */ }
if($this.hasClass('B')) { /* do something else */ }
}
$('.selector').click(f);
and so inside the f function you check what was class of clicked element
and depending on that do what u wish
For better performance, you can assign only one event listener to your page. Then, use event.target to know which part was clicked and what to do.
I would put each action in a separate function, to keep code readable.
I would also recommend using a unique Id per clickable item you need.
$("body").click(function(event) {
switch(event.target.id) {
// call suitable action according to the id of clicked element
case 'dictionaryFlip':
flipDictionnary()
break;
case 'menuToggle':
toggleMenu()
break;
// other actions go here
}
});
function flipDictionnary() {
// code here
}
function toggleMenu() {
// code here
}
cf. Event Delegation with jQuery http://www.sitepoint.com/event-delegation-with-jquery/

No events for dynamically generated input tags

I have dynamically generated some input tags for a web application.
function FormElement () {
this.formElement = $('<div class="formElement"></div>');
this.formElement.append('<label for=""></label>');
this.formElement.append('<input type="text" />');
FormElement.prototype.addIds = function (id) {
this.formElement.find('label').attr({'for':id});
this.formElement.find('input').attr({'id':id});
return this.formElement;
};
FormElement.prototype.addLabelText = function (value) {
this.formElement.find('label').html(value);
};
FormElement.prototype.addInputValue = function (value) {
this.formElement.find('input').attr({'value':value});
};
FormElement.prototype.addClass = function (className) {
this.formElement.attr({'class':className});
};
FormElement.prototype.append = function (selector) {
$(selector).append(this.formElement);
};
}
The appended elements do not seem to have associated click, select etc.. events. I read you can you .on(). I would like to associate all possible events to all types of elements in a general way. What is the best way to go about this?
Suppose you want to assign a default behavior on click event for all inputs with a specific class, say 'foo':
$(document).on('click','input.foo', function(){
/* your function here */
});
If you don't go this way and try the following:
$('input.foo').click(function(){
/* your function here */
});
then the behavior will be added only to existing elements, not to those added after the script executed.
you have to use On() function on them
Attach an event handler function for one or more events to the selected elements.
$("button").on("click", 'selector',notify);
$("target").on("change",'selector', notify);
For dynamically generated element's you need event delegation -
$(document).on('change','.yourInputClass',function(){
var value = $(this).val();
});
http://api.jquery.com/on/

assigning click method to variable

I am creating an array & assigning the value to each index in a function through variables.
I also want to attach a jquery click method to each variable. However, I am getting 'undefined' in return when the click method is called.
var i = 0;
var eCreditTransactions = new Array(6); // 6 members created which will be recycled
function abc()
{
addingElements (i);
}
/* **** THE FOLLOWING IS THE PROBLEM AREA **** */
$(eCreditTransactions[i]).click (function () // if user clicks on the transaction box
{
creditTransactionSlideIn (eCreditTransactions[0], 150); //another function called
});
/* **** this is the function being called in the first function above **** */
function addingElements (arrayIndex) // func called from within the 'createCreditTransaction()' func
{
eCreditTransactions[i] = $(document.createElement('div')).addClass("cCreditTransaction").appendTo(eCreditSystem);
$(eCreditTransactions[i]).attr ('id', ('trans' + i));
$(eCreditTransactions[i]).html ('<div class="cCreditContainer"><span class="cCreditsNo">-50</span> <img class="cCurrency" src="" alt="" /></div><span class="cCloseMsg">Click box to close.</span><div class="dots"></div><div class="dots"></div><div class="dots"></div>');
creditTransactionSlideOut (eCreditTransactions[i], 666); // calling slideOut animation
counterFunc ();
return i++;
}
Try this:
$(document).ready(function() {
$(".cCreditTransaction").click(function() {
//do what you want on click event
});
});
Hope it helps
Given that it looks like each element you're adding to the array has a classname (cCreditTransaction) you can hookup the click events using something like
$(document).delegate(".cCreditTransaction", "click", function() {
// code to fire on click goes here.
});
or in jQuery 1.7+ you can use .on instead of .delegate
You don't then need to hook up n events, but just one event that matches all items in the selector (in your case, the class name)
You should also change $(document) to a container element that has an Id, so that the DOM traversal to find the classes is trimmed down as much as possible. Why? Because finding elements by class name is a relatively expensive procedure, as opposed to finding tags or even better, an ID.
it looks like there should be a loop in this part:
function abc()
{
addingElements (i);
}
there is a call to addingElements, and an 'i' parameter being passed, but 'i' is at that moment still defined as 0.
it should say something like
function abc()
{
for (i=0;i<=7;i++)
{
addingElements (i);
}
}

Categories