I have the code below working to handle clicking a link from a list, showing a screen, and then hiding it when the .back button is pressed.
Is there a cleaner way to handle the click function for any x number of list items?
$(".container").on("click", ".dog-btn", function() {
$(".screen1").css("display","flex")
});
$(".container").on("click", "#back", function() {
$(".screen1").css("display","none")
});
$(".container").on("click", ".cat-btn", function() {
$(".screen2").css("display","flex")
});
$(".container").on("click", "#back", function() {
$(".screen2").css("display","none")
});
$(".container").on("click", ".bird-btn", function() {
$(".screen3").css("display","flex")
});
$(".container").on("click", "#back", function() {
$(".screen3").css("display","none")
});
You can use html5 data attributes to pass screen classes.
HTML CODE
<div class="container">
<button class="flex" data-screen="screen1"> DOG</button>
Back
</div>
JavaScript Code
//Flex Handler
$(".container").on("click", ".flex", function() {
$("."+$(this).data("screen")).css("display","flex")
});
//Back Button Handler
$(".container").on("click", ".back", function() {
$("."+$(this).data("screen")).css("display","none")
});
Hope it helps.
You can have benefits of data-* attributes of HTML5 as its answered here.
But additionally you can put your custom styles in JSON format in data attributes too. So that you don't need to specify it on every control. That would just go with one click handler as below
$('button').on('click',function(){
var target=$(this).data('target'),
css = $(this).data('css');
$(target).css(css);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button data-css='{"background":"yellow"}'
data-target="#screen1">
click 1
</button>
<button data-css='{"background":"red"}'
data-target="#screen2">
click 2
</button>
<div id="screen1">
screen1
</div>
<div id="screen2">
screen2
</div>
A mockup without jQuery, using event delegation and ES20xx
document.querySelector(".container").addEventListener("click", handleEvents);
document.querySelector("#back").click();
function handleEvents(evt) {
const origin = evt.target;
const screenMap = {
"dog-btn": "screen1",
"cat-btn": "screen2",
"bird-btn": "screen3",
};
if (origin.id && origin.id === "back") {
const screens = `.${Object.entries(screenMap).map(([key, value]) => value).join(",.")}`;
return Array.from(document.querySelectorAll(screens))
.forEach(screen => screen.style.display = "none");
}
if (Array.from(origin.classList).filter(v => /\-btn$/i.test(v)).length) {
return document.querySelector(`.${screenMap[origin.classList]}`)
.style.display = "flex";
}
}
<div class="container">
<div class="screen1">screen 1 DOG</div>
<div class="screen2">screen 2 CAT</div>
<div class="screen3">screen 3 BIRD</div>
<button id="back">#back</button>
<button class="dog-btn">.dog-btn</button>
<button class="cat-btn">.cat-btn</button>
<button class="bird-btn">.bird-btn</button>
</div>
Related
Having the following structure:
<div class="the-parent">
<div>
<a onClick="doParentStuff()">
<div>
<i onClick="doChildStuff()"></i>
</div>
</a>
</div>
</div>
Now, when the child element (icon) is clicked it logs the content of doChildStuff() but afterwards it also logs the content of doParentStuff().
Is there a way to call doChildStuff only when the icon is clicked and call doParentStuff when everything else inside the-parent div is clicked?
When the child is clicked, you must stopPropagation of the event:
function doChildStuff(e) {
e.stopPropagation();
console.log('child clicked');
}
function doParentStuff() {
console.log('parent clicked');
}
<div class="the-parent">
<div>
<a onClick="doParentStuff()">
<div>
Test
<button onClick="doChildStuff(event)">Child</button>
</div>
</a>
</div>
</div>
Avoid the use of Event.stopPropagation() (unless you really, really know what you're doing).
An application, or third party code, should never stop or prevent an event to propagate throughout the application layers / components.
Instead, change your logic to implement a third function (like doStuff) that will trigger a desired function depending on the Event.target.closest() match
const doChildStuff = () => {
console.log("child stuff");
};
const doParentStuff = () => {
console.log("parent stuff");
};
const doStuff = (ev) => {
if (!ev.target.closest(".icon")) {
doParentStuff();
}
doChildStuff();
};
document.querySelectorAll(".anchor").forEach(elAnchor => {
elAnchor.addEventListener("click", doStuff);
});
<div class="the-parent">
<div>
<a class="anchor">
<div>
Link
<i class="icon">icon</i>
</div>
</a>
</div>
</div>
Also, stop using HTML inline on* attribute handlers. Such code is hard to maintain and debug. JavaScript should be in one place only, and that's the respective tag or file. Use addEventListener instead.
Even if not asked, if you want to also separate the handler for the parent, simply put it into an else block:
const doChildStuff = () => {
console.log("child stuff");
};
const doParentStuff = () => {
console.log("parent stuff");
};
const doStuff = (ev) => {
if (!ev.target.closest(".icon")) {
doParentStuff();
} else {
doChildStuff();
}
};
document.querySelectorAll(".anchor").forEach(elAnchor => {
elAnchor.addEventListener("click", doStuff);
});
<div class="the-parent">
<div>
<a class="anchor">
<div>
Link
<i class="icon">icon</i>
</div>
</a>
</div>
</div>
Thanks for the support! - Sory, my english is bad!
I use this code to get the DOM component from the page entry to display on the homepage.
When I click on open-ajax, it loads the DOM from the entrypage and display in ajax-outer, when clicked on ajax-overlay, it will delete the DOM.
But I discovered an error, if I clicked on an open-ajax link and clicked on ajax-overlay immediately, get () will still load the DOM and display in ajax-outer.
It seems that ajax-overlay is unable to stop get ()
How can I optimize the code?
Html from Homepage:
<div class="main_content">
<a class="open-ajax" href="/link/101">1</a>
...
<a class="open-ajax" href="/link/10n">n</a>
</div>
<div class="ajax-wrap">
<div class="ajax-overlay"></div>
<div class="ajax-outer"></div>
</div>
Html from Entry:
<div class="coupon_content">
<div class="abc">
....
</div>
</div>
Javascript:
$('.main_content').on('click', '.open-ajax', function(e) {
var gethref = $(this).attr('href');
e.preventDefault();
$('.ajax-wrap').addClass('active');
$.get(gethref, function(sch) {
$('.coupon_content', sch).each(function() {
$('.ajax-outer').append($(this).html());
$("body").addClass('noscroll');
});
});
});
$('.ajax-overlay').click(function(e) {
$('.ajax-wrap').removeClass('active');
$('.ajax-outer').children().remove();
$("body").removeClass('noscroll');
});
Ví dụ tương tự : https://dribbble.com/shots
You can't prevent a ajax request but you can prevent the appending using a global variable
var canAppend = true;
$('.main_content').on('click', '.open-ajax', function(e) {
var gethref = $(this).attr('href');
e.preventDefault();
$('.ajax-wrap').addClass('active');
$.get(gethref, function(sch) {
if(canAppend) {
$('.coupon_content', sch).each(function() {
$('.ajax-outer').append($(this).html());
$("body").addClass('noscroll');
canAppend = true;
});
}
});
});
$('.ajax-overlay').click(function(e) {
$('.ajax-wrap').removeClass('active');
$('.ajax-outer').children().remove();
$("body").removeClass('noscroll');
canAppend = false;
});
You could hide the ajax-overlay when you click open-ajax and show it in the success callback, this way you make sure that the overlay will not be clicked until all the code is loaded:
$('.main_content').on('click', '.open-ajax', function(e) {
e.preventDefault();
var gethref = $(this).attr('href');
$('.ajax-wrap').addClass('active');
$('.ajax-overlay').hide();
$.get(gethref, function(sch) {
$('.coupon_content', sch).each(function() {
$('.ajax-outer').append($(this).html());
$("body").addClass('noscroll');
$('.ajax-overlay').show();
});
});
});
I am trying to toggle visibility of signup and signin boxes if sign in and sign up buttons are clicked. I am trying to use only pure javascript.
I wrote simple html and javascript as below:
<div>
<button class="signin">sign in</button><button class="signup">sign up</button>
<div class="signin-box" style="display: none;">
<form class="signin-form">
<label>username<input></label><label>password<input></label><button type="submit">signin</button>
</form>
</div>
<div class="signup-box" style="display: none;">
<form class="signup-form">
<label>username<input></label><label>password<input></label><button type="submit">signup</button>
</form>
</div>
</div>
javascript part:
var signupButton = document.getElementsByClassName('signup')[0];
var signinButton = document.getElementsByClassName('signin')[0];
var signupBox = document.getElementsByClassName('signup-box')[0];
var signipBox = document.getElementsByClassName('signin-box')[0];
console.log("box: ", signupBox, "button: ",signupButton);
var toggleVisible = function(item){
if (item.style.display === 'none'){
return item.style.display = 'block';
}else{
return item.style.display = 'none';
}
};
window.onload = function(){
signupButton.onclick = toggleVisible(signupBox);
signinButton.onclick = toggleVisible(signipBox);
};
The problem here is that the javascript toggleVisible is automatically activated even if i never clicked the buttons.
as a result, the signin-box and signup-box both gets display:block property.
How do i solve this problem?
You're calling the function, not passing it in. Just wrap your function call in an anonymous function:
signupButton.onclick = function() {
toggleVisible(signupBox);
};
If you don't care about older browsers, you can also simplify your code a little if you put your JavaScript at the bottom of the <body> tag and add a rule to your CSS:
document.querySelector('.signup').addEventListener('click', function() {
document.querySelector('.signup-box').classList.toggle('hidden');
}, false);
document.querySelector('.signin').addEventListener('click', function() {
document.querySelector('.signin-box').classList.toggle('hidden');
}, false);
And the CSS:
.hidden {
display: none;
}
I would recommend to use a standard JavaScript method addEventListener() to attached onclick event listener to the button.
It has following advantages over different solution:
You can attach an event handler to an element without overwriting existing event handlers.
You can add many event handlers of the same type to one element, i.e
two "click" events.
In your code it will look like
window.onload = function(){
signupButton.addEventListener("click", function() { toggleVisible(signupBox); });
signinButton.addEventListener("click", function() { toggleVisible(signipBox); });
};
Current code invokes toggleVisible(..) method and assigns its result to the button attribute, which is not one would expect.
signupButton.onclick = toggleVisible(signupBox);
I have a page which has a random number of items each of which has a button and a modal - as I do not know how many items there will be I am using classes for the button and modal.
When I click any button it loads all the modals whereas I only want it to load the next modal - I have tried to use closest and next but cannot get them to fire.
<div class="social-button-container">
<button type="button" class="social-button">Button</button>
</div>
<div class="socialModal modal fade">
<h2>123</h2>
</div>
<div class="social-button-container">
<button type="button" class="social-button">Button2</button>
</div>
<div class="socialModal modal fade">
<h2>234</h2>
</div>
$(document).ready(function () {
$('.social-button').click(function () {
$('.socialModal').modal();
return false;
});
});
The above code works in that the modals fire but they all do - I tried using:
$(document).ready(function () {
$('.social-button').click(function () {
$('.socialModal').next().modal();
return false;
});
});
but this does nothing at all (none fire)
Also tried:
$(document).ready(function () {
$('.social-button').click(function () {
$(this).next('.socialModal').modal();
return false;
});
});
with the same result - how can I get only the following modal to open on clicking the relevant button?
http://jsfiddle.net/0v0pg7fx/
Your selectors were a bit off, and you probably want to in initialize the modals first.
$('.socialModal').modal({show:false});
$('.social-button').click(function () {
$(this).closest('.social-button-container').next('.socialModal').modal('show');
});
Demo
$(document).ready(function () {
$('.button').click(function () {
$('.Modal').closest().modal();
return false;
});
});
i have a piece of code like this.
// HTML file
<div class="box" ng-click="displayinfo()">
click here to display info about this page.
<div class="content" ng-click="displaytext()">
Click here to display text.
</div>
click here to display info about this page.
</div>
// JS file
$scope.displayinfo = function()
{
alert('info');
}
$scope.displaytext = function()
{
alert('Text');
}
the thing is while clicking on 'click here to display text', it is calling both functions and displaying 'Text' and 'info'. but i dnt want to display 'info' here. i cannot change the html div structure.
how to do that?
It's a little hidden in the docs, but if you look here: http://docs.angularjs.org/api/ng.directive:ngClick
You can see that parameters it mentions an $event object. So your html will become:
<div class="box" ng-click="displayinfo($event)">
click here to display info about this page.
<div class="content" ng-click="displaytext($event)">
Click here to display text.
</div>
click here to display info about this page.
</div>
and then your javascript will become:
$scope.displayinfo = function($event)
{
$event.stopPropagation();
alert('info');
}
$scope.displaytext = function($event)
{
$event.stopPropagation();
alert('Text');
}
jsfiddle: http://jsfiddle.net/rtCP3/32/
Instead calling functions there inline use jquery to solve this issue:
$('.box').click(function(){
displayinfo();
});
$('.content').click(function(e){
e.stopPropagation(); //<-------------------this will stop the bubbling
displaytext();
});
demo code for e.stopPropagation(): http://jsfiddle.net/HpZMA/
var a = "text for info";
$('.box').click(function(){
$(this).append(a)
});
var b = "text for info";
$('.content').click(function(e){
e.stopPropagation(); //<-------------------this will stop the bubbling
$(this).append(b)
});
For native javascript solution you need to pass event as argument to your 2 methods in order to prevent the event from propagating
<div class="box" onclick="displayinfo(event)">
Then change js to:
var displayinfo = function(event) {
event.cancelBubble = true
alert('info')
}
var displaytext = function(event) {
event.cancelBubble = true
alert('text')
}
DEMO: http://jsfiddle.net/MvgTd/
whatever you are getting.stopPropagation();
in your case
$event.stopPropagation();