I have a repeated component with a control that toggles between displaying 2 images (mobile image and desktop image). I need each control to only toggle the component it is in, and function independently from every other component.
I am able to generate unique ids for all the controls, unique ids for all the images, and on click I am able to add/remove classes as well as show/hide images. My problem is that I don't know how to associate the toggle control id to the image id so that I'm only changing one component. Right now I am targeting the class (which is the same for every component) so everything toggles when you click the control.
This is inside Wordpress using Visual Composer, so I don't believe I am able to use a loop to render the repeated components.
JSFiddle Here
below is a single component, which would be repeated a number of times
<div class="wrapper">
<div class="platform-toggle">
<div class="mobile-toggle">
mobile
</div>
<div class="desktop-toggle">
desktop
</div>
</div>
<div class="platform-images">
<img class="mobile-image" src="https://via.placeholder.com/100x100.png?text=mobile" />
<img class="desktop-image" src="https://via.placeholder.com/100x100.png?text=desktop" />
</div>
</div>
$.each($('.platform-toggle'), function(ind) {
$(this).attr('id', 'platform-toggle_' + parseInt(ind + 1));
});
$.each($('.mobile-toggle'), function(ind) {
$(this).attr('id', 'mobile-toggle_' + parseInt(ind + 1));
});
$.each($('.desktop-toggle'), function(ind) {
$(this).attr('id', 'desktop-toggle_' + parseInt(ind + 1));
});
$.each($('.mobile-image'), function(ind) {
$(this).attr('id', 'mobile-image_' + parseInt(ind + 1));
});
$.each($('.desktop-image'), function(ind) {
$(this).attr('id', 'desktop-image_' + parseInt(ind + 1));
});
$(".mobile-toggle").click(function() {
if ($(".mobile-toggle").hasClass("inactive")) {
$(".mobile-toggle").removeClass("inactive");
$(".mobile-toggle").addClass("active");
$(".mobile-image").show()
$(".desktop-toggle").removeClass("active");
$(".desktop-toggle").addClass("inactive");
$(".desktop-image").hide()
}
});
$(".desktop-toggle").click(function() {
if ($(".desktop-toggle").hasClass("inactive")) {
$(".desktop-toggle").removeClass("inactive");
$(".desktop-toggle").addClass("active");
$(".desktop-image").show()
$(".mobile-toggle").removeClass("active");
$(".mobile-toggle").addClass("inactive");
$(".mobile-image").hide()
}
});
You would use $(this) selector for this case, and jQuery has lot of functions for finding parent, sibling, children, next, prev or etc elements.
I've changed your fiddle and added new selectors.
JSFiddle
$(".mobile-toggle").click(function() {
if ($(this).hasClass("inactive")) {
$(this).removeClass("inactive");
$(this).addClass("active");
//find current toggle element parent, then find next element(wrapper of the images) and finally find children image.
$(this).parent('.platform-toggle').next('.platform-images').children('.mobile-image').show();
$(this).siblings('.desktop-toggle').removeClass("active");
$(this).siblings('.desktop-toggle').addClass("inactive");
$(this).parent('.platform-toggle').next('.platform-images').children('.desktop-image').hide();
}
});
You may use parent div of the specific control in this way:
$(".mobile-toggle").click(function() {
var parentObj=$(this).closest(".wrapper");
if ($(parentObj).find(".mobile-toggle").hasClass("inactive")) {
$(parentObj).find(".mobile-toggle").removeClass("inactive");
$(parentObj).find(".mobile-toggle").addClass("active");
$(parentObj).find(".mobile-image").show()
$(parentObj).find(".desktop-toggle").removeClass("active");
$(parentObj).find(".desktop-toggle").addClass("inactive");
$(parentObj).find(".desktop-image").hide()
}
});
$(".desktop-toggle").click(function() {
var parentObj=$(this).closest(".wrapper");
if ($(parentObj).find(".desktop-toggle").hasClass("inactive")) {
$(parentObj).find(".desktop-toggle").removeClass("inactive");
$(parentObj).find(".desktop-toggle").addClass("active");
$(parentObj).find(".desktop-image").show()
$(parentObj).find(".mobile-toggle").removeClass("active");
$(parentObj).find(".mobile-toggle").addClass("inactive");
$(parentObj).find(".mobile-image").hide()
}
});
This should be exactly the same as #Slim's answer, but with simplified code that doesn't re-select the same elements again and again. The $() selector in jQuery is fast, but there's no reason to keep selecting $(this) 7 times if we don't have to.
$(".mobile-toggle").click(function() {
var $this = $(this);
if ($this.hasClass("inactive")) {
$this.removeClass("inactive").addClass("active");
//find current toggle element parent, then find next element(wrapper of the images) and finally find children image.
var $platformImgs = $this.parent('.platform-toggle').next('.platform-images')
$platformImgs.children('.mobile-image').show();
$this.siblings('.desktop-toggle').removeClass("active").addClass("inactive");
$platformImgs.children('.desktop-image').hide();
}
});
Related
I am completely new to Javascript / Jquery and I have a problem.
Suppose in my html page I have a number (undefined) of class to hover (when I hover something happens). Here I put 2 examples.
<div class='hover' id='hov33749'>Wikipedia</div>
<div class='hover' id='hov32747'>Google</div>
How to :
Apply a function when I hover on Google or Wikipedia
Retrieve the div corresponding to the hover (id, text, position on the page etc.)
I tried to put a random id and put some regex but it doesn't work well
I thank you in advance
Since you are starting out with JavaScript, I'd suggest refrain JQuery for now and understand how the language itself works.
The following code adds an eventListener to all elements with class hover, the functionality of which is in onHover method
const onHover = (e) => {
const id = e.target.id;
const text = e.target.textContent;
console.log(id, text);
}
const hover = document.querySelectorAll(".hover");
hover.forEach(item => item.addEventListener("mouseover", onHover));
<div class='hover' id='hov33749'>Wikipedia</div>
<div class='hover' id='hov32747'>Google</div>
See JQuery documentation
.hover()
$(".hover").each(function(){
$(this).hover(function(){
// Do something ...
console.log("Text: " + $(this).text() + ", Id: " + $(this).attr("id"));
});
});
My goal is on hover a p element contained inside an a tag gets bigger on hover. I have achieved this via css3 transitions, however this is not the issue.
A loop creates a variable amount of elements in the form below on each iteration.
anchorElement = "<a id='anchor" + countWide + "' class=\"boxOPT oneplustwo\" alt=\'"+ image_website +"' style=\"cursor:pointer;width:"+ itemWidth + "px"+";height:"+anchorHeight+";position:absolute;left:"+ locationLeft + "px"+";top:0.3%;\" ><p id=\"test\" class=\"popupDynamic\"> " + popupImageTitles[i] + "</p>";
anchorElement += '</a>';
I would love to be able to add a mouse in/out effect whenever the user scrolls on the relevant anchor. each p tag contains unique information that needs to be conveyed and on hover only the relevant one should react.
I dont want to it it the below way, making two each of the methods every time a new element is created above. is there a way to have the following below which will work for a dynamic amount of elements?
$("#anchor" + etc).mouseover(function() {
document.getElementById("test").style.height="1.1em";
});
$("#anchor" + etc).mouseout(function() {
document.getElementById("test").style.height="1.1em";
});
My version of suggestions. the console logs works.
.popupHighlight {
color: red;
}
..
$('.boxOPToneplustwo').mouseover(function (e) {
console.log("in");
$(e.target).next('p').addClass("popupHighlight");
});
$('.boxOPToneplustwo').mouseout(function (e) {
$(e.target).next('p').removeClass("popupHighlight");
});
What about selecting all a elements?
$('a').mouseout(function() {
//do stuff in here
});
or better yet, have a class selector:
$('.mySpecialRolloverClass').mouseover(function (e) {
$(e.target).next('p').addClass("highlight");
});
$('.mySpecialRolloverClass').mouseout(function (e) {
$(e.target).next('p').removeClass("highlight");
});
which would go hand in hand with
An anchor
and
.highlight {
color:red;
}
Here's a jsfiddle demo:
http://jsfiddle.net/8J6kM/
The #yochannah answer is correct, however if you want to add more links dynamically, you then need to use on method instead of mouseover and mouseout, otherwise it won't work. See the demo and jQuery documentation for further details.
// I assumed that links are placed inside of a container element: #links
$('#links').on('mouseover', '.mySpecialRolloverClass', function (e) {
$(e.target).next('p').addClass("highlight");
});
I have two sets of divs — one that is the 'main' div and one that is the 'extra' div. Both of these have classes that are brought in via the CMS.
What's the best way of showing/hiding (preferably slideToggle) each div, on click, that corresponds to the div clicked?
<div class="each-business-content-main" data-id="group-1"></div>
<div class="each-business-content-main" data-id="group-2"></div>
<div class="each-business-content-extra group-1"></div>
<div class="each-business-content-extra group-2"></div>
These 'group-1' or 'group-2' classes aren't known in advance so can't be hard-coded in. Essentially I'm wondering how, if you click on one div it shows another div (as long as they share the same class name).
I've tried this so far:
$('.each-business-content-main').on('click', function (e) {
e.preventDefault();
var id = $(this).data('id');
jQuery('.each-business-content-extra').slideUp();
jQuery('.each-business-content-extra .' + id).slideDown();
});
But I'm guessing hrefs and id might come in useful? Or some other data-id...
If you assign a data attribute to your divs it makes this pretty easy:
<div class="each-business-content-main group-1" data-group="1">main 1</div>
<div class="each-business-content-main group-2" data-group="2">main 2</div>
<div class="each-business-content-extra group-1" data-group="1">extra 1</div>
<div class="each-business-content-extra group-2" data-group="2">extra 2</div>
$('.each-business-content-main').click(function () {
$('.each-business-content-extra.group-' + $(this).data('group')).slideToggle();
});
jsFiddle example
Have you tried replacing this:
jQuery('.each-business-content .' + id).slideDown();
...with this:
jQuery('.each-business-content #' + id).slideDown();
jQuery selects classnames as .classname and IDs as #id.
Try
$('.each-business-content').click(function () {
var that = $(this);
$('.each-business-content').each(function () {
if ($(this) === that) {
$(this).slideUp();
} else {
$(this).slideDown();
}
});
});
Can you try this code at jsFiddle? Don't need group 1 and group 2, I use index instead of the name of the id. Is that all right for you?
$('.each-business-content-main').on('click', function (e) {
$('.each-business-content-extra').(':eq(' + $(this).index() + ')').slideDown();
$('.each-business-content-extra').not(':eq(' + $(this).index() + ')').slideUp();
});
I've got a list of items which can be expanded/collapsed individually or all at once with an Expand All/Collapse All button.
All the items start collapsed, but if you manually expand item so that every item is expanded, the 'Expand All' button should change to 'Collapse All'. Similarly if you collapse all the items it should change to 'Expand All'.
So every time you click on an individual line, it should check to see if ALL the items have now been collapsed/expanded, and if so, update the Expand/Collapse All button.
My problem is that I'm not sure how to iterate over all the items on a click to see if they are collapsed or not and properly update.
Here is a JSFiddle for this: JSFiddle
Here is my current code:
var expand = true;
jQuery.noConflict();
jQuery(function() {
jQuery('[id^=parentrow]')
.attr("title", "Click to expand/collapse")
.click(function() {
jQuery(this).siblings('#childrow-' + this.id).toggle();
jQuery(this).toggleClass("expanded collapsed");
ExpandCollapseCheck();
});
jQuery('[id^=parentrow]').each(function() {
jQuery(this).siblings('#childrow-' + this.id).hide();
if (jQuery(this).siblings('#childrow-' + this.id).length == 0)
jQuery(this).find('.expand-collapse-control').text('\u00A0');
});
jQuery('#childrow-' + this.id).hide("slide", { direction: "up" }, 1000).children('td');
});
function CollapseItems() {
jQuery('[id^=parentrow]').each(function() {
jQuery(this).siblings('#childrow-' + this.id).hide();
if (!jQuery(this).hasClass('expanded collapsed'))
jQuery(this).addClass("expanded collapsed");
});
}
function ExpandItems() {
jQuery('[id^=parentrow]').each(function() {
jQuery(this).siblings('#childrow-' + this.id).show();
if (jQuery(this).hasClass('expanded collapsed'))
jQuery(this).removeClass("expanded collapsed");
});
}
function ExpandCollapseChildren() {
if (!expand) {
CollapseItems();
jQuery('.expander').html('Expand All');
}
else {
ExpandItems();
jQuery('.expander').html('Collapse All');
}
expand = !expand;
return false;
}
function ExpandCollapseCheck() {
if ((jQuery('[id^=parentrow]').hasClass('expanded collapsed')) && (expand)) {
jQuery('.expander').html('Expand All');
CollapseItems();
expand = !expand;
}
else if ((!jQuery('[id^=parentrow]').hasClass('expanded collapsed')) && (!expand)) {
jQuery('.expander').html('Collapse All');
ExpandItems();
expand = !expand;
}
}
A couple of things I see with your code.
It seems that you may have multiple children with the same ID, such as #childrow-parent0. This is not legal HTML, and can lead to problems with JavaScript. Use classes instead.
Manipulating ID's to find children is more difficult than using built-in jQuery selectors to find children. I realize that in this case, they are siblings rather than true children, but you can still use .nextUntil(".parent") to find all of the "children" of a parent.
Use your click handlers to do the expanding/collapsing instead of repeating code. One you have a click handler, you can call .click() on a parent, and it will toggle as if you clicked it.
If half of your elements are collapsed, do you want "Expand All" or "Collapse All"? You might want both.
With all of that in mind, I wrote your code with a lot less lines. To answer your specific question, I just compared the number of '.parent.expanded' elements to the number of '.parent' elements to see if they were all expanded or not. (I changed to using a single .parent class.)
Demo
The relevant code to your question:
$('#expand_all').toggleClass("disabled", $('.parent.expanded').length == $('.parent').length);
$('#collapse_all').toggleClass("disabled", $('.parent.collapsed').length == $('.parent').length);
This uses toggleClass(), with the second argument returning true/false depending on the number of collapsed/expanded parents. This is used by toggleClass to determine whether the disabled class is applied.
Don't bother iterating, just use a selector to get a count of all the elements & their classes:
var $all = jQuery('selector to return all lines');
if($all.length == $all.filter('.collapsed').length)
//all the rows are collapsed
if($all.end().length == $all.filter('.expanded').length)
//all the rows are expanded
I want to set another class for the clicked menu-part. Clicking generates url with #NAME. Here is my menu:
<div id="head_menu">
<div name="order" id="menu_part">make order</div>
<div id="menu_part">portfolio</div>
<div id="menu_part">contacts</div>
<div id="menu_part">vacancies</div>
<div id="menu_part">about company</div>
</div>
I need to add class: 'menu_choosed' for clicked part. Here is my jquery-code:
$(document).ready(
function()
{
currentPage = window.location.hash;
$('#head_menu>div').each(
function()
{
if( currentPage == $(this).hash )
{
$(this).addClass("menu_choosed");
}
}
)
}
)
I really don't know, how to filter values :( Help, please.
The easy way:
$(document).ready(
function()
{
currentPage = window.location.hash;
$('#head_menu a[href=' + currentPage + '] div').addClass('menu_choosed');
}
);
There are a few problems with your HTML I would like to mention:
Nowadays, most people use lists (<ul>, mostly) for navigation.
Having a <div> inside an <a> is invalid if the <div> has display: block (default) and the <a> has display: inline (default).
One document may only have one element per ID. You currently have several elements with the menu_part id.
Using name for anchor points is not recommended. Prefer using ID's.
All IDs must be unique. You're currently repeating menu_part. I'd suggest removing the duplicate IDs. Give the nav links a class of "nav_link" and then use jquery to reference that class with an onclick event that changes the class to "menu_choosed".
Try this:
$(document).ready(
function()
{
var currentPage = window.location.hash;
$('#head_menu a div').each(
function()
{
if( currentPage == $(this).parent().attr("href") )
{
$(this).addClass("menu_choosed");
}
}
)
}
)
it should be $('#head_menu>a>div') I believe.
also, ids are supposed to be unique, so it could cause problems that you have multiple divs with the same id. you may want to change menu_part to a class.
You can use:
$("#head_menu").find("a[href=" + window.location.hash + "]").addClass('highlight')