Jquery on event not firing for buttons - javascript

I have searched for an answer for this and I understand how event delegation works but what ever I try nothing changes.
The buttons that are dynamicaly created will not trigger the on event when manually clicked however using the trigger() method works, what is wrong with my code?
components.forEach(function (component) {
var id = randomId();
var li = $.create("li").addClass("col-12");
componentList.append(li);
var btn = $.create("button")
.text(component.type)
.attr("id", id)
.addClass("btn")
.appendTo(li);
componentList.on("click", "#" + id, function () {
alert("test");
window.circuit.push(component.create());
circuitList.refresh();
});
btn.trigger("click");
});
$.create = function (arg) {
return $(document.createElement(arg));
}
randomId = function () {
return "id" + Math.floor(Math.random() * 100000) + "_" + Math.floor(Math.random() * 100000);
}
The display is as expected, the buttons just won't fire manually.
Components is an array of objects with a type property and create method.

The following statement was erroneous:
componentList.on("click", "#" + id, function () {...
jQuery is smart enough to know which button was clicked just by using a class or even a tag as the second parameter.
$('.list').on("click", '.btn', function(e) {
Details commented in Demo
Demo
/* Had no idea what components is supposed to be */
var components = ['potentiometer', 'transistor', 'capicitor', 'transformer'];
/* On each loop $.map() will run a function */
$.map(components, function(cmp, idx) {
var ranID = randomId();
/* Creating nodes is easy with jQuery
|| You can actually assign a string to a
|| jQuery object and when used with a jQuery method
|| it would be parsed into real HTML
*/
var li = $('<li class="col-12"></li>');
$('.list').append(li);
/* This string is a Template Literal. a TL is a
|| string with a powerful syntax.
*/
var btn = $(`<button id='${ranID}' class='btn' type='button'>${cmp}</button>`);
btn.appendTo(li);
});
/* Originally the OP has a dynamically generated
|| id as the 'this', that's wrong and pointless.
|| That second parameter should be a class ex. '.btn'
*/
$('.list').on("click", '.btn', function(e) {
var ID = $(this)[0].id;
$(`<label for="${ID}"> ${ID}</label>`).insertAfter($(this));
console.log(ID);
alert(`ID:${ID} Type: ${this.textContent}`);
});
function randomId() {
return "id" + Math.floor(Math.random() * 100000) + "_" + Math.floor(Math.random() * 100000);
}
<ol class='list'></ol>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Related

Converting HTML Script Functions to React JS

In my react web, I have a script tag with functions inside shown below (like: clicking on button changing class name and so on...). I want to know how to convert the functions inside the script tag to React JS. Please Help Thank you!
/* tab */
function tab(e, num) {
var num = num || 0;
var menu = $(e).children();
var con = $(e + "_con").children();
var select = $(menu).eq(num);
var i = num;
select.addClass("on");
con.eq(num).show();
menu.click(function () {
if (select !== null) {
select.removeClass("on");
con.eq(i).hide();
}
select = $(this);
i = $(this).index();
select.addClass("on");
con.eq(i).show();
});
}
/* Function */
$(function () {
/* tab */
tab("#tab", 0);
tab("#tab_bg", 0);
/* 기본 배경 click */
$(".btn_bg").on("click", function () {
$(".btn_bg.on")
.find("img")
.attr(
"src",
$(".btn_bg.on")
.find("img")
.attr("src")
.replace("_on.svg", "_off.svg")
);
$(".btn_bg").removeClass("on");
var thisImg = $(this).find("img");
thisImg.attr(
"src",
thisImg.attr("src").replace("_off.svg", "_on.svg")
);
$(this).addClass("on");
});
as I can see your code is mostly jquery based, wich have no sense to migrate.. in any case you can refactorize your code to a react version

Jquery dropdown change value not working

I have a dropdown list i want to change the view on jquery change events
Html code is
<select id="pu_viewToLoad" class="select-dark" name="viewToLoad"></select>
Js code
$("#pu_viewToLoad").change(function(evt) {
evt.preventDefault();
var index = parseInt($("#pu_viewToLoad option:selected").val(), 10);
if (index >= 1000) {
index -= 1000;
console.log("Changing to 2D view: " + _views2D[index].name);
switchSheet();
loadView(_viewerSecondary, _views2D[index]);
}
else {
console.log("Changing to 3D view: " + _views3D[index].name);
switchSheet();
loadView(_viewerSecondary, _views3D[index]);
}
});
This function is not executing
You should either use:
var index = parseInt($("#pu_viewToLoad option:selected").attr("value"), 10);
Or
var index = parseInt($(this).val(), 10);
Please change accordingly. And make sure you are running the above function inside the $(document).ready() function.

jQuery getting ID of clicked link

I have a modal box in jQuery which I have created to display some embed code. I want the script to take the id of the link that is clicked but I can't seem to get this working.
Does anyone know how I can do that or why this may be happening?
My jQuery code is:
function generateCode() {
var answerid = $('.openembed').attr('id');
if($('#embed input[name="comments"]:checked').length > 0 == true) {
var comments = "&comments=1";
} else {
var comments = "";
}
$("#embedcode").html('<code><iframe src="embed.php?answerid=' + answerid + comments + '" width="550" height="' + $('#embed input[name="size"]').val() + '" frameborder="0"></iframe></code>');
}
$(document).ready(function () {
$('.openembed').click(function () {
generateCode();
var answerid = $('.openembed').attr('id');
$('#box').show();
return false;
});
$('#embed').click(function (e) {
e.stopPropagation()
});
$(document).click(function () {
$('#box').hide()
});
});
My mark-up is:
Embed
Embed
Your problem is here:
$('.openembed')
returns an array of matched elements. Your should instead select only the clicked element.
$('.openembed') works correctly if you assing a click event to all elements that have this class. But on the other hand, you're unable do know which is clicked.
But fortunately in the body of handler function click you could call $(this).
$(this) will return the current (and clicked element).
// var answerid = $('.openembed').attr('id'); // Wrong
var answerid = $(this).attr('id'); // Correct
// Now you can call generateCode
generateCode(answerid);
Another error is the body of generateCode function. Here you should pass the id of selected element. This is the correct implementation.
function generateCode(answerid) {
if($('#embed input[name="comments"]:checked').length > 0 == true) {
var comments = "&comments=1";
} else {
var comments = "";
}
$("#embedcode").html('<iframe src="embed.php?answerid=' + answerid + comments + '" width="550" height="' + $('#embed input[name="size"]').val() + '"frameborder="0"></iframe>');
}
Here I have implemented your code with the correct behavior: http://jsfiddle.net/pSZZF/2/
Instead of referencing the class, which will grab all members of that class, you need to reference $(this) so you can get that unique link when it is clicked.
var answerid = $(this).prop('id');
$('.openembed').click(function () {
generateCode();
var answerid = $(this).attr('id');
$('#box').show();
return false;
});
Use $(this). $('.openembed') refers to multiple links.
var answerid = $('.openembed').attr('id');
needs to be
var answerid = $(this).prop('id');
The other answers are trying to fix the click() function, but your issue is actually with the generateCode function.
You need to pass the clicked element to the generateCode function:
$('.openembed').click(function () {
generateCode(this);
And modify generateCode:
function generateCode(element) {
var answerid = element.id;
Of course var answerid = $('.openembed').attr('id'); within the click code isn't correct either, but it doesn't seem to do anything anyway.
Get the id when the correct anchor is clicked and pass it into your generateCode function
$('.openembed').click(function () {
var answerid = $(this).attr('id');
generateCode(answerid)
$('#box').show();
return false;
});
Change your function
function generateCode(answerid) {
// dont need this line anymore
// var answerid = $('.openembed').attr('id');

How to get jQuery placeholder/watermark plugin to work for ajax loaded text fields?

I'm using the following placeholder plugin
(function($){
var ph = "PLACEHOLDER-INPUT";
var phl = "PLACEHOLDER-LABEL";
var boundEvents = false;
var default_options = {
labelClass: 'placeholder'
};
//check for native support for placeholder attribute, if so stub methods and return
var input = document.createElement("input");
if ('placeholder' in input) {
$.fn.placeholder = $.fn.unplaceholder = function(){}; //empty function
delete input; //cleanup IE memory
return;
};
delete input;
//bind to resize to fix placeholders when the page resizes (fields are hidden/displayed, which can change positioning).
$(window).resize(checkResize);
$.fn.placeholder = function(options) {
bindEvents();
var opts = $.extend(default_options, options)
this.each(function(){
var rnd=Math.random().toString(32).replace(/\./,'')
,input=$(this)
,label=$('<label style="position:absolute;display:none;top:0;left:0;"></label>');
if (!input.attr('placeholder') || input.data(ph) === ph) return; //already watermarked
//make sure the input tag has an ID assigned, if not, assign one.
if (!input.attr('id')) input.attr('id', 'input_' + rnd);
label .attr('id',input.attr('id') + "_placeholder")
.data(ph, '#' + input.attr('id')) //reference to the input tag
.attr('for',input.attr('id'))
.addClass(opts.labelClass)
.addClass(opts.labelClass + '-for-' + this.tagName.toLowerCase()) //ex: watermark-for-textarea
.addClass(phl)
.text(input.attr('placeholder'));
input
.data(phl, '#' + label.attr('id')) //set a reference to the label
.data(ph,ph) //set that the field is watermarked
.addClass(ph) //add the watermark class
.after(label) //add the label field to the page
//setup overlay
itemFocus.call(this);
itemBlur.call(this);
});
};
$.fn.unplaceholder = function(){
this.each(function(){
var input=$(this),
label=$(input.data(phl));
if (input.data(ph) !== ph) return;
label.remove();
input.removeData(ph).removeData(phl).removeClass(ph).unbind('change',itemChange);
});
};
function bindEvents() {
if (boundEvents) return;
//prepare live bindings if not already done.
$("form").live('reset', function(){
$(this).find('.' + ph).each(itemBlur);
});
$('.' + ph)
.live('keydown',itemFocus)
.live('mousedown',itemFocus)
.live('mouseup',itemFocus)
.live('mouseclick',itemFocus)
.live('focus',itemFocus)
.live('focusin',itemFocus)
.live('blur',itemBlur)
.live('focusout',itemBlur)
.live('change',itemChange);
;
$('.' + phl)
.live('click', function() { $($(this).data(ph)).focus(); })
.live('mouseup', function() { $($(this).data(ph)).focus(); });
bound = true;
boundEvents = true;
};
function itemChange() {
var input = $(this);
if (!!input.val()) {
$(input.data(phl)).hide();
return;
}
if (input.data(ph+'FOCUSED') != 1) {
showPHL(input);
}
}
function itemFocus() {
$($(this).data(ph+'FOCUSED',1).data(phl)).hide();
};
function itemBlur() {
var that = this;
showPHL($(this).removeData(ph+'FOCUSED'));
//use timeout to let other validators/formatters directly bound to blur/focusout work
setTimeout(function(){
var input = $(that);
//if the item wasn't refocused, test the item
if (input.data(ph+'FOCUSED') != 1) {
showPHL(input);
}
}, 200);
};
function showPHL(input, forced) {
var label = $(input.data(phl));
//if not already shown, and needs to be, show it.
if ((forced || label.css('display') == 'none') && !input.val())
label
.text(input.attr('placeholder'))
.css('top', input.position().top + 'px')
.css('left', input.position().left + 'px')
.css('display', 'block');
//console.dir({ 'input': { 'id':input.attr('id'), 'pos': input.position() }});
}
var cr;
function checkResize() {
if (cr) window.clearTimeout(cr);
cr = window.setTimeout(checkResize2, 50);
}
function checkResize2() {
$('.' + ph).each(function(){
var input = $(this);
var focused = $(this).data(ph+'FOCUSED');
if (!focused) showPHL(input, true);
});
}
}(jQuery));
It applies the placeholder attribute to form fields in browsers that do not natively support the placeholder attribute (ex. IE9). It works for statically loaded text fields, however for text fields that are loaded via ajax, the placeholder does not appear.
Is it possible to achieve this 'watermark' effect on text fields that are loaded via ajax?
What happens if you trigger the window resize function after adding in new inputs?
$(window).trigger('resize')
You could apply the plugin to newly created controls after the AJAX call completes. Forgive the pseudo-code as I'm not really sure about how your AJAX calls are working:
$.ajax({
url: "test.html",
cache: false
}).done(function( result ) {
field = $('<input>').html(result);
$("#results").append(field);
field.placeholder();
});
Another option is that you could use jQuery's .on() method to bind dynamically created controls to the function--but it wants an event (like click). I'm not sure how you would do that. Maybe something like this:
$( 'body' ).on('click','input.addField', function(e){
$(this).placeholder();
});
I know this won't work, but maybe it helps get you brainstorm solutions.

Using a loop variable inside a function, javascript scoping confusion

I have built a dropdown menu system, everything works when tested independently, the problem I have is in the code below. I use the jQuery ready function to build the menu bar from an external array (menubar[]). Here I am trying to get the mouseover event to call the dropdown() function, but using a different argument for each anchor tag.
So rolling over the first should call dropdown(0), the second dropdown(1) and so on.
$(document).ready(function () {
for (i in menubar) {
var declaration = '<a href="' + baseurl + '/' + menubar[i].url +
'" class="menutitle">' + menubar[i].name + '</a>';
var a = $(declaration).mouseover(function () {
dropdown(i);
}).mouseout(function () {
activeTimer = setTimeout("removedropdowns()", 100);
});
$("#menu").append(a);
}
});
The code is calling dropdown(6); on each rollover. How can I pass the loop variable (i) into the mouseover function as a literal/static value!
I got this working fine in FF by using
.attr('onMouseOver','javascript:dropdown('+i+');')
but that wasn't firing for some versions of IE, so I switched to the jQuery mouseover, which fires, but I have the issue above :(
Your actual problem is that each of your mouseover callbacks uses the same i you increase i all the way up to 6, the callbacks still point to the same i and therefore all use 6 as the value.
You need to make a copy of the value of i, you can do this by using an anonymous function.
$(document).ready(function () {
// you should use (for(var i = 0, l = menubar.length; i < l; i++) here in case menubar is an array
for (var i in menubar) {
var declaration = '<a href="' + baseurl + '/' + menubar[i].url +
'" class="menutitle">' + menubar[i].name + '</a>';
(function(e) { // e is a new local variable for each callback
var a = $(declaration).mouseover(function () {
dropdown(e);
}).mouseout(function () {
activeTimer = setTimeout(removedropdowns, 100); // don't use strings for setTimeout, since that calls eval
});
$("#menu").append(a);
})(i); // pass in the value of i
}
});
$(function() {
$(menubar).each(function(i){
$("#menu").append('' + menubar[i].name + '');
});
$("#menu a").hover(
function(){
dropdown($(this).index());
},
function(){
activeTimer = setTimeout("removedropdowns()", 100);
}
);
});
First, don't use for..in but rather ordinary loop.
Second, I would just append the links first then apply the events later:
$(document).ready(function() {
for (var i = 0; i < menubar.length; i++) {
$("#menu").append('' + menubar[i].name + '');
}
$("#menu a").each(function(index) {
$(this).mouseover(function() { dropdown(index); }).mouseout(function() { activeTimer = setTimeout("removedropdowns()", 100); });
});
});
Have a look here and here.
To capture the current value of i, you need to pass it as a parameter to another function where it can be captured as a local variable:
Try using jQuery's each() function:
jQuery(function() {
jQuery.each(menubar, function(index, element) {
var declaration = '' + element.name + '';
var a = $(declaration).mouseover(function() { dropdown(index); }).mouseout(function() { activeTimer = setTimeout("removedropdowns()", 100); });
$("#menu").append(a);
});
});
In JavaScript, if you don't declare your variable, it is defined globally. To fix this, add "var" in front of your i looping variable like this. UPDATE: As Sime noticed (see comment), you also need to pass the variable into the function, otherwise you form a closure on the i.
$(document).ready(function() {
for(var i in menubar) {
var declaration = '' + menubar[i].name + '';
var a = $(declaration).mouseover(function(i) { dropdown(i); }).mouseout(function() { activeTimer = setTimeout("removedropdowns()", 100); });
$("#menu").append(a);
}
});

Categories