Prevent default function using only child pseudo selectors - javascript

I am using jQuery to dynamically add elements every time a user clicks a link (".add-event"). Also included in this element is a icon to remove the entire element if the user chooses. I want to hide or disable this remove icon if the element is the last left on the page. This is what I have tried so far:
$(document).on('click','.close_box2:only-child',function(){
event.preventDefault();
});
AND
if( $('.event').length===1) {
$('.close_box2').hide()
}
HTML:
<div class="event">
<span class="close_box2"><i class="icon-remove"></i></span>
<span class="add-event">Add Event</span>
</div>
What am I doing wrong!? Thanks

JSFiddle: http://jsfiddle.net/TrueBlueAussie/KPY9r/6/
You just want to check for the "last one" inside the delete handler:
// initial hide of sole close button
$('.close_box2').hide();
// On add, clone the template and show all close buttons
$(document).on('click', '.add-event', function () {
// Create a new event based on the template
$('#events').append($('#template').html());
// Show all close buttons (as we must now have > 1 event)
$('.close_box2').show();
});
$(document).on('click', '.close_box2', function (e) {
$(this).closest('.event').remove();
// Is there only one left?
if ($('.event').length === 1) {
// Hide the close box on the last event
$('.close_box2').hide()
}
});
Notes:
I use a dummy <script> element to hold you HTML template. This is better than cloning an element on the page and much better than inline HTML strings in your code.

The following looks better regarding performance:
$('.close_box2:only-child').on('click', function(event){
event.preventDefault();
});

Related

Dynamic data opens only first element in the row

I have some data fetched and they all have the same buttons for opening modal, but each modal should have content about that specific item that has been clicked.
Button is shown on all items in the row, but when I click it it opens modal only on the first item in the row.
I have simple button in HTML
// this is part of fetched items in a row, each item has this button
<div>
<button id="openUniqueModal">
BUTTON
</button>
</div>
And open function in JS
let openUniqueModalBtn = document.getElementById('openUniqueModal');
if (openUniqueModalBtn != null) {
document.getElementById(
'openUniqueModal'
).onclick = function () {
modal.style.display = 'block';
};
.....
.....
How can I achieve that each button item in row will get triggered onclick? Do I have to loop through it in JS code?
EDIT:
another approach
<button class="openUniqueModal">BUTTON</button>
document
.querySelectorAll('.openUniqueModal')
.addEventListener('click', (event) => {
myModal.style.display = 'block';
});
You don't need to attach event listener to every button instead you can use add a common class to add buttons and then add listener just once
document.querySelector('.btn').addEventListener('click', (event) => {
// you can check button id and take different actions if needed
// event.target.id
});
you can use Zohaib Ijaz's answer and you can even add a wild card if you want to the '.btn' phrase.
[id^='openUniqueModal'] will match all ids starting with openUniqueModal.
[id$='openUniqueModal'] will match all ids ending with openUniqueModal.
[id*='openUniqueModal'] will match all ids containing openUniqueModal.
Please don't use duplicate ids on elements. as button 'openUniqueModal' will be duplicated in your dom for each row as there will be no increment on the id.
Having elements with the same id will cause lots of problems when it comes to industrial.
if you're using jquery you use the below function,
$( "#openUniqueModal" ).on( "click", function() {
// your desired functionality here
// use $( this ) to access current element
});
*I would've added this as a comment in Zohaib Ijaz's answer but I don't have enough permission.

Trying to add EventListener to dynamically created object

I am attemping to load HTML from an external file. However upon doing so the input elements are non-interactable. I have tried this using vanilla JavaScript to no avail and just imported jQuery. My current progress is as follows:
I have a page with a static element and a menu bar. When clicking on the menu bars icons the elements content gets updated through JS/JQ. This is my HTML and jQuery for loading the view:
settings.html:
<section class="settings">
<div class="container">
# some elements here
<div id="graph-settings" class="settings-card">
<i class="fa fa-chart-line fa-3x"></i><h1>Graph Settings</h1>
<p>Web Interface Refresh Rate</p>
<form>
<input type="text" name="graphInterval" id="graphInterval" placeholder="E.g. 2000">
</form>
</div>
# more elements here
</div>
</section>
jQuery:
$.get("./pages/settings.html", (data) => {
$("#main").append(data);
});
$(document).on("click", "#graphInterval", function() {
// do something...
console.log("test");
});
The content seems to be loaded correctly into the page but is not markable/interactable (dynamically added to DOM etc.). However my jQuery does not seem to find the #graphInterval element as I get no logged output from the console.
Any way to get the input fields working would be a solution. All they're needed for is to edit and retrieve it's value. I will use JavaScript to add/interact with buttons later on, no posting forms will be used, hence why the form has no "action=''".
If you use event delegation (where you set the event listener at a high level DOM object and let all events triggered from decedents of that high level element bubble up to the high level element, any new elements added in will trigger events caught higher up. Then, in the listener, you can check to see which element actually triggered the event and act accordingly. So, in your case, remove the id from the .on() method call and then check the event.target inside the listener:
// Set the event listener on a high level element and capture the event
$(document).on("click", function(event) {
// You can find out what exact element triggered the event with event.target
console.log("event triggered by: " + event.target);
// Now you can proceed as you need to:
if(event.target.id === "heading1"){
console.log("You clicked the heading");
} else if(event.target.id === "para1"){
console.log("You clicked the paragraph");
}
});
// Create new elements
let data1 = "<h1 id='heading1'>Some new data (click me)</h1>";
let data2 = "<p id='para1'>Some new data (click me)</p>";
// Dynamically add elements to document
$(document.body).append(data1);
$(document.body).append(data2);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

jQuery .html() not setting html at all

I have a simple thing. When a user clicks on the edit link it turns the previous element into an input element for editing and the edit into a cancel. If the user decides not to edit he can click on cancel and everything should revert to its initial state.
Right now this is not working at all:
$('.cancel').on('click', function() {
$(this).parent().html("<a href='#'>edit</a>");
});
HTML:
<div class='photo-section'>
<div class='photo-head'>
<div class='photo-info'>
Photo Name : <span class='photo-name'>Work selfie</span>
<span class='title-edit'><a href='#'>edit</a></span>
</div>
</div>
<div class='photo'>
<img src='' alt='' title=''>
</div>
<div class='tag-section'>
<div class='tags'>Photo Tags:
<span>#code#coffee#late#night</span>
<span class="tags-edit">edit</span>
</div>
</div>
</div>
CSS:
// JavaScript to handle photo operations
$(document).ready(function() {
// show/hide edit option
$('.photo-info, .tags').hover(function() {
$(this).find('.title-edit > a, .tags-edit > a').addClass('visible');
}, function() {
$(this).find('.title-edit > a, .tags-edit > a').removeClass('visible');
});
// show editable area
$('.title-edit, .tags-edit').on('click', function () {
edit(this);
});
});
function edit(elem) {
// change element into an input elemnt for editing
var $item = $(elem).prev();
var text = $item.text();
$item.html("<input type='text'>").find('input').attr('value', text);
// change edit to cancel if input element present
if ($('input').length) {
$item.next().html("<a href='#' class='cancel'>cancel</a>");
}
// change cancel back to edit
if ($('.cancel').length) {
$('.cancel').on('click', function() {
$(this).parent().html("<a href='#'>edit</a>");
});
}
}
Result: https://jsfiddle.net/hgwkxygz/6/
Any help would be great!
This is a very common case of attaching event at wrong time in javascript.
Actually you are removing and re-adding a DOM element. So the already attached event to .cancel won't work this time. You again have to write event listener on .cancel whenever you attach a new DOM element after clicking on edit button.
Basically it means whenever you do .html(), you have to re-add event listener for click.
There are various approach to solve this problem.
1) make a function which attach the DOM element as well as click event to that DOM element. Call that function only on click events.
2)Do event delegation.
3)Do not remove DOM elements on click events, rather hide and show elements so that you wont loose your event listeners.
4)If you really have to do remove and re-add DOM elements then in my opinion, best approach is to make a class, where you make DOM elements, add event listeners privately in that class, and on click events just make new instance of that class.
You can check out these options in detail on web.

Toggling if a condition is met on table elements

I have a table. Each column has a button at the top. If the td elements below within the column have content in them, then hide the button. If not then display the button and onClick add class active too the td element.
$(document).ready(function (){
$('.button-fill').on("click", function() {
var i=$(this).parent().index();
if($(this).closest("tr").siblings().find("td:eq("+i+")").text()=="")
$(this).hide();
else
$(this).show();
});
<!-- Fill in the td -->
$('.button-fill').on("click", function() {
var i=$(this).parent().index();
$(this).closest("tr").siblings().find("td:eq("+i+")").addClass("active");
//});
});
});
http://jsfiddle.net/ujw0u6au/
I've created a jsfiddle. I don't know what i'm doing wrong? Thank you
Since you have bind the button toggle logic inside button click - you will always have the button in the starting. When you will click on the button only then it will first hide the button and then make the content active.
In case you want this behavior in the starting as soon as the page loads, you should change below line (the 2nd line in your code) from your code -
$('.button-fill').on("click", function() {
to
$('.button-fill').each( function(i,e) {
also, you should not use <!-- Fill in the td --> style of commenting in JavaScript.
I can see you are having two "click" event handler on same class. Instead of it, you can merge it as well.
Here is the optimized version of your code :
JavaScript :
$(document).ready(function (){
$('.button-fill').on("click", function() { //Only one click event handler
var $this = $(this);
var i=$this.parent().index();
var $trSibling = $this.closest("tr").siblings();
$this.toggle($trSibling.find("td:eq("+i+")").addClass("active").text() != ""); //adds the class as well and check the text as well.
})
$(".button-fill").trigger("click");
// explicitly clicking on button to make sure that initially button should not be shown if column text is not empty
});
JSFiddle link : http://jsfiddle.net/ujw0u6au/1/
Is this the same what you want?
#Vijay has the right answer, but as a side note, you need to change this:
if($(this).closest("tr").siblings().find("td:eq("+i+")").text()=="")
to this
if($(this).closest("tr").siblings().find("td:eq("+i+")").text()!="")
if you want to hide the button when there is content, instead of the other way around (notice the != near the end).

how to make the menu close if it is clicked out

i have an menu with some values and i got someting hidden and while click on more button it shows like google more menu... if it is clicked out it is not hiding till the more menu is clicked once again
More<small>▼</small><div class="more list" id="one" style="display:none">test <span style="color:#329">|</span> test1 <span style="color:#169">|</span> test4</div></div>
Script:
function toggle(one)
{
var o=document.getElementById(one);
o.style.display=(o.style.display=='none')?'block':'none';
}
how to make it close while the mosuse clicks on any other place other than the menus
Try using the onblur event.
I see you've tagged this with jQuery, if that is an option, you can clear up the link a bit, like this:
More<small>▼</small>
And use unobtrusive script combined with event bubbling to your advantage, like this:
$(function() {
$(".more_link").click(function(e) {
$(this).next(".more").toggle();
e.stopPropagation();
});​​
$(".more").click(function(e) {
e.stopPropagation();
});
$(document).click(function() {
$(".more").hide();
});​
});
You can test it out here, this only closes the menu if you clicked neither the menu of the toggle, e.g. clicking one of the test links will not close it. If you want it to, just remove the $(".more").click(function(e) { e.stopPropagation(); }); portion.
It uses event.stopPropagation() to stop the click from bubbling up to document, which if happens (and would if you clicked anything else) triggers its click handler, closing all the .more elements.
I wouldn't use onBlur because it's not a good accessibility approach (for example if the user is using tab to navigate the page).
Look at this solution instead:
jQuery click event for document but ignore a div
Typically, I let the event bubble up to the 'body' or 'html' doc and check if the target is what i want (and/or isn't contained within what i want). If the event target is not contained within your menu, then perform your desired operation (in this case, hide the div).
i.e.
jQuery(document).ready(function(){
jQuery("html").bind("click", function(evt){
var $target = jQuery(evt.target);
var shouldShowMenu = $target.hasClass("menu_toggle");
shouldShowMenu |= $target.parents(".menu_toggle, .more_list").length;
if(!shouldShowMenu)jQuery(".more_list").hide();
});
});
NOTE: your markup would needs to be extended such that the "more" href becomes has a class attribute, class="menu_toggle"

Categories