So I have got this code for my website, which I built myself and works fine. The thing is, that I want the JavaScript code 'cleaner'. I read that JavaScript was all about not-rewriting code. The problem is that I don't really know how to restructure the dropDownOne through dropDownSeven functions.
Each of the functions corresponds to a particular button, which on click then shows the corresponding information block by applying the class 'show' on it, which only got one property: Display: block;
So to wrap it up: how do I get to rework the code, so that I only need say, one function for all the buttons to click on. If a particular button is clicked, that buttons content should show, and not that from the others.
-No jQuery-
HTML:
<div class="dropdown">
<button onclick="dropDownFour()" class="projectbuttons">
PSD to Bussiness Site (01-2017)
</button>
<div id="dropdownfour" class="dropdown-content">
<!--Content-->
</div>
</div>
JavaScript:
function dropDownOne() {
document.getElementById("dropdownone").classList.toggle("show");
}
function dropDownTwo() {
document.getElementById("dropdowntwo").classList.toggle("show");
}
function dropDownThree() {
document.getElementById("dropdownthree").classList.toggle("show");
}
function dropDownFour() {
document.getElementById("dropdownfour").classList.toggle("show");
}
function dropDownFive() {
document.getElementById("dropdownfive").classList.toggle("show");
}
function dropDownSix() {
document.getElementById("dropdownsix").classList.toggle("show");
}
function dropDownSeven() {
document.getElementById("dropdownseven").classList.toggle("show");
}
window.onclick = function (event) {
if (!event.target.matches('.aboutmebuttons, .projectbuttons,
#mailopenbutton, [name="name"],
[name="message"], ' + '[name="email"],
[name="submitmail"], [name="reset"],
#dropdownseven, #mailform')
) {
var dropDowns = document.getElementsByClassName("dropdown-content");
for (var i = 0; i < dropDowns.length; i++) {
var openDropDown = dropDowns[i];
if (openDropDown.classList.contains('show')) {
openDropDown.classList.remove('show');
}
}
}
}
Thanks!
function dropDown(id){
document.getElementById(id).classList.toggle("show");
}
And then you could use it like that
<div class="dropdown">
<button onclick="dropDown('dropdownfour')" class="projectbuttons">PSD to Bussiness Site (01-2017)</button>
<div id="dropdownfour" class="dropdown-content">
<!--Content-->
</div>
</div>
function dropdown(dropdown){
document.getElementById(dropdown).classList.toggle("show");
}
Then use this HTML:
<div class="dropdown">
<button onclick="dropdown('dropdownfour')" class="projectbuttons">
PSD to Bussiness Site (01-2017)
</button>
<div id="dropdownfour" class="dropdown-content">
<!--Content-->
</div>
</div>
You may use the this and event keywords:
Change this html line:
<button onclick="dropDownFour()" class="projectbuttons">
to:
<button onclick="dropDown(this, event)" class="projectbuttons">PSD to Bussiness Site (01-2017)</button>
From MDN:
In an in–line event handler
When code is called from an in–line on-event handler, its this is set to the DOM element on which the listener is placed:
And the final function is:
function dropDown(ele, evt) {
ele.classList.toggle("show");
}
The snippet:
function dropDown(ele, evt) {
ele.classList.toggle("show");
}
.show {
display: none;
}
<div class="dropdown">
<button onclick="dropDown(this, event)" class="projectbuttons">PSD to Bussiness Site (01-2017)</button>
<div id="dropdownfour" class="dropdown-content">
<!--Content-->
aaaaaaaaaaaaaaaaaaaa
</div>
</div>
Another short form is based on:
DOMContentLoaded: when document is ready
querySelectorAll: select all button with class under div with class
addEventListener: create the click event handler for each element
window.addEventListener('DOMContentLoaded', function(e) {
document.querySelectorAll('div.dropdown button.projectbuttons').forEach(function(ele, idx) {
ele.addEventListener('click', function(e) {
ele.classList.toggle("show");
})
});
});
.show {
display: none;
}
<div class="dropdown">
<button class="projectbuttons">PSD to Bussiness Site (01-2017)</button>
<div id="dropdownfour" class="dropdown-content">
<!--Content-->
aaaaaaaaaaaaaaaaaaaa
</div>
</div>
<div class="dropdown">
<button class="projectbuttons">PSD to Bussiness Site (01-2017)</button>
<div id="dropdownfour" class="dropdown-content">
<!--Content-->
bbbbbb
</div>
</div>
<div class="dropdown">
<button class="projectbuttons">PSD to Bussiness Site (01-2017)</button>
<div id="dropdownfour" class="dropdown-content">
<!--Content-->
ccccc
</div>
</div>
You can use like that way also
HTML
<div class="dropdown">
<button onclick="dropDown(this)" class="projectbuttons">
1 button
</button>
<div id="dropdownone" class="dropdown-content">
<!--Content--> 1 content
</div>
</div>
<div class="dropdown">
<button onclick="dropDown(this)" class="projectbuttons">
2 button
</button>
<div id="dropdowntwo" class="dropdown-content">
<!--Content--> 2 content
</div>
</div>
<div class="dropdown">
<button onclick="dropDown(this)" class="projectbuttons">
3 button
</button>
<div id="dropdownthree" class="dropdown-content">
<!--Content--> 3 content
</div>
</div>
JAVASCRIPT
function dropDown(element){
element.parentElement.getElementsByClassName("dropdown-content")[0].classList.toggle("show") ;
}
Thanks,
Related
Hello so I have tabs using javascript:
function openScreen(screen, button) {
let i;
const tabContent = document.getElementsByClassName("tab-content");
const tabButton = document.getElementsByClassName("tab-button");
for (i = 0; i < tabContent.length; i++) {
tabContent[i].style.display = "none";
}
document.getElementById(screen).style.display = "block";
for (i = 0; i < tabButton.length; i++) {
tabButton[i].classList.remove('active');
}
document.getElementById(button).classList.add('active');
}
<div class="tab-links">
<button id="login-button" class="active tab-button" onclick="openScreen('Login', 'login-button')">Login</button>
<button id="register-button" class="tab-button" onclick="openScreen('Register', 'register-button')">Register</button>
</div>
<div>
<div id="Login" class="tab-content">
<p>Login</p>
</div>
<div id="Register" class="tab-content" style="display:none">
<p>Register</p>
</div>
</div>
And this is working, but I want to do this without passing any parameters to function and do it without using onclick function. But I dont image how I should achieve this.
This is a perfect task for event delegation. You register one even listener for the click event on the element that wraps the buttons and the content. In that event listener, you can use e.target is the element from which the event originated. e.currentTarget is the one on which the listener was attached.
In the listener, you need to figure out if it was really the button. Which could be done by checking for a certain property (in this case for the data-target attribute)
function openScreen(tabContainer, button) {
// remove active class from tab-content and tab-button in the current tab container
tabContainer.querySelectorAll(".tab-content.active, .tab-button.active").forEach(elm => {
elm.classList.remove('active');
})
// add the active class to the button and the container set by the target
let screen = button.dataset.target;
document.getElementById(screen).classList.add('active');
button.classList.add('active');
}
// Add the delegate event listener to all tab-conainers
document.querySelectorAll(".tab-container").forEach(container => {
container.addEventListener('click', (e) => {
// check if the event happened on an element with the `data-target` attribute
if (e.target.dataset.target) {
const tabContainer = e.currentTarget
const button = e.target
openScreen(tabContainer, button)
}
})
})
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
<div class="tab-container">
<div class="tab-links">
<button id="login-button" data-target="Login" class="tab-button active">Login</button>
<button id="register-button" data-target="Register" class="tab-button">Register</button>
</div>
<div>
<div id="Login" class="tab-content active">
<p>Login</p>
</div>
<div id="Register" class="tab-content">
<p>Register</p>
</div>
</div>
</div>
<hr>
<div class="tab-container">
<div class="tab-links">
<button id="login-button2" data-target="Login2" class="tab-button active">Login2</button>
<button id="register-button2" data-target="Register2" class="tab-button">Register2</button>
</div>
<div>
<div id="Login2" class="tab-content active">
<p>Login2</p>
</div>
<div id="Register2" class="tab-content">
<p>Register2</p>
</div>
</div>
</div>
You can do it with data attributes https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes
short example
<div class="tab" data-type="login"></div>
<div class="tab" data-type="register"></div>
Then
const tabs = document.querySelectorAll('.tab');
for (let tab of tabs) {
tab.onclick = function () {
const type = this.dataset.type;
/*now you can do all needed actions*/
}
}
Do you mean something like this?
function openScreen(e) {
const button = e.target;
const { screen } = button.dataset;
const tabs = document.querySelectorAll('.tab-content');
tabs.forEach(tab => tab.classList.toggle('active', screen === tab.id));
}
const buttons = document.querySelectorAll('button');
buttons.forEach(button => button.addEventListener('click', openScreen));
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
<div class="tab-links">
<button
id="login-button"
class="active tab-button"
data-screen="Login"
>Login</button>
<button
id="register-button"
class="tab-button"
data-screen="Register"
>Register</button>
</div>
<div>
<div id="Login" class="tab-content active">
<p>Login</p>
</div>
<div id="Register" class="tab-content">
<p>Register</p>
</div>
</div>
as your request. not passing any parameter. let me know at comment section if something doesn't work correctly.
$('#login-button').click(function(){
switchTab( $(this), $('#Login') );
});
$('#register-button').click(function(){
switchTab( $(this), $('#Register') );
});
function switchTab(this_, target_){
$('.tab-content').hide();
target_.show();
$('.tab-button').removeClass('active');
this_.addClass('active');
}
button.active{
border:1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="tab-links">
<button id="login-button" class="active tab-button">Login</button>
<button id="register-button" class="tab-button">Register</button>
</div>
<div>
<div id="Login" class="tab-content">
<p>Login</p>
</div>
<div id="Register" class="tab-content" style="display:none">
<p>Register</p>
</div>
</div>
I am trying to develop a page where there would be multiple divs, each of these divs have a button of which would show a "dropdown" style div below it when clicked.
Currently I have some code which when one button is clicked, it shows all of the "dropdown" styled divs on the page instead of just the one in the same container as the button.
I would like this to be done in pure JavaScript without jquery, any help would be appreciated, thank you!
HTML
<div class="fullResultsContainer">
<div class="resultContainer">
<div class="resultRow">
<!-- This has multiple divs but this is the only one relevant to the issue-->
<div class="resultMenu">
<button class="mobileShowActivityFeedBtn" onclick="mobileActivityLog()"> Show activity feed </button>
</div>
</div>
<div class="mobileDropDown">
<p> This is the content I want to show on button click</p>
</div>
</div>
<div class="resultContainer">
<div class="resultRow">
<!-- This has multiple divs but this is the only one relevant to the issue-->
<div class="resultMenu">
<button class="mobileShowActivityFeedBtn" onclick="mobileActivityLog()"> Show activity feed </button>
</div>
</div>
<div class="mobileDropDown">
<p> This is the content I want to show on button click</p>
</div>
</div>
</div>
JS
function mobileActivityLog() {
var btn = document.getElementsByClassName("mobileShowActivityFeedBtn");
var activity = document.getElementsByClassName("mobileDropDown");
for(var i=0; i<btn.length; i++) {
for(var j=0; i<activity.length; j++) {
if(activity[j].style.display == "none") {
activity[j].style.display = "flex"
} else {
activity[j].style.display = "none"
}
}
}
}
I think the easiest way is to send a parameter to the method and getElementById with a concatenated string with the parameter.
<div class="fullResultsContainer">
<div class="resultContainer">
<div class="resultRow">
<div class="resultMenu">
<button onclick="mobileActivityLog(1)"> Show activity feed </button>
</div>
</div>
<div class="mobileDropDown-1">
<p> This is the content I want to show on button click</p>
</div>
</div>
<div class="resultContainer">
<div class="resultRow">
<div class="resultMenu">
<button onclick="mobileActivityLog(2)"> Show activity feed </button>
</div>
</div>
<div id="mobileDropDown-2">
<p> This is the content I want to show on button click</p>
</div>
</div>
</div>
JS
function mobileActivityLog(index) {
var activity = document.getElementsById("mobileDropDown-" + index);
if(activity.style.display == "none") {
activity.style.display = "flex"
} else {
activity.style.display = "none"
}
}
One of the best possible ways to achieve this is to pass the current context using 'call' in the HTML. Use this context to target the required result container(here 'mobileDropDown' container).
function mobileActivityLog () {
var _this = this;
var activity = _this.closest('.resultContainer').querySelector(".mobileDropDown");
activity.classList.toggle('hide');
}
.hide {
display: none;
}
<div class="fullResultsContainer">
<div class="resultContainer">
<div class="resultRow">
<!-- This has multiple divs but this is the only one relevant to the issue-->
<div class="resultMenu">
<button class="mobileShowActivityFeedBtn" onclick="mobileActivityLog.call(this)"> Show activity feed </button>
</div>
</div>
<div class="mobileDropDown">
<p> This is the content I want to show on button click</p>
</div>
</div>
<div class="resultContainer">
<div class="resultRow">
<!-- This has multiple divs but this is the only one relevant to the issue-->
<div class="resultMenu">
<button class="mobileShowActivityFeedBtn" onclick="mobileActivityLog.call(this)"> Show activity feed </button>
</div>
</div>
<div class="mobileDropDown">
<p> This is the content I want to show on button click</p>
</div>
</div>
</div>
I have multiple div which has the same class and I want to display only one div per click which belongs to the parent div. I want to hide and show div "post-reply-box".
HTML
<div class="comet-avatar">
<img src="images/resources/comet-3.jpg" alt="">
</div>
<div class="we-comment">
<div class="coment-head">
<h5>Olivia</h5>
<span>16 days ago</span>
<a class="we-reply" href="javascript:void(0)" title="Reply"><i class="fa fa-reply"></i></a>
<ins>280</ins>
</span>
</div>
<p>i like lexus cars, lexus cars are most beautiful with the awesome features, but this car is really outstanding than lexus</p> </div>
<div class="comnt comnt-reply">
<div class="post-reply-box" style="padding:10px; display: none;">
<form method="post">
<textarea placeholder="You are Replying..."></textarea>
<button class="replyButton" type="submit">send</button>
<button class="cancelButton">cancel</button>
</form>
</div>
</div>
jQuery
$(document).ready(function(){
$(".fa-reply").on("click",function(){
$(".post-reply-box").css("display","block");
});
});
$(document).ready(function(){
$(".cancelButton").on("click",function(){
$(".post-reply-box").css("display","none");
});
});
The issue in your code is because you're using a class selector which retrieves all the .post-reply-box elements in the DOM, not just the one relevant to the button which was clicked.
To fix this use DOM traversal to relate the elements to each other. In this specific example use closest() to get the .we-comment related to the button, then next() to get the .comnt-reply container, then find().
In addition there some other issues which need to be addressed:
There's no need to duplicate document.ready handlers. Put all the logic in a single one.
Use show() and hide() instead of css() to set the display state of the element.
Use a CSS file instead of inline style elements to set style rules.
Attach the event handler to the a element, not the child i, and call preventDefault() on the event that's raised.
Add the type="button" attribute to the Cancel button so that clicking it does not submit the form.
With all that said, try this:
jQuery($ => { // updated document.ready handler
$(".we-reply").on("click", e => {
e.preventDefault()
$('.post-reply-box').hide(); // hide all
$(e.target).closest('.we-comment').next('.comnt-reply').find(".post-reply-box").show(); // show relevant
});
$(".cancelButton").on("click", function() {
$(".post-reply-box").hide();
});
});
.post-reply-box {
padding: 10px;
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="comet-avatar">
<img src="images/resources/comet-3.jpg" alt="">
</div>
<div class="we-comment">
<div class="coment-head">
<h5>Olivia</h5>
<span>16 days ago</span>
<a class="we-reply" href="javascript:void(0)" title="Reply"><i class="fa fa-reply"></i> Reply</a>
<span class="like-comment" data-toggle="tooltip" title="like">
<i class="ti-heart"></i>
<ins>280</ins>
</span>
</div>
<p>i like lexus cars, lexus cars are most beautiful with the awesome features, but this car is really outstanding than lexus</p>
</div>
<div class="comnt comnt-reply">
<div class="post-reply-box">
<form method="post">
<textarea placeholder="You are Replying..."></textarea>
<button class="replyButton" type="submit">send</button>
<button class="cancelButton" type="button">cancel</button>
</form>
</div>
</div>
<div class="comet-avatar">
<img src="images/resources/comet-3.jpg" alt="">
</div>
<div class="we-comment">
<div class="coment-head">
<h5>Olivia</h5>
<span>16 days ago</span>
<a class="we-reply" href="javascript:void(0)" title="Reply"><i class="fa fa-reply"></i> Reply</a>
<span class="like-comment" data-toggle="tooltip" title="like">
<i class="ti-heart"></i>
<ins>280</ins>
</span>
</div>
<p>i like lexus cars, lexus cars are most beautiful with the awesome features, but this car is really outstanding than lexus</p>
</div>
<div class="comnt comnt-reply">
<div class="post-reply-box">
<form method="post">
<textarea placeholder="You are Replying..."></textarea>
<button class="replyButton" type="submit">send</button>
<button class="cancelButton" type="button">cancel</button>
</form>
</div>
</div>
I am trying to develop a drop down menu. I have written html code and javascript for two buttons, but I am wondering how to link the second button to javascript. Do I need to write another function()?
<div class="dropmenu">
<button onclick="myFunction()" class="button1" style="background-color:#61117F ;">Dropdown</button>
<div id="Dropdown1" class="dropmenu-content">
Apple
google
</div>
</div>
<div class="dropmenu">
<button onclick="myFunction()" class="button1" style="background-color:#d7791b ;">DropDown2</button>
<div id="Dropdown2" class="dropmenu-content">
Yahoo
FB
</div>
</div>
<script>
function myFunction() {
document.getElementById("Dropdown1").classList.toggle("show");
window.onclick = function(event) {
if (!event.target.matches('.button1')) {
var drop = document.getElementsByClassName("dropmenu-content");
var i;
for (i = 0; i < drop.length; i++) {
var Dropdown = drop[i];
if (Dropdown.classList.contains('show')) {
Dropdown.classList.remove('show');
}
}}}
</script>
You could give your button a data-attribute with the id of the dropdown you want to affect and a css class of something like "trigger-event" to fire the event
<button data-dropdown="Dropdown1" class="trigger-event" style="...">
...
<button data-dropdown="Dropdown2" class="trigger-event" style="...">
and use the data attribute to retrieve the dropdown
$(document).on('click', '.trigger-event', function(){
var dropdownId = $(this).data("dropdown");//or attr("data-dropdown")
myFunction(dropdownId);
});
function myFunction(dropdownId) {
document.getElementById(dropdownId).classList.toggle("show");
window.onclick = function(event) {
...
}
}
Your JavaScript can be simplified a lot. Just pass the clicked button to the function and then find it's sibling with the class dropmenu-content. After you have that, all you need to do is toggle the show class.
window.myFunction = function(e) {
var dropdown = e.parentNode.getElementsByClassName('dropmenu-content')[0];
dropdown.classList.toggle('show');
}
.dropmenu-content {
display: none;
}
.dropmenu-content.show {
display: block;
}
<div class="dropmenu">
<button onclick="myFunction(this);" class="button1" style="background-color:#61117F ;">Dropdown</button>
<div id="Dropdown1" class="dropmenu-content">
Apple
google
</div>
</div>
<div class="dropmenu">
<button onclick="myFunction(this);" class="button1" style="background-color:#d7791b ;">DropDown2</button>
<div id="Dropdown2" class="dropmenu-content">
Yahoo
FB
</div>
</div>
function myFunction(dr){
var vis = document.getElementById(dr).style.display == "block" ? "none" : "block";
document.getElementById(dr).style.display = vis;
}
.button1{
border:none;
border-radius:5px;
padding:10px;
color:white;
margin:5px;
}
.dropmenu-content{
margin:10px;
}
.dropmenu-content a{
text-decoration:none;
color:brown;
box-shadow:1px 1px #ccc;
padding:5px;
border-left:solid 3px green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="dropmenu">
<button onclick="myFunction('Dropdown1')" class="button1" style="background-color:#61117F ;">Dropdown1 ▼</button>
<div id="Dropdown1" style='display:none;' class="dropmenu-content">
Apple
google
</div>
</div>
<div class="dropmenu">
<button onclick="myFunction('Dropdown2')" class="button1" style="background-color:#d7791b ;">DropDown2 ▼</button>
<div id="Dropdown2" style='display:none;' class="dropmenu-content">
Yahoo
FB
</div>
</div>
So, I am using bootstrap's modal.
I want to make a wizard style modal and came up with the following solution:
div snippets:
<div class="modal-instance hide fade" id="step1">
<div id="stepa">
...
</div>
</div>
<div id="stepb" style="display: none;">
...
</div>
Upon pressing a button in step-a step-b is loaded.
javascript snippet:
$("#stepa").replaceWith($('#stepb'));
document.getElementById('stepb').style.display = 'block';
This works ok.
But when I dismiss the modal. The div stepa has still been replaced by stepb. My solution was to build a replacement back to stepa when the modal is hidden:
$("#myModal").on("hidden", function() {
//replace the child
});
I tried:
$('#step1').children().remove();
$('#step1').append($('#stepa'));
and
$("#step1").children("div:first").replaceWith($('#stepa'));
But I am having a hardtime selecting step-a as a replacement div, probably due to it not being a separate div. My question is, is this the right approach for a wizard styled modal or should I take another approach?
It's much simpler just to hide the previous and next steps, instead of copying them.
<button type="button" data-toggle="modal" data-target="#myModal">Launch modal</button>
<div id="myModal" class="modal hide fade" data-step="1">
<div class="step step1">
<h1>Step 1</h1>
<button class="btn next">Next</button>
</div>
<div class="step step2">
<h1>Step 2</h1>
<button class="btn previous">Previous</button>
<button class="btn next">Next</button>
</div>
<div class="step step3">
<h1>Step 3</h1>
<button class="btn previous">Previous</button>
<button class="btn done" data-dismiss="modal">Done</button>
</div>
</div>
<style type="text/css">
#myModal > .step { display: none; }
</style>
<script type="text/javascript">
$(function() {
showStep(parseInt($('#myModal').data('step')) || 1);
$('#myModal .next').on('click', function () {
showStep(parseInt($('#myModal').data('step')) + 1);
});
$('#myModal .previous').on('click', function () {
showStep(parseInt($('#myModal').data('step')) - 1);
});
$('#myModal').on('hidden', function() {
showStep(1);
});
function showStep(step) {
$('#myModal').data('step', step);
$('#myModal > .step').hide();
$('#myModal > .step' + step).show();
}
});
</script>
http://jsfiddle.net/7kg7z/5/