In my example here:
Example
JS
$('button').on('click', showHide);
$('.overlay').on('click', showHide);
function showHide(){
$('.scroll-container').toggleClass('show');
$('.content-container').toggleClass('no-scroll');
$('.overlay').toggleClass('opacity');
}
you have a basic body with text. A clickable element (in this case a 'button') causes a scrollable container to appear and 'hover' over the original body, which can be hidden again by clicking outside of this container.
I'm not very good at JavaScript and with this example I was helped by a friend. The thing I'm struggling with now is that I need multiple different clickable elements, displaying a similar scrolling container, but with different content.
I'm doing this for a portfolio website, so imagine a bunch of photos on a page, which when clicked result in a body hovering over the original content, further elaborating the clicked project.
Do I create multiple id's for each project, together with multiple scrolling container id's, and just copy the JavaScript a couple of times?
I hope this makes sense and I hope someone is capable of explaining to me how I'm able to create the proposed effect.
First of all, you have to make a connection between buttons and containers that should be opened. One way is to use their indexes, so that when first button is clicked, first container would open. You can use this reference of the clicked object inside your function, in order to get its index. Like this:
$(this).index()
Then, you have to select all the elements with scroll_container class $('.scroll-container') and reduce the set of matched elements to the one by passing index of the clicked element to .eq() method .eq($(this).index()). Finally, you have to add show class to it addClass('show').
And because the logic is changed, you have to separate actions done on button and .overlay click events. They do not make a reverse action now, so they are not "togglers" anymore.
http://codepen.io/anon/pen/LpWwJL
$('button').on('click', show);
$('.overlay').on('click', hide);
function show(){
$('.scroll-container').eq($(this).index()).addClass('show');
$('.content-container').addClass('no-scroll');
$('.overlay').addClass('opacity');
}
function hide() {
$('.scroll-container').removeClass('show');
$('.content-container').removeClass('no-scroll');
$('.overlay').removeClass('opacity');
}
UPDATE
One thing you should keep in mind regarding $(this).index() method.
As it is written here:
If no argument is passed to the .index() method, the return value is an integer indicating the position of the first element within the jQuery object relative to its sibling elements.
That means that trigger elements should have common parent in order to maintain our logic.
In cases like this: https://stackoverflow.com/posts/32946956/edit, elements that are triggering scroll_container appearance, have different parent nodes (they are placed in 3 different divs). So, if we will call index() method for each of them, it will return '0' because they are the first and the only elements in their parent nodes.
Actually it means that you have to get the order of their parent elements, not theirs own. This can be achieved by using parent() method before index():
$(this).parent().index()
Here is updated codepen.
If I were you, I would implement a generic function to display a different content using the same function based in the button. So for that we will need something to relational the click with the content for that we can set a value in out button:
<button data-id="1">Click me 1!</button>
<button data-id="2">Click me 2!</button>
so out when we click the button we should get the value to send it to our function:
$('button').on('click', function(){
var dataButtonValue = $(this).data('id');
});
Then we can match it with the content using for example data-content-id
<div class="content" data-content-id="1">your wording</div>
<div class="content" data-content-id="2">your wording</div>
With all that we can manage what content we want to show depends on the click.
function showHide(id){
$('.content[data-content-id="' + id + '"]').toggleClass('show');
}
DEMO
I hope it's helps.
Related
I'm currently designing a webpage presenting a twitter-like user input that generates an <li> (inside a <ul>) element in which are appended one <h6> element (the post's title) and a <p> element underneath (the content).This works, therefore the input and generation of elements is not the problem.
But what I want to do is use jQuery to hide the posts's content, and toggle it when I click on the post's title. The issue is that the event handler seems to work only for every second post. Whenever i post once more, the 1st post on the list can be toggled, the second not, third yes, etc.
From what I've seen in some answers, I've tried the .click() method, the .on() method, I've tried to replace .toggle() with.hide() and .show() under conditionals, then created a class with display:none to toggle on click. This was my last stop, and the result is described in the above paragraph. Here's the event handler:
$('.postinstance').on("click", "h6.postname", function() {
$(this).siblings().toggleClass('postOff');
});
The .siblings() is actually only the post content, but that's the only way I could get near what I wanted. When I replace $(this).siblings() with the actual class of the content element, every post's content toggles when I click on any title.
How can I make each post open individually when I click on it?
Here's a JSFiddle isolating the input & posts part.
I have looked thoroughly in Stack Overflow and other places, even tutorials, to solve this problem but although similar questions were found none of their answers provided a solution.
You should not attach event handlers to dynamically generated elements directly, instead use some common parent element. Here's a piece of your snippet where I changed the selector and everything started working:
$('.postlist').on("click", "h6.postname", function() {
$(this).siblings().toggleClass('postOff');
});
Important note: you must pull this piece of code out from $('.postbtn').click(..) one level up, otherwise for even number of posts toggling will not work!
And move this out of click handler:
$('.postlist').on("click", "h6.postname", function() {
console.log(this);
$(this).siblings().toggleClass('postOff');
});
I am trying to toggle a div by clicking on a different div. The only relation that two divs share is that they are inside the same div. I have a DIV class comment which holds DIV class button that is supposed to toggle DIV class box when clicked. The box DIV is also inside the comment DIV. I am trying to use jQuery(this).find(".box").toggle();, but it is not working. I am triggering it with $( ".button" ).click(function(). The script is currently at the bottom of my body.
Could anyone please tell me what am I doing wrong here? I've been playing around with the function for a while now, but with no luck at all. Thank you in advance for your replies.
JSFIDDLE here
HTML
<div class="comment">
<div class="button">
show/hide .box with text1
</div>
<div class="box">
text 1
</div>
</div>
<div class="comment">
<div class="button">
show/hide .box with text2
</div>
<div class="box">
text 2
</div>
<div>
jQuery
$( ".button" ).click(function() {
jQuery(this).find(".box").toggle();
});
You can use the jQuery selector .siblings() to re-write your function like this:
$( ".button" ).click(function() {
$(this).siblings().toggle();
});
Here's a working fiddle to demonstrate.
All you really need to do is this:
$(this).parent().find(".box").toggle();
In short, change:
jQuery(this).find(".box").toggle();
To ONE of the following lines:
$(this).parent('.comment').find(".box").toggle();
$(this).closest('.comment').find(".box").toggle();
$(this).siblings(".box").toggle();
Full Explanation:
The reason it's not working is due to the call. Let's break down your call and see what exactly it's doing.
First we see a simple jQuery selector. This tells jQuery to look for a div containing the class button. Keep in mind, jQuery makes use of any CSS selector. So selecting an item in jQuery is as simple as using it's CSS selector!
$( ".button" )
Next you are assigning an event. In this case, that event is click, meaning you're telling a div having the class button to do something every time it is clicked. Keep in mind, however, not including a callback function is an easy way to trigger this event as well.
$( ".button" ).click(function() {
Now this next line is where your mistake takes place.
jQuery(this).find(".box").toggle();
The first mistake is the use of jQuery. after you're already making use of it's short sign, $. You only need use the elongated name if you are using jQuery's noconflict because another JS library you include might use $. In other words, if $('.button') works and is a jQuery object when used, then you don't need to use jQuery.. See more about this here.
Now, that aside, we can look at jQuery(this) as $(this). Whenever you use $(this) in an Event's callback method, you're referring to the element that the event was tied too. That means that $(this) in your function refers to $('.button'). The problem here is that you then want it to find an inner element containing the class box. Well according to your HTML, that can't happen since .box is a sibling, it is not within the inner HTML of .button. Thus you need to make a different call before you can find .box.
There are actually several solutions here. No solution is more "correct" than another, just simply different and possibly causes a different amount of "time" to run. Now I went with what I saw as being the most simple in that it gives you control over the parent element which contains ALL relevant elements to this function. I'll talk about possible alternatives in a minute.
$(this).closest('.comment')
The above line simply tells .button:clicked to look for the first parent element that contains the class .comment. In other words, this won't find any children or siblings, it will only go up from the current element. This allows us to grab the block that contains all relevant elements and information and thus make maneuvers as needed. So, in the future, you might even use this as a variable in the function, such as:
$('.button').click(function(e) {
var container = $(this).closest('.comment');
Now you can find anything within this element block. In this case you want to find box and toggle it. Thus:
$(this).closest('.comment').find(".box").toggle();
// Or with our variable I showed you
container.find(".box").toggle();
Now, there are plenty of alternatives based on your HTML layout. This example I've given would be good even if .box was buried inside more elements inside .comment, however, given your exact HTML, we see that .button and .box are siblings. This means that you could make this call different entirely and get the same result using something like:
$(this).siblings(".box").toggle();
This will allow our currently clicked and selected button element to look for ANY and ALL siblings having class box. This is a great solution and simple if your HTML is that simple.
However, many times, for "comment" type setups, our HTML is not so simple, nor is it static. It's usually something loaded after the page load. This means our general assignment of .click will not work. Given your exact HTML and not knowing a static Parent ID, I would probably write your code as:
$(document).on('click', '.button', function(e) {
$(this).siblings('.box').toggle();
});
What this does is allow for this click event to be assigned to ANY element containing .button for a class, whether loaded with page or even ten minutes after the page is up. However, the caveat often seen here is the assignment is placed on document. Should we assign a lot of events to document it could become quite convoluted and possibly slow down the client's browser. Not to mention the arguments held over all the other headaches this could cause. So here's my recommendation, make a static (loads with page, is a part of page's main HTML) loading area and do our dynamic assignment to that. For instance:
<div id"Comments"><!-- load comments --></div>
Then you can do the assignment as such:
$('#Comments').on('click', '.button', function(e) {
$(this).siblings('.box').toggle();
});
If you have any more questions, just comment!
Side Note .on is for jQuery versions 1.7+. If using older jQuery, use .live or .bind
so i implemented a bit of jQuery that basically toggles content via a slider that was activated by an <a> tag. now thinking about it id rather have the DIV thats holding the link be the link its self.
the jQuery that i am using is sitting in my head looks like this:
<script type="text/javascript">
function slideonlyone(thechosenone) {
$('.systems_detail').each(function(index) {
if ($(this).attr("id") == thechosenone) {
$(this).slideDown(200);
}
else {
$(this).slideUp(600);
}
});
}
</script>
i was using this as a index type box so there are several products when you click on the <a> tag that used to be an image* it would render a bit of content beneath it describing the products details:
<div class="system_box">
<h2>BEE Scorecard database</h2>
<p>________________</p>
</div>
the products details are wrapped in this div.
<div class="systems_detail" id="sms_box">
</div>
so when you click on what used to be a image* it would run the slideonlyone('div_id_name') function. the function above then first closes all the other divs with the class name 'system details' and then opens/slides the div with the id that was passed into the slideonlyone function. that way you can toggle products details and not have them all showing at once.
note i only kept the <a> tag to show you what was in there i will be getting rid of it.
note: i had an idea of just wrapping the whole div in an <a> tag but is that good practice?
So now what i am wondering is since you need JavaScript to run onclick on a div tag how do you write it so that it still runs my slideonlyone function?
Using obtrusive JavaScript (i.e. inline code) as in your example, you can attach the click event handler to the div element with the onclick attribute like so:
<div id="some-id" class="some-class" onclick="slideonlyone('sms_box');">
...
</div>
However, the best practice is unobtrusive JavaScript which you can easily achieve by using jQuery's on() method or its shorthand click(). For example:
$(document).ready( function() {
$('.some-class').on('click', slideonlyone('sms_box'));
// OR //
$('.some-class').click(slideonlyone('sms_box'));
});
Inside your handler function (e.g. slideonlyone() in this case) you can reference the element that triggered the event (e.g. the div in this case) with the $(this) object. For example, if you need its ID, you can access it with $(this).attr('id').
EDIT
After reading your comment to #fmsf below, I see you also need to dynamically reference the target element to be toggled. As #fmsf suggests, you can add this information to the div with a data-attribute like so:
<div id="some-id" class="some-class" data-target="sms_box">
...
</div>
To access the element's data-attribute you can use the attr() method as in #fmsf's example, but the best practice is to use jQuery's data() method like so:
function slideonlyone() {
var trigger_id = $(this).attr('id'); // This would be 'some-id' in our example
var target_id = $(this).data('target'); // This would be 'sms_box'
...
}
Note how data-target is accessed with data('target'), without the data- prefix. Using data-attributes you can attach all sorts of information to an element and jQuery would automatically add them to the element's data object.
Why do you need to attach it to the HTML? Just bind the function with hover
$("div.system_box").hover(function(){ mousin },
function() { mouseout });
If you do insist to have JS references inside the html, which is usualy a bad idea you can use:
onmouseover="yourJavaScriptCode()"
after topic edit:
<div class="system_box" data-target="sms_box">
...
$("div.system_box").click(function(){ slideonlyone($(this).attr("data-target")); });
You can bind the mouseenter and mouseleave events and jQuery will emulate those where they are not native.
$("div.system_box").on('mouseenter', function(){
//enter
})
.on('mouseleave', function(){
//leave
});
fiddle
note: do not use hover as that is deprecated
There's several things you can improve upon here. To start, there's no reason to use an <a> (anchor) tag since you don't have a link.
Every element can be bound to click and hover events... divs, spans, labels, inputs, etc.
I can't really identify what it is you're trying to do, though. You're mixing the goal with your own implementation and, from what I've seen so far, you're not really sure how to do it. Could you better illustrate what it is you're trying to accomplish?
== EDIT ==
The requirements are still very vague. I've implemented a very quick version of what I'm imagining you're saying ... or something close that illustrates how you might be able to do it. Left me know if I'm on the right track.
http://jsfiddle.net/THEtheChad/j9Ump/
There are a lot of asked questions with almost similar titles with this question of mine, but you know I didn't find an answer.
My simple question is:
I have button, when I click on it, javascript creates modal window
<div class="aui-dialog">
html here...
<button id="closeButton">Close</button>
</div>
just after <body> tag.
I can bind click event of close button with no problem using jQuery live:
$("#closeButton").live("click", function() {
alert("asdf"); // it calls
$("body").find(".aui-dialog").remove();
});
My problem is, I cannot select that dynamically created modal window div by its classname. So that I could call jQuery .remove() method to make close action. Now I know, I must deal with dynamic elements in another way.
What way?
EDIT:
I think it's important to mention this:
I dont' create the modal window myself, I use liferay portal. It has built-in javascript framework AUI(YUI) that creates that modal window. I can just create that close button inside it in its view.
EDIT 2:
Modal window div class attribute value is: "aui-component aui-panel aui-dialog aui-widget-positioned"
Since jquery will read the current DOM-state when page loads:
jQuery( document ).ready(function( $ ) {
it will miss the elements you generate post to page load.
One simple solution is to listen for clicks on document, and filter with the class or element-type that you want to use to execute your code. That way jquery will find new elements generated under document, after page load.
$(document).on("click", '#closeButton', function(){
$(".aui-dialog").remove();
});
Create a reference when you're creating the modal window:
var modalWindow = $('<div class="aui-dialog">html here... <button id="closeButton">Close</button></div>');
// later...
modalWindow.remove();
To your edit:
Get the window via jQuery's parent when the button is inside the modal window:
$('#closeButton').on('click',function() {
$(this).parent().remove();
return false;
});
Many users will come on this page when they want to select some element generated runtime by JQuery and it failed, like me.
The solution is simply approach the root (the parent) of your randomly generated element and then get inner by jQuery TAG selection. For example you generate many TDs of users in a table at runtime, the element having your users list is a table with id tblUsers then you can iterate over runtime generated TRs or TDs as following:
$("#tblUsers tr").each(function(i){
alert('td' + i);
});
further if you have inputs in tds you can go deep in selection as
$("tblUsers tr td input")
Another case could be a randomly generated dialog or popup, then you have to approach its root(parent) and next same selection by TAG as stated above.
You could do a few things, but first, if you are using jQuery 1.7, better use .on(). it has replaced .live() which is deprecated.
if you have no control over the building of the modal but know that the button is a direct child of the modal, then use parent()
$('#closeButton').on('click',function() {
$(this).parent().remove();
return false;
});
if the button is somewhere deep in the parent but has a fixed depth from the parent, use parents() which gets all ancestors of the element, and then filter it to a specific depth. if the close was 2 levels deep, the index of :eq() would be 1.
$('#closeButton').on('click',function() {
//where N is zero-indexed integer, meaning first item of the set starts with 0
$(this).parents(':eq(N)').remove();
return false;
});
another way is to add the handler when the modal is created
var modal = $('modalHTML');
$('#closeButton',modal).on('click',function(){
//modal still refers to the whole modal html in this scope
modal.remove();
});
//show modal
UPDATED:
You can use:
$(".aui-dialog").live('click', function() {
$(this).remove();
return false;
});)
This attach an event handler for all elements which match the current selector, now and in the future.
Please not that this method is depreciated in newer version of jQuery and you should consider using .on() instead of .live().
I found an answer, hope it would be helpful for developers who faced with dynamically generated html with IFRAME inside.
If you have a button (#closeButton) inside that IFRAME, and you want select iframe parent window's dom elements, just add second argument window.parent.document for your selector:
// This functions is inside generated IFRAME
$("#closeButton").on("click", function() {
// body - is your main page body tag
/* Will alert all html with your dynamically
generated html with iframe and etc. */
alert($('body', window.parent.document).html());
return false;
});
I want to add a slide up affect with jQuery to a DIV when a link inside of the DIV is clicked, but the problem i am running into is the class of the DIV's are defined by a loop. So, i can't define the DIV class in the jQuery line, because each DIV class is different and i cannot determine ahead of time what they are. I am trying to use .parent and .child but I am not sure how to go about this. Is this making any sense?
Bind to the click of the element you want (in this case I just used a simple anchor element). Then find the first parent that is a div and perform the slideUp() effect.
$('a').click(function() {
$(this).parents('div:first').slideUp();
});
You can see it work here: http://jsfiddle.net/XNnSp/
Let me know if that's what you are looking for http://jsbin.com/ehoza3
$('a').click(function() {
$(this).parent().slideUp();
});
Two (most obvious) ways
FIRST
If your tree is always defined in terms of depth you could access your parent DIV doing just that:
$(this).parent().parent().parent().slideUp();
SECOND
Add an additional class that doesn't clash with dynamic ones and do this:
$(this).closest(".some-custom-class").slideUp();