I am trying to show a div with JavaScript, but as the title says, it is taking 2 clicks to show.
Here's the code I am using, and the JS is being called with a <script> tag on the same file:
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<div id="mobile-search" class="mobile-search">
<input type="search" name="">
</div>
<button class="search-btn" id="mobile-search-button" onclick="show_search()">
<i class="fa fa-search" aria-hidden="true"></i>
</button>
<style>
.mobile-search {
display: none;
}
</style>
<script type="text/javascript">
var mobile_search = document.getElementById("mobile-search");
function show_search() {
if (mobile_search.style.display === "none") {
mobile_search.style.display = "block";
} else {
mobile_search.style.display = "none";
}
}
</script>
As you can see, it is taking 2 clicks to show the div, and I want it to be only 1. What is going on?
You need to click the button twice because when you click the button for the first time, following condition
mobile_search.style.display === "none"
is false. This is because Element.style property returns CSSStyleDeclaration object which contains a list of styles that are added on the element using the style attribute. In other words, it returns the inline CSS styles set on the element. In your code, since you haven't added the display: none style using inline CSS, initial value of mobile_search.style.display is not what you expect it to be.
So, on first click, the else block executes, setting display to none and when you click for the second time, above mentioned condition evaluates to true and the input element is displayed.
Solution
You have couple of options to solve the problem:
Add display: none as an inline-style on the #mobile-search element.
<div id="mobile-search" class="mobile-search" style="display: none;">
<input type="search" name="" />
</div>
Use Window.getComputedStyle() method to get the value of the display property.
var mobile_search = document.getElementById("mobile-search");
function show_search() {
if (window.getComputedStyle(mobile_search).display === "none") {
mobile_search.style.display = "block";
} else {
mobile_search.style.display = "none";
}
}
.mobile-search {
display: none;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<div id="mobile-search" class="mobile-search">
<input type="search" name="">
</div>
<button class="search-btn" id="mobile-search-button" onclick="show_search()">
<i class="fa fa-search" aria-hidden="true"></i>
</button>
The style property doesn't return styles from CSS. According to your condition when you are clicking the button it's adding display: none, after clicking the second time it's adding display: block, that's why you need to click twice to show the div.
You can try this in two ways.
Step 1: Just toggle block and none on click function
var toggle = document.getElementById("mobile-search-button");
var content = document.getElementById("mobile-search");
toggle.addEventListener("click", function() {
content.style.display = (content.dataset.toggled ^= 1) ? "block" : "none";
});
.mobile-search {
display: none;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<div id="mobile-search" class="mobile-search">
<input type="search" name="">
</div>
<button class="search-btn" id="mobile-search-button">
<i class="fa fa-search" aria-hidden="true"></i>
</button>
Step 2:
You don't need any css, add styles to your input box.
var mobile_search = document.getElementById("mobile-search");
function show_search() {
if (mobile_search.style.display === "none") {
mobile_search.style.display = "block";
} else {
mobile_search.style.display = "none";
}
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<div id="mobile-search" class="mobile-search" style="display: none">
<input type="search" name="">
</div>
<button class="search-btn" id="mobile-search-button" onclick="show_search()">
<i class="fa fa-search" aria-hidden="true"></i>
</button>
Step: Extra
You can do it much more in an easier way. Just toggle class onclick
$("#mobile-search-button").on("click", function(){
$("#mobile-search").toggle();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<div id="mobile-search" class="mobile-search" style="display: none">
<input type="search" name="">
</div>
<button class="search-btn" id="mobile-search-button">
<i class="fa fa-search" aria-hidden="true"></i>
</button>
When you already have a class to hide mobile-search, why not toggle that :
var toggle = document.getElementById("mobile-search-button");
var classes = document.getElementById("mobile-search").classList;
toggle.addEventListener("click", function() {
classes.contains("mobile-search") ? classes.remove("mobile-search") : classes.add("mobile-search");
});
.mobile-search {
display: none;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<div id="mobile-search" class="mobile-search">
<input type="search" name="">
</div>
<button class="search-btn" id="mobile-search-button">
<i class="fa fa-search" aria-hidden="true"></i>
</button>
Related
Here's what I'm trying to do here -
Take input from a form field and append the data in a div option-badges
The badges have X button that I'm using to remove the items clicked if needed
What's the problem?
With the code I've written, I'm unable to remove the said appended badge while I'm easily able to remove the badges which were there already.
Here's the code. Please help me with this. Thanking in anticipation.
$(document).ready(function() {
//take input data from first input field and display comma separated in second field
let dataList = [];
let dataString = "";
$("#addData").on('click', function() {
let data = $("#firstInput").val();
let dataBadge = '<span class="badge badge-secondary" style="margin-left: 5px;">' +
data + '   <i id="newBadge" class="fa-solid fa-xmark" ></i></span>';
$('.option-badges').append(dataBadge);
$("#firstInput").val('');
})
//remove badge on clicking x
$(".option-badges > span > i").on("click", function() {
$(this).parent().remove();
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.1/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.1/css/bootstrap.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" />
<div class="option-badges">
<span class="badge badge-secondary" style="margin-left: 5px;">data <i class="fa-solid fa-xmark"></i></span>
<span class="badge badge-secondary" style="margin-left: 5px;">data <i class="fa-solid fa-xmark"></i></span>
</div>
-
Try with on off click like
$(document).off('click', '.option-badges > span > i');
$(document).on('click', '.option-badges > span > i', function () {
$(this).parent().remove();
})
$(document).ready(function() {
//take input data from first input field and display comma separated in second field
let dataList = [];
let dataString = "";
$("#addData").on('click', function() {
let data = $("#firstInput").val();
let dataBadge = '<span class="badge badge-secondary" style="margin-left: 5px;">' +
data + '   <i id="newBadge" class="fa-solid fa-xmark" ></i></span>';
$('.option-badges').append(dataBadge);
$("#firstInput").val('');
})
//remove badge on clicking x
$(document).off('click', '.option-badges > span > i');
$(document).on('click', '.option-badges > span > i', function () {
$(this).parent().remove();
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.1/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.1/css/bootstrap.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" />
<div class="option-badges">
<span class="badge badge-secondary" style="margin-left: 5px;">data <i class="fa-solid fa-xmark"></i></span>
<span class="badge badge-secondary" style="margin-left: 5px;">data <i class="fa-solid fa-xmark"></i></span>
</div>
<input id="firstInput" type text />
<a id="addData">ADD </a>
I am trying to trigger a function through a event listener with only one click.
But it occurs after two click (in the first time) if I don't do F5 its trigger after one click.
Code:
HTML
<div class="main-header-navbar">
....
<span class="main-header-navbar-right-icons">
<i class="fas fa-search header-icon"></i>
<i class="fas fa-plus header-icon"></i>
</span>
</div>
JS
const ADD_FORM_BUTTON = document.querySelector(".fa-plus");
ADD_FORM_BUTTON.addEventListener("click", function (event) {
event.preventDefault();
if (ADD_FORM.style.display === "none") {
ADD_FORM.style.display = "flex";
} else ADD_FORM.style.display = "none";
});
What am I missing?
You probably need to add style="display: none;" to your ADD_FORM so that it's initially hidden, then when you click on the fa-plus it will display it. See the snippet below:
const ADD_FORM_BUTTON = document.querySelector(".fa-plus");
const ADD_FORM = document.getElementById("form");
ADD_FORM_BUTTON.addEventListener("click", function(event) {
event.preventDefault();
if (ADD_FORM.style.display === "none") {
ADD_FORM.style.display = "flex";
} else {
ADD_FORM.style.display = "none"
};
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/css/all.min.css" rel="stylesheet" />
<div class="main-header-navbar">
<span class="main-header-navbar-right-icons">
<i class="fas fa-search header-icon"></i>
<i class="fas fa-plus header-icon"></i>
</span>
<div id="form" style="display: none;">ADD_FORM</div>
</div>
I have an ul (unordered list) which contains several li (list items) when I click on the + sign left to li, console log should output "description expanded" For the two first li, it works just fine, but not for any other li's. The html code by default includes only 2 li's. any li after that is added through the form. However, any new li does not produce the console log output. Which means they're not responding to clicks. I'm using jQuery to listen for click events. When clicking on the icon.
project link http://pctechtips.org/apps/todo/
//variables
//todoList array to hold (title, description) for every todo tiem
var todoList = []; //{title: "value", desc: "value"},
var numId = 2; //num is for desc paragraph id eg <p id="plus-3">
/*
* Script main body
*/
$(document).ready(function() {
//hide form when doc loads first time
$("#submit-form").hide();
//hide list item description <p>
$(".item-desc").hide();
//listener for show hide form functionality
$("#add-todo").click(function() {
toggleForm();
return false; //return false to prevent page reload
});
//listener for add new item form (submit button)
$(".btn").click(function() {
console.log("submit item");
addToList();
});
//listener for expanding li description
$(".plus").click(function() {
console.log("description expanded")
var plusId = $(this).attr("id"); //grabbing id of plus sign
showDescription(plusId);
return false;
});
});
//functionality for show / hide form
function toggleForm() {
if($("#submit-form").is(":hidden")) {
console.log("form exapnded");
$("#submit-form").show("slow");
$("#form-icon").removeClass("fa-plus-square-o");
$("#form-icon").addClass("fa-minus-square-o");
}
else {
console.log("form hidden");
$("#submit-form").hide("slow");
$("#form-icon").removeClass("fa-minus-square-o");
$("#form-icon").addClass("fa-plus-square-o");
}
}
//add new item to todo list items
function addToList() {
numId++;
//getting data from input fields
var todoTitle = $("#todo-title").val();
var todoDesc = $("#todo-desc").val();
//checking user input
if(todoTitle == "" || todoDesc == "") {
alert("fill in all fields!");
}
else {
console.log(todoTitle + "\n" + todoDesc);
//adding values to array
todoList.push({title: todoTitle, desc: todoDesc},);
//adding new li to ul
var ul = document.getElementById("list");
var li = document.createElement("li");
$(li).addClass("list-group-item justify-content-between align-items-center");
$(li).append(($('<i id="plus-'+numId+'" class="plus fa fa-plus-square-o left" aria-hidden="true"></i>')));
$(li).append(($('<span class="left marg-left">'+todoTitle+'</span>')));
$(li).append(($('<i class="fa fa-trash-o right" aria-hidden="true"></i>')));
$(li).append(($('<i class="fa fa-pencil right marg-right pr-2" aria-hidden="true"></i>')));
ul.appendChild(li);
}
}
//expanding description under for each todo
function showDescription(plusId) {
//getting the number from id
var num = plusId.substring(plusId.indexOf("-")+1);
//checking for hide / show description paragraph
if($("#desc-"+num).is(":hidden")) {
$("#desc-"+num).show("slow");
$("#desc-"+num).removeClass("fa-plus-square-o");
$("#desc-"+num).addClass("fa-minus-square-o");
}
else {
$("#desc-"+num).hide("slow");
$("#desc-"+num).removeClass("fa-minus-square-o");
$("#desc-"+num).addClass("fa-plus-square-o");
}
}
index.html
<!DOCTYPE html>
<html>
<head>
<title>TodoList App</title>
<!-- bootstrap, fontawsome cdn -->
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<!-- local stylesheet -->
<link rel="stylesheet" type="text/css" href="css/style.css">
<!-- jquery cdn -->
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<!-- local javascript -->
<script type="text/javascript" src="js/todo.js"></script>
</head>
<body>
<!-- navbar -->
<nav class="navbar navbar-expand-lg navbar-drak bg-dark mb-4">
<a class="navbar-brand" href="#"><i class="fa fa-thumb-tack" aria-hidden="true"></i> Todo<strong>List</strong></a>
</nav>
<!-- /navbar -->
<!-- todoList -->
<div class="container">
<div class="add-item text-white text-center col-sm-12 col-md-10 col-lg-8 mb-4">
<a id="add-todo" class="new-todo text-white text-center" href=""><i id="form-icon" class="fa fa-plus-square-o" aria-hidden="true"></i> Enter new todo item</a>
<div id="submit-form" class="form-hide text-center col-sm-12 col-md-12 col-lg-8">
<form class="">
<div class="form-group">
<input type="text" class="form-control" id="todo-title" placeholder="Todo Title" value="Pay Car Insurance">
</div>
<div class="form-group">
<input type="text" class="form-control" id="todo-desc" placeholder="Todo Description" value="This is to pay car insurance">
</div>
<button type="button" class="btn btn-primary btn-lg col-12">Submit Todo</button>
</form>
</div>
<!-- horizontal line -->
<hr>
<!-- list items -->
<h1 class="heading-4">Todo List Items</h1>
<ul id="list" class="list-group mt-4 pb-4">
<li class="list-group-item justify-content-between align-items-center">
<i id="plus-1" class="plus fa fa-plus-square-o left" aria-hidden="true"></i>
<span class="left marg-left">Pay Car Insurance </span>
<i class="fa fa-trash-o right" aria-hidden="true"></i>
<i class="fa fa-pencil right marg-right pr-2" aria-hidden="true"></i>
</li>
<p id="desc-1" class="item-desc bg-white">Helloooooooooo this is description</p>
<li class="list-group-item justify-content-between align-items-center">
<i id="plus-2" class="plus fa fa-plus-square-o left" aria-hidden="true"></i>
<span class="left marg-left">Pay Car Insurance </span><i class="fa fa-trash-o right" aria-hidden="true"></i>
<i class="fa fa-pencil right marg-right pr-2" aria-hidden="true"></i>
</li>
<p id="desc-2" class="item-desc bg-white">Helloooooooooo this is description</p>
</ul>
</div>
</div>
</body>
</html>
ok for dynamically added elements the even listener needs to be defined at the root / document level. so
$("class").on("click", function() { });
will not work. It needs to be
$(document).on("click", ".class", function() { });
Thanks to "MADDY BLACKLISTED" above pointed me in right directions
Use
$(document).on("click", ".plus", function() {
console.log("description expanded")
var plusId = $(this).attr("id"); //grabbing id of plus sign
showDescription(plusId);
return false;
});
Instead of having a static click listener defined at document load.
I'd like to just simply update the tooltip each time on hover before display. I have a warning icon that pops up if there's been an error, and on hover I'd like the most recent error to show up. What I have doesn't work, though.
HTML Snippet
<div id="title">App</div>
<button id="warningbtn" type="button" class="btn-default btn-sm"
data-toggle="errortip" data-placement="right" title="">
<span class="glyphicon glyphicon-warning-sign"></span>
</button>
JavaScript/JQuery:
function start(){
let result = addon.start();
if (result == -1){
recentError = "Your license is invalid.";
}
}
$(document).ready(function(){
$('[data-toggle="errortip"]').tooltip({
trigger : 'hover',
title: errorVariable
});
Start is called from a simple start button on the page. recentError is declared at the top of the .js file.
Thanks for the help!
You can set this attribute whenever you will need a new value for the tooltip:
$('#warningbtn').attr('data-original-title','something else');
There is an issue reported here, and it seems to be a problem with setting the tooltip title dynamically
https://github.com/twbs/bootstrap/issues/14769
You may use data-original-title attribute on show.bs.tooltip event:
var errorVariable = Date.now() % 100;
$(function () {
$('[data-toggle="errortip"]').tooltip({
trigger : 'hover',
title: errorVariable
}).on('show.bs.tooltip', function(e) {
$(this).attr('data-original-title', errorVariable);
});
$('#myBtn').on('click', function(e) {
errorVariable = Date.now() % 100;
});
});
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<button type="button" class="btn-default btn-sm" id="myBtn">Click Me to create a random tooltip message</button>
<div id="title">App</div>
<button id="warningbtn" type="button" class="btn-default btn-sm"
data-toggle="errortip" data-placement="right" title="">
<span class="glyphicon glyphicon-warning-sign"></span>
</button>
Try this
$('#warningbtn').on('show.bs.tooltip', function() {
$('#warningbtn').tooltip({
title: errorVariable
})
});
You can use following code. I have updated according to your requirement. :
var recentError;
function start() {
var result = -1;
if (result == -1) {
recentError = "Your license is invalid.";
}
}
$(document).ready(function() {
$('[data-toggle="errortip"]').tooltip({
title : recentError
});
});
start();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.js"></script>
<div id="title">App</div>
<button id="warningbtn" type="button" class="btn-default btn-sm"
data-toggle="errortip" data-placement="right" title="">
<span class="glyphicon glyphicon-warning-sign"></span>
</button>
here is my problem. I need on click to change button icon and on another click to go to original state, like +,- and span description like home/back
i dont know what to do. Pleas help.
Here is html...
<div class="navbar-left left">
<button class="toggle btn mr2 white " >
<i class="fa fa-home fa-2x "></i>
<span class="mobile-hide ">Home</a>
</button>
</div>
and bad js
if ($('.toggle').hasClass('fa fa-home fa-2x')) {
$('.toggle').toggleClass('fa fa-home ').html('<span class="mobile-hide ">Home</a>');
} else($('.toggle').hasClass('fa fa-home ')) {
$('.toggle').toggleClass('fa fa-home fa-2x ').html('<span class="mobile-hide ">Back</a>');
}
toggleMenu();
});
You can
jQuery(function($){
$('.toggle').click(function () {
var $i = $(this).find('i').toggleClass('fa-2x');
$(this).find('span.mobile-hide').html($i.hasClass('fa-2x') ? 'Home' : 'Back')
})
})
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/css/font-awesome.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="navbar-left left">
<button class="toggle btn mr2 white" >
<i class="fa fa-home fa-2x"></i>
<span class="mobile-hide">Home</span>
</button>
</div>
You can only use .hasClass() to check for a single class Name.
In order to check for many class names I guess is better get the class attribute string and check with .indexOf()
if ($('.toggle').attr("class").indexOf('fa fa-home fa-2x') != -1) {
The same happens with toggleClass. You have to break it down:
$('.toggle').toggleClass('fa').toggleClass('fa-home').toggleClass('fa-2x')
You might be able to achieve this effect with the ::after pseudo-element. Just change the content property as appropriate based on some class on the button.
A simplified example:
$(function () {
$('#toggle').click(function () {
$(this).toggleClass('on');
});
});
.icon::after {
content: '+';
}
.text::after {
content: 'Home';
}
.on .icon::after {
content: '-'
}
.on .text::after {
content: 'Back'
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<button id="toggle">
<i class="icon"></i>
<span class="text"></span>
</button>