Can't trigger action after changing element's ID - javascript

I have a show/hide password button, when I click to SHOW the password, it works, but when I try to hide it again it doesn't.
Fiddle: http://jsfiddle.net/vcvgj09z/
<input type="password" id="pass1" value="Now try to hide me">
<i class="fa fa-eye"></i> Show
$("#show-password").on("click",function() {
$(this).html('<i class="fa fa-eye-slash"></i> Hide');
$(this).prop("id","hide-password");
$("#pass1").attr("type","text");
});
$("#hide-password").on("click",function() {
$(this).html('<i class="fa fa-eye"></i> Show');
$(this).prop("id","show-password");
$("#pass1").attr("type","password");
});

As per my comment, the reason why your code is not working is because the element #hide-password is not present in the DOM at runtime, so no click events will be bound to it.
Although you can use .on() to listen to event bubbling, I strongly advise against changing IDs of elements. Instead, you can store the toggle on/off state as a jQuery data object. The advantages of this method is that:
does not rely on changing the markup and event bubbling
stores the toggle state of the password by evaluating and modifying the jQuery data object
allows other elements to manipulate/influence the toggle state
See fiddle here: http://jsfiddle.net/teddyrised/vcvgj09z/10/
$('#toggle-password').click(function() {
// Check state
if(!$(this).data('state') || $(this).data('state') == 0) {
// If the data object "state" is undefined or have a value of 0, convert password to text
// Update HTML and data object
$(this)
.html('<i class="fa fa-eye-slash"></i> Hide')
.data('state', 1);
// Change password to text
$("#pass1").attr('type', 'text');
} else {
// If the data object "state" has a value of 1, convert text to password
// Update HTML and data object
$(this)
.html('<i class="fa fa-eye"></i> Show')
.data('state', 0);
// Change text to password
$("#pass1").attr("type","password");
}
});

Try something like this ...
$("body").on("click", "#show-password", function() {
... and associated ...
$("body").on("click", "#hide-password", function() {
This way when the ID dynamically changes, the on-click's will work.

Your code doesnt work because it does not support the dynamically setted elements.
The correct way to set the events for dynamically added elements is by using $(document).on().
JS:
$(document).on("click", "#show-password", function() {
$(this).html('<i class="fa fa-eye-slash"></i> Hide');
$(this).prop("id","hide-password");
$("#pass1").attr("type","text");
});
$(document).on("click", "#hide-password", function() {
$(this).html('<i class="fa fa-eye"></i> Show');
$(this).prop("id","show-password");
$("#pass1").attr("type","password");
});
Updated jsFiddle

You should use delegate. Because you generated new DOM
$(document).on("click","#show-password",function() {
//....
});
$(document).on("click","#hide-password",function() {
//....
});

Related

jQuery on-click event empty

I'm trying to read an attribute in my JavaScript-Function, so I can then further call a DELETE via AJAX with this attribute, but I already fail with retrieving the attribute by, what appears to me as, random. (jQuery version used for that is 3.2.1)
The "button" to start that chain (also already tried without the href and with href="#"):
UPDATE: Since it appeared as a comment, I indeed have something within the a-tag
<a class="btn btn-light delete-record" href="" data-id="5c25f547d42" title="Delete">
<i class="fa fa-trash"></i>
</a>
My JavaScript:
$(document).ready(function(){
$('.delete-record').on('click', function(e){
$target = $(e.target);
var id = $target.attr('data-id');
if(confirm('Entry with ID ' + id){
//AJAX
}
});
});
During testing with the confirm, I found out that my ID is sometimes set to undefined. Sadly I have no clue how this sometimes works and shows me the ID, and sometimes not.
Is there a solution to make this work with every click and not only about 24 out of the 42?
The issue is that when you click the icon inside the hyperlink, that the event bubbles up to the click handler. Inside the click handler, event.target will then refer to the icon element, which does not have the data-id attribute.
So the solution is to either:
1) Move the click event onto the icon and then make sure the hyperlink does not have any padding or other CSS styles that make the <a> clickable without also clicking the <i>.
2) Or check for which node was clicked inside the event:
var $target = $(e.target);
var id = $target.prop('tagName') === 'I'
? $target.parent().attr('data-id')
: $target.attr('data-id');
if (!id ) {
console.error( $target );
throw new Error( 'cannot find the correct id for target' );
}
else {
var is_correct_id = confirm( 'Entry with ID ' + id );
if ( is_correct_id ) {
//createAjaxCall( 'DELETE', 'somePath', id );
}
}
There are other methods to find the correct parent element, in case one day you change the structure and the icon is not an immediate child of the hyperlink anymore. But I don't use JQuery anymore, so I'll leave searching for the correct syntax for .findParent( 'a[data-id]' ) up to the implementer.
3) Or as you demonstrate, duplicate the id onto the icon. :)
The answer is actually based on Shilly's comment to the question.
Since I indeed got another element within my a-tag, the target was different depending on where I clicked the link/button. As an easy fix for that, I simply appended the ID to the i-tag as well:
<a class="btn btn-light delete-record" href="" data-id="5c25f547d42" title="Delete">
<i class="fa fa-trash" data-id="5c25f547d42"></i>
</a>
Did you tried to href="javascript" and also this could return list of elements so try to put the listener using an id like this
<a class="btn btn-light delete-record" id="deleteButton" href="" data-id="5c25f547d42" title="Delete">
$(document).ready(function(){
$('#deleteButton').on('click', function(e){
e.stopPropagation();
$target = $(e.target);
var id = $target.attr('data-id');
if(confirm('Entry with ID ' + id){
//AJAX
}
});
});
You should change your JS + HTML to this:
HTML
<button class="btn btn-light delete-record"
data-id="5c25f547d42"
title="Delete">
Click me!
</button>
Your problem with using <a> is that you don't stop the defaul behaviour of the <a> tag - which is a link. It's just refreshing the page (if you leave href blank). Changing it to a button is much better, as it's .. well a button in principle.
jQuery
jQuery(document).ready(function($)
{
$('.delete-record').click(function()
{
let id = $(this).attr('data-id');
if (confirm('Entry with ID '+ id)) {
//whatever
}
});
})
You don't need to get the target, just use $(this) to get the clicked element's data-attribute. Then carry on script as normal
You could try specifying the role of the anchor tag to button. Then you won't have to worry about specifying the href as the anchor tag will be treated as button.
https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/button_role
Use event.preventDefault() as first line in your callback function for "click" or you'll be redirected to link or just reloaded.
<a class="btn btn-light delete-record" id="btnDelete" title="Delete">
$(document).ready(function(){
$('#btnDelete').on('click', function(e){
e.stopPropagation();
$target = $(e.target);
var id = $target.attr('data-id');
if(confirm('Entry with ID ' + id){
//AJAX
}
});
});
Or you can try
<a class="btn btn-light delete-record" id="btnDelete" href="javascript:DeleteRecord()" title="Delete">
<script>
function DeleteRecord(){
//Do your code here
}
</script>
Since you are tracking the click you should prevent the default behaviour of the click, so do like this:
$('.delete-record').on('click', function(e){
e.preventDefault();
(...)
});
you don't need to use the target, you can get the data attribute directly.
if you want to use a vanilla js approach:
document.addEventListener("DOMContentLoaded", function () {
//const records = document.querySelectorAll('.delete-record');
Array.from(document.querySelectorAll('.delete-record')).forEach(elem =>{
elem.addEventListener('click', function(e){
//don't do the default link behaviour
e.preventDefault();
const id = this.dataset.id;
console.log('Entry with ID :' + id);
//use your jquery here
});
})
});
<a class="btn btn-light delete-record" href="" data-id="5c215f547d42" title="Delete">link1</a>
<a class="btn btn-light delete-record" href="" data-id="eeee5c1125f547d42" title="Delete">link2</a>
<a class="btn btn-light delete-record" href="" data-id="cccc5c25f431547d42" title="Delete">link3</a>
<a class="btn btn-light delete-record" href="" data-id="bbbbb5c2345f547d42" title="Delete">link4</a>
<a class="btn btn-light delete-record" href="" data-id="111115c25f547d42" title="Delete">link5</a>
Personally i had some problems with data attributes and jQuery so i try to avoid using jquery for that. So you can use this and use the ajax call with the id on the variable.
Have a look on my example, it should cover your problem:
$(document).ready(function(){
// assuming you're adding/removing .delete-record elements you should bind click on body
$('body').on('click', '.delete-record', function(e){
e.preventDefault(); // prevent default action
var id = $(this).attr('data-id') || false; // i removed $target, you don't need it
if( id !== false ){ // if id exists
if(confirm('Entry with ID ' + id){
//AJAX
}
}else{ console.log('id is invalid', id, typeof id); }
});
});
Use jQuery .data() function:
<a class="btn btn-light delete-record"
href=""
data-id="5c25f547d42"
title="Delete">
Delete
</a>
$(document).ready(function () {
$('.delete-record').on('click', function (e) {
$target = $(e.target);
var id = $target.data('id');
if (confirm('Entry with ID ' + id)) {
// AJAX
}
});
});

jQuery Button changes not working

I'm trying to give the button a new content if it's clicked. I also add new classes. That work's perfectly fine on the first click but for some reason the innerhtml ins't changing after clicking a second time on it..
HTML:
<button class="btn btn-warning btn-invisible"><i class="fa fa-eye-slash"></i></button>
jQuery:
$('.btn-invisible').click(function() {
$(this).removeClass('btn-invisible');
$(this).addClass('btn-visible');
$(this).html('<i class="fa fa-eye"></i>');
});
$('.btn-visible').click(function() {
$(this).removeClass('btn-visible');
$(this).addClass('btn-invisible');
$(this).html('<i class="fa fa-eye-slash"></i>');
});
I got this fiddle ready: https://jsfiddle.net/dthee9w6/7/
Would love if someone could help.
You should use 'on' instead of 'click', so that you can play with dynamically added elements.
$('body').on('click','.btn-invisible',function() {
$(this).removeClass('btn-invisible');
$(this).addClass('btn-visible');
$(this).html('<i class="fa fa-eye"></i>');
});
$('body').on('click','.btn-visible',function() {
$(this).removeClass('btn-visible');
$(this).addClass('btn-invisible');
$(this).html('<i class="fa fa-eye-slash"></i>');
});
hope it helps.
Wrap your code in $(function(){}) ,which is $(document).ready(function(){
});, apart from this every thing is fine
There is no need to update the html each time on the click , all you need to do is add and remove neccessary classes.
For the first click, you are removing invisible class and what if one clicked next time, it tries to remove invisible class again which is not there, it throws an error here,you should use toggleClass
$(function() {
$('.btn-invisible').click(function() {
$(this).toggleClass('btn-invisible');
if (!$(this).hasClass('btn-visible')) {
$(this).addClass('btn-visible');
$(this).find('.fa').removeClass('fa-eye-slash').addClass('fa-eye');
}
});
$('.btn-visible').click(function() {
$(this).toggleClass('btn-visible');
if (!$(this).hasClass('btn-invisible')) {
$(this).addClass('btn-invisible');
$(this).find('.fa').removeClass('fa-eye').addClass('fa-eye-slash');
}
});
});
Hope it helps

Bind click event not work in dynamic created elements

I call call ajax and when success i build button elements.
Like this :
...
.done(function(data) {
$('#data-message').empty();
// console.log(data);
$('#total_notification_msg').html(data.total);
$.each(data.data, function(index, value) {
// console.log(value);
var redirectRead = '{{ route("adm1n.message.show", ":id") }}'
redirectRead = redirectRead.replace(":id", value.id);
var pesan = value.message.substr(0,100);
$('#data-message').append('<button id='reply' class='btn btn-default btn-xs' style='margin-top:5px;'>Reply</button>");
});
})
...
But, i can't add click event on #reply button.
I already using on or click event :
$(document).on('click', '#reply', function() {
alert('Reply here');
});
// or this ...
$('#reply').click(function() {
alert('Reply here');
});
But it still not works.
Please help, thank you ^^
You need to use quotes properly when creating elements using string.
$('#data-message').append('<button class="reply btn btn-default btn-xs" style="margin-top:5px;">Reply</button>");
And use Event Delegation using .on() delegated-events approach, when generating elements dynamically
$('#data-message').on('click', '.reply', function() {
alert('Reply here');
});
Since Identifiers must be unique, use class instead.
You need to change two things:
correct quotes.
change id to class.
$('#data-message').append("<button class='btn btn-default btn-xs reply' style='margin-top:5px;'>Reply</button>");
//-----------------change here-----------------------------------^^^^^
Because you are in loop and you are duplicating same ids.
change your event binding to class:
$(document).on('click', '.reply', function() {
alert('Reply here');
});

Toggle change with jQuery

I'd like to change fa-bars to fa-times when menu-button is clicked.
How do I do this with my current code?
$(document).ready(function(){
$('nav.primary').prepend('<div id="menu-button">Menu <i class="fa fa-bars"></i></div>');
$('nav.primary #menu-button').on('click', function(){
var menuItems = $(".menu-header-container");
menuItems.toggle();
});
});
Use .toggleClass()
Add or remove one or more classes from each element in the set of matched elements, depending on either the class's presence or the value of the state argument.
$('nav.primary #menu-button').on('click', function(){
$(this).find('i').toggleClass('fa-bars fa-times')
});
Use $.toggleClass('fa-bars fa-time') (or $.addClass('fa-bars').removeClass('fa-times');
Also I recommend to change event binding to
$(document).on('click', '#menu-button', function(){
You can use toggle with the two classes you wan to change:
$('#menu-button i').toggleClass('fa-bars fa-times');
Try this:
$('nav.primary #menu-button').on('click', function(){
var el = $(this).find('.fa-bars');
el.removeClass('fa-bars').addClass('fa-times');
});

jQuery .click() doesn't fire but console.log shows output

I'm having a problem in my code where I click a DOM-element using JavaScript. The click does not work and I am almost sure it is no dumb programming mistake (always dangerous to say).
After deleting some DOM-elements I want my code to click an element and trigger its onclick event. However this doesn't work. According to my code the event triggers but the event doesn't happen and the click event returns the jQuery object.
HTML:
<div class="castor-tabs">
<div class="castor-tab" data-path="../SiteBuilding/alertbox.js" data-saved="saved" data-editor="5475c897f1900editor">
<span class="castor-filename">alertbox.js</span>
<span class="castor-close"><i class="fa fa-fw fa-times"></i></span>
</div>
<div class="castor-tab" data-path="../SiteBuilding/index.php" data-saved="saved" data-editor="5475c89903e70editor">
<span class="castor-filename">index.php</span>
<span class="castor-close"><i class="fa fa-fw fa-times"></i></span>
</div>
<div class="castor-tab active" data-path="../SiteBuilding/makesite.php" data-saved="saved" data-editor="5475c8997ac77editor">
<span class="castor-filename">makesite.php</span>
<span class="castor-close"><i class="fa fa-fw fa-times"></i></span>
</div>
</div>
JavaScript:
$(".castor-tabs").on("click", ".castor-close", function() {
var tab = $(this).parent();
if(tab.attr("data-saved") == "saved") {
// File is saved
if($(".castor-tab").length > 1) {
// 1 element is 'tab' the other is a second tab
if(tab.next().length > 0) {
// If element is to the right
window.newTab = tab.next();
} else if(tab.prev().length > 0) {
// If element is to the left
window.newTab = tab.prev();
}
} else {
window.newTab = false;
}
var editor = tab.attr("data-editor");
$("#" + editor).remove(); // textarea linked to CodeMirror
$("#" + editor + "editor").remove(); // Huge CodeMirror-element
tab.remove();
if(window.newTab) {
console.log("window.newTab.click()");
console.log(window.newTab.click()); // Simulate click()
}
} else {
// File isn't saved
}
});
The onclick event:
$(".castor-tabs").on("click", ".castor-tab", function() {
$(".castor-tab.active").removeClass("active");
$(this).addClass("active");
var editor = $(this).attr("data-editor");
$(".CodeMirror").hide();
$("#" + editor).show();
});
I saved the element in the window object for a reason. After the code runs and it skips the click-part I still have the DOM-element i want to click saved in the window object. This means I can run
console.log(window.newTab.click());
again. Surprisingly this does click the element and this does activate the click-event. It also returns the DOM-element instead of the jQuery-object.
The image shows in the first two lines the failed click. The third line is my manual input and the fourth line is the successful return value of the click().
I hope you can help me to solve this.
UPDATE
.trigger("click") unfortunately gives the same output..
UPDATE 2
To help you i made the website available on a subdomain. I know many of you hate it if you have to go to a different page but I hope you'll forgive me because in my opinion this cant be solved through JSFiddle.
The link is http://castor.marknijboer.nl.
After clicking some pages to open try closing them and you'll see what i mean.
try adding return false; at the end, when binding .castor-close click event
$(".castor-tabs").on("click", ".castor-close", function() {
var tab = $(this).parent();
if(tab.attr("data-saved") == "saved") {
// File is saved
if($(".castor-tab").length > 1) {
// 1 element is 'tab' the other is a second tab
if(tab.next().length > 0) {
// If element is to the right
window.newTab = tab.next();
} else if(tab.prev().length > 0) {
// If element is to the left
window.newTab = tab.prev();
}
} else {
window.newTab = false;
}
var editor = tab.attr("data-editor");
$("#" + editor).remove(); // textarea linked to CodeMirror
$("#" + editor + "editor").remove(); // Huge CodeMirror-element
tab.remove();
if(window.newTab) {
console.log("window.newTab.click()");
console.log(window.newTab.click()); // Simulate click()
}
} else {
// File isn't saved
}
return false;
});
Instead of simulating a click, why not just pull the click logic out of your click function and just call the javascript function using the arguments that you'll need to perform your business logic?
Your code is working but not able to trigger click event binded to castor-close because i tag is empty. Put some text in it and check
<span class="castor-close"><i class="fa fa-fw fa-times">Click me</i></span>
DEMO
Your click handler has the requirement that the click target should have the class castor-close but when you are calling click via JavaScript you are clicking the parent element instead (.castor-tab), and the click handler doesn't react.

Categories

Resources