Connecting click events to multiple items, without the need for multiple functions

I'm struggling with the efficiency of my Javascript and I believe there must be a better way to achieve my goal. To demonstrate my issue, I've created a simplified version of my project on JSFiddle.

JSFiddle

The main objective is to display information in the large grey box when a block on the left is clicked. This functionality is working in the JSFiddle example! However, I currently have a separate javascript function for each block. (In reality, my project has over 70 blocks)

Each function hides all previously clicked blocks and removes their "clicked" class. The "clicked" class serves as a flag to determine whether to hide or show the information.

Below is an example of one of the functions. Is this the most effective approach? Keep in mind, I have to go through and hide each info block every time in my actual project.

$('.block1').on('click', function (e) {
    if ($(this).hasClass('block1-clicked')) {
       $('.block1-info').fadeOut();
    }
    else {
        $('.block2-info').fadeOut();
        $('.block2').removeClass('block2-clicked');
        $('.block3-info').fadeOut();
        $('.block3').removeClass('block3-clicked');
        $('.block4-info').fadeOut();
        $('.block4').removeClass('block4-clicked');
        $('.block1-info').fadeIn();

    }
   $(this).toggleClass('block1-clicked') ;
});

Thank you for your help!

Answer №1

If you're looking to achieve this effect, there are a variety of methods you can use. One way is to utilize a specific pattern that allows you to control the state of a DIV based on the ID of the unit that was clicked. By implementing two distinct classes, you can easily manage the items on the page.

<div id="block1" class="block">Block 1</div>
. . .

<div class="info"></div>
<div class="blockinfo block1">Info about Block 1</div>
... and so on

Here is an example of how you can achieve this using JavaScript:

$('.block').on('click', function() {
     var myId = $(this).attr('id');
     $('.block').removeClass('clicked');
     $(this).addClass('clicked');
     $('.blockinfo').fadeOut();
     $('.' + myId).fadeIn();
})

Answer №2

I've simplified everything, taking out the animation, to demonstrate the fundamental structure and created a new fiddle for you to view: http://jsfiddle.net/7E3ch/

Code Snippet:

<div id="blocks">
    <div id="block1" class="block" data-info="Info about Block 1">Block 1</div>
    <div id="block2" class="block" data-info="Info about Block 2">Block 2</div>
    <div id="block3" class="block" data-info="Info about Block 3">Block 3</div>
    <div id="block4" class="block" data-info="Info about Block 4">Block 4</div>
</div>
<div id="info"></div>

Javascript:

$(".block").on("click", function (e) {
    $("#info span").hide();
    $("#info").append("<span>" + $(this).data("info") + "</span>");
});

CSS:

#blocks{
    float:left;
}

.block {
    margin-left:20px;
    margin-top:10px;
    height:40px;
    width:140px;
    display:block;
}

#block1 {
    background-color:red;
}

#block2 {
    background-color:blue;
}

#block3 {
    background-color:green;
}

#block4 {
    background-color:orange;
}

#info {
    margin-left:180px;
    margin-top:10px;
    height:190px;
    width:140px;
    display:block;
    position:absolute;
    background-color:grey;
}

Key takeaways:

  • Utilize generic classes for flexibility in applying animations and styles.
  • Remember the abbreviation: DRY (Don't Repeat Yourself)
  • Maximize the use of data attributes.

Hopefully, this explanation is beneficial. Best of luck with your project!

Answer №3

To streamline the functionality, one approach is to group all buttons and information blocks within wrapper elements. By adding a single click handler to these wrappers, it becomes possible to selectively display the desired information block while hiding others.

Introducing a data-* attribute helps in associating each button with its corresponding info block for seamless operation.

<div id="block-buttons">
  <div class="block1" data-target="block1-info">Block 1</div>
  <div class="block2" data-target="block2-info">Block 2</div>
  <div class="block3" data-target="block3-info">Block 3</div>
  <div class="block4" data-target="block4-info">Block 4</div>
</div>


<div class="info-blocks">
  <div class="block1-info">Info about Block 1</div>
  <div class="block2-info">Info about Block 2</div>
  <div class="block3-info">Info about Block 3</div>
  <div class="block4-info">Info about Block 4</div>
</div>

Javascript:

$("#block-buttons").on("click", "div", function (clickEvent) {
    var target = $(clickEvent.target).data("target");
    $(".info-blocks > div").fadeOut();
    $("." + target).fadeIn();
});

If there is uniformity in button styling, eliminating the block1 to block4 classes can simplify the code further.

Furthermore, switching to CSS transitions instead of jQuery fadeIn/out can enhance performance, especially for browsers that support hardware rendering like IE9 and newer versions.

Answer №4

When faced with situations like these, we often rely heavily on utilizing custom data attributes () -

<div class="selector" data-block="d1">Block 1</div>
<div class="selector" data-block="d2">Block 2</div>
<div class="selector" data-block="d3">Block 3</div>
<div class="selector" data-block="d4">Block 4</div>


<div class="info active"></div>
<div class="info" data-info="d1">Info about Block 1</div>
<div class="info" data-info="d2">Info about Block 2</div>
<div class="info" data-info="d3">Info about Block 3</div>
<div class="info" data-info="d4">Info about Block 4</div>

This allows us to significantly reduce the amount of code needed -

$('.selector').click(function() {
    var selectedBlock = $(this).data('block');
    $('.info').removeClass('active');
    $('.info[data-info=' + selectedBlock + ']').addClass('active');    
});

Personally, I find this method less elegant compared to the approach taken by Moby's Stunt Double. He manages to streamline the process without the need for additional lines of markup for each block.

Answer №5

It is essential to hide only one block at most, specifically the one that was previously active, and then reveal only one block when a change happens. The key is to remember which block was active before, fade it out by removing its class, and then fade in the new block.

Answer №6

Rather than cluttering the gray div with multiple sub-divs and checking for clicks to remove a class, consider using jQuery's .html() or .text() to directly set the text content of the gray div. Check out more information about these methods here:

http://api.jquery.com/html/

http://api.jquery.com/text/

Answer №7

Check out this easy method that uses common classes and indexing:

HTML:

<div class="section part1">Part 1</div>
<div class="section part2">Part 2</div>

<div class="details part1-info">Information about Part 1</div>
<div class="details part2-info">Information about Part 2</div>

JS:

var $sections=$('.section'), $details=$('.details').hide();
$sections.click(function(){
   var index=$sections.removeClass('active').index(this);
    $(this).addClass('active')
    $details.filter(':visible').fadeOut()
    $details.eq(index).fadeIn();
});

Check out the DEMO

Answer №8

(I have improved my previous answer with a more robust solution...)

This new solution eliminates the need for special numbered classes or IDs, making it easier to add 70 sections without specifying a class for each one.

Check out this cleaner solution on jsFiddle. It utilizes a single click handler for all the buttons on the left and utilizes CSS3 transitions to fade in/out the information boxes. It simplifies the structure by using indexes instead of data-target and boxN-info attributes and classes, assuming that buttons and info blocks are aligned in the same order:

http://jsfiddle.net/5dQUk/11/

Html:

<ul class="block-buttons">
  <li class="active">Block 1</div>
  <li>Block 2</div>
  <li>Block 3</div>
  <li>Block 4</div>
</ul>

<div class="info-blocks">
  <div class="active">Info about Block 1</div>
  <div>Info about Block 2</div>
  <div>Info about Block 3</div>
  <div>Info about Block 4</div>
</div>

CSS

.block-buttons {
    list-style: none;
    margin: 0;
    padding: 0;
    float: left;
}

.block-buttons li {
    border: 1px solid #777;
    background-color: #eee;
    cursor: pointer;
    margin-bottom: 2px;
    padding: 2px;
}

.block-buttons li.active {
    background-color: #aaa;    
}

.info-blocks {
    position: relative;
    min-width: 100px;
    min-height: 100px;
    border: 1px solid #777;
    margin-left: 10px;
    float: left;
}

.info-blocks > div {
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    opacity: 0;
    transition: opacity 0.4s ease-in 0s;
    -ms-transition: opacity 0.4s ease-in 0s;
    -moz-transition: opacity 0.4s ease-in 0s;
    -webkit-transition: opacity 0.4s ease-in 0s;
}

.info-blocks > div.active {
    opacity: 1;
    transition: opacity 0.4s ease-out 0.4s;
    -ms-transition: opacity 0.4s ease-out 0.4s;
    -moz-transition: opacity 0.4s ease-out 0.4s;
    -webkit-transition: opacity 0.4s ease-out 0.4s;
}

JS:

$(".block-buttons").on("click", "li", function (clickEvent) {
    var $clickedElement = $(clickEvent.target);
    var index = $clickedElement.index();

    // set class on selected button
    $(".block-buttons > li").removeClass("active");
    $clickedElement.addClass("active");

    // set class on selected panel
    $(".info-blocks > div")
        .removeClass("active")
        .eq(index)
        .addClass("active");
});

Answer №9

I Decided to Go All Out!

Play around with the Fiddle: http://jsfiddle.net/3A5M6/


After seeing that your code had quite a bit of redundancy, I took the liberty to strip away as much as possible:

Let's Start with the HTML

<div id="blocksAndInfo">
    <div class="blockContainer" onmousedown="return false">
        <div class="block" id="b1">Block 1</div>
        <div class="block" id="b2">Block 2</div>
        <div class="block" id="b3">Block 3</div>
        <div class="block" id="b4">Block 4</div>
    </div>

    <div class="infoContainer">
        <div class="info b1">Info about Block 1</div>
        <div class="info b2">Info about Block 2</div>
        <div class="info b3">Info about Block 3</div>
        <div class="info b4">Info about Block 4</div>
    </div>
</div>

Moving on to the JS

$('.block').on('click',function(){
    if ($(this).hasClass('active')) {
        //deactivate the clicked block, and hide its info
        $(this).removeClass('active');
        $('.info.'+$(this).attr('id')).fadeOut();
    } else {
        //first deactivate any possible active block, and hide its info
        $('.block').removeClass('active');
        $('.info').fadeOut();
        //then activate the clicked block, and show its info
        $(this).addClass('active');
        $('.info.'+$(this).attr('id')).fadeIn();
    }
});

And a Touch of CSS

#blocksAndInfo {
    height: 190px;
    margin: 20px 0px 0px 20px;
}

.blockContainer {
    float: left;
    width: 140px;
    height: 100%;
}
.block {
    width: 100%;
    margin: 0px 0px 10px 0px;
    padding: 5px 0px;
    border: 2px solid transparent;
    cursor: pointer;
}
.block:last-child {margin-bottom:0px;}
.block.active {border:2px solid black;}
.block#b1 {background-color:red;}
.block#b2 {background-color:blue;}
.block#b3 {background-color:green;}
.block#b4 {background-color:orange;}

.infoContainer {
    position: relative;
    float: left;
    width: 140px;
    height: 100%;
    margin: 0px 0px 0px 20px;
    padding 5px;
    background-color: grey;
}
.info {
    display: none;
    position: absolute;
    width: 100%;
    height: 100%;
}

If you dive into the CSS within the jsFiddle, you'll find some extra styling tricks and tweaks added.

Answer №10

Hopefully, this information proves useful to you. Check out this fiddle

Here is the HTML code:

<div class="block1 block" value="Information about Block 1">Block 1</div>
<div class="block2 block" value="Information about Block 2">Block 2</div>
<div class="block3 block" value="Information about Block 3">Block 3</div>
<div class="block4 block" value="Information about Block 4">Block 4</div>

<div class="info"></div>

And here is the JavaScript code:

$(".block").click(function() {
    var value = $(this).attr('value');
    $(".info").html(value);
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the method for obtaining the CSS text content from an external stylesheet?

I've spent countless hours trying to achieve the desired results, but unfortunately, I haven't been successful. Below is a summary of my efforts so far. Any helpful tips or suggestions would be greatly appreciated. Thank you in advance. Upon rec ...

Linking Background Images in HTML

Is there anyone who can provide assistance with this question? I am looking for a solution where I can have a link with a background image, placed in a row within a table. Your help would be greatly appreciated. Thank you ...

The 'in' operand is invalid

I am encountering a JavaScript error: "[object Object]" TypeError: invalid 'in' operand a whenever I attempt to perform an AJAX request using the following code: .data("ui-autocomplete")._renderItem = function( ul, item ) { return $( " ...

"Can you tell me the method for obtaining an array within an Angular

Within the realm of PHP, there exist certain elements within an array: $this->data['messages']['ms'][] = 'Line1'; $this->data['messages']['ms'][] = 'Line2'; along with a method that return ...

Tips for accessing the ID in a specific row of a datatable

My module displays a list of customer details in a datatable with a button for action. Why am I unable to retrieve the id of the button added to each row? When I click the button, no alert is displayed. What could be causing this issue? Below is my ajax ...

Angular URL changes causing template flickering

Currently, I am in the process of developing a small application using Angular, but I am encountering an issue with template flickering. This problem occurs when one template is displayed briefly and then immediately switches to another. In my base templa ...

Tips for maintaining grid width when columns are rearranged in the column menu

Is it possible to stop jqgrid from changing its width to full screen after column selection? I attempted the code below, following guidance from How to change column name in column chooser pop up in jqgrid? My aim was to create a column switcher function ...

Is there a method to preserve the pressed/focused state when moving from one input box to the next?

While creating a form for a client, I encountered a requirement where the input box should change once clicked and retain that change even after it has been filled and the user moves to the next input box. Is there a way to achieve this using only HTML & C ...

Utilizing DOMStringMap data to populate CSS URLs

I am attempting to create a universal CSS modification for a webpage element that resembles: <button data-action="link" class="cardImageContainer coveredImage cardContent itemAction lazy lazy-image-fadein-fast" data-blurhash="lo ...

The data point on jqPlot does not display in full

I've been working on creating a chart with jqPlot to display data for each hour. It's mostly going well, but there's an issue where the first and last data points are not showing correctly - part of the circle is getting cut off. Here' ...

Enhancing user experience: Implementing specific actions when reconnecting with Socket.io after a disconnection

I am working on a game using node.js and socket.io. The code I have written is quite simple. The game starts animating as soon as it connects to the server and continues to do so. My main concern is ensuring that the game handles network and server disco ...

Improving the performance when toggling visibility of multiple div elements

Having implemented a show/hide effect on a lengthy list of titles and definitions, I've found the speed at which it occurs to be quite sluggish. The code used was sourced from elsewhere, so I can't take full credit for it. One potential reason fo ...

How can I create my own custom pagination and sorting features instead of relying on the default ui-bootstrap options?

Can anyone provide assistance with resolving conflicts I am experiencing while using ui-bootstrap? ...

Sorting through an array using several filter arrays

Is there a way to efficiently filter an array of items based on multiple filter arrays? Each item has various filters, and I want to display only the ones that match all selected filters. const selectedFilters = { color: ["Red", "Blue"], type: ["S ...

Is it possible to postpone sending a message on Discord until a certain event has been successfully completed?

After the User leaves the Discord, I attempted to create a RichEmbed Message that would include a random GIF from Giphy. The GIF was meant to be generated using the getGiphyPic() function with the help of this node module: https://github.com/risan/giphy-ra ...

Exploring the Difference Between $onChanges and $onInit in Angular Components

What sets apart the use of Controller1 compared to Controller2? angular.module('app', []) .component('foo', { templateUrl: 'foo.html', bindings: { user: '<', }, controller: Controller1, ...

The buffer for the operation `users.insertOne()` exceeded the timeout limit of 10000 milliseconds, resulting in a Mongoose

I am currently utilizing a generator that can be found at this Github link Project repository: Github Project Link Encountering an issue when attempting to input a user using the `MASTER_KEY`, I keep receiving the following error message: MongooseError ...

Error: TweenLite has not been recognized

/justincavery/pen/mPJadb - this is a link to CodePen After copying the code from CodePen and running it, I encountered an error: "Uncaught ReferenceError: TweenLite is not defined". The image only draws once and there is no animation unless I press "F5 ...

Localhost file not refreshing

I'm feeling quite frustrated at the moment. It seems like such a simple issue, but I can't seem to figure it out. I have created a basic webpage with a "tree-view" structure. In my readjson.js file, I am reading from a json file located in json/ ...

Creating an effective follow-following system in Node.js

I have built a Node.js application that features a basic follow system, allowing users to receive the latest articles from those they follow. The current implementation involves creating an array called followers, which stores the userIDs of all users fol ...