STEEZENS
STEEZENS

Reputation: 45

Single jQuery function to manipulate elements with the same ".class" independently

I want to duplicate the "voting-bar-container" div that carries jQuery functionality with it. However, because each duplicate carries with it the same ".classes" (and my jQuery Selectors target those classes), the jQuery is executed on each duplicate regardless of which "voting-bar-container" div is being interacted with.

I want the jQuery events to be executed ONLY on the elements being interacted with.

I believe the answer lies in my choice of Selectors as I know I don't need to duplicate my jQuery code for each duplicate HTML element with different "ID's".

https://jsfiddle.net/STEEZENS/aqd87b2d/

OR

Here is my HTML & jQuery:

<div class="voting-bar-container">

    <button class="upvote">
        <span class="upvote-counter">0</span>
    </button>

    <div class="vote-meter">
        <div class="upvotes"></div>
        <div class="downvotes"></div>
    </div>

    <button class="downvote">
        <span class="downvote-counter">0</span>
    </button>

</div>

jQuery:

$(document).ready(function () {

var $downvoteCount = 0;
var $upvoteCount = 0;

$(".upvote").click(function () {
    $upvoteCount++;
    $(".upvote-counter").text(" " + $upvoteCount);
    var $totalVoteCount = $upvoteCount + $downvoteCount;
    var $upvoteProportion = Math.round(($upvoteCount / $totalVoteCount) * 100);
    var $downvoteProportion = Math.round(($downvoteCount / $totalVoteCount) * 100);
    if (($upvoteProportion + $downvoteProportion) > 100) {
        $(".upvotes").width(($upvoteProportion - 0.5) + "%");
        $(".downvotes").width(($downvoteProportion - 0.5) + "%");
    } else {
        $(".upvotes").width($upvoteProportion + "%");
        $(".downvotes").width($downvoteProportion + "%");
    }
});

$(".downvote").click(function () {
    $downvoteCount++;
    $(".downvote-counter").text(" " + $downvoteCount);
    var $totalVoteCount = $upvoteCount + $downvoteCount;
    var $upvoteProportion = Math.round(($upvoteCount / $totalVoteCount) * 100);
    var $downvoteProportion = Math.round(($downvoteCount / $totalVoteCount) * 100);
    if (($upvoteProportion + $downvoteProportion) > 100) {
        $(".upvotes").width(($upvoteProportion - 0.5) + "%");
        $(".downvotes").width(($downvoteProportion - 0.5) + "%");
    } else {
        $(".upvotes").width($upvoteProportion + "%");
        $(".downvotes").width($downvoteProportion + "%");
    }
});
});

Upvotes: 1

Views: 211

Answers (2)

Mohamed-Yousef
Mohamed-Yousef

Reputation: 24001

you need to use $(this)

$(this).find(".upvote-counter")

instead of

$(".upvote-counter")

while you asked for (*What I want is for the jQuery events to be executed ONLY on the elements being interacted with) .. your code should be something like this .. you will need to use .closest() as well >> to get the downvote div related with the upvote div and reverse

   $(document).ready(function () {

    var $downvoteCount = 0;
    var $upvoteCount = 0;

    $(".upvote").click(function () {
        $upvoteCount++;
        $(this).find(".upvote-counter").text(" " + $upvoteCount);
        var $totalVoteCount = $upvoteCount + $downvoteCount;
        var $upvoteProportion = Math.round(($upvoteCount / $totalVoteCount) * 100);
        var $downvoteProportion = Math.round(($downvoteCount / $totalVoteCount) * 100);
        if (($upvoteProportion + $downvoteProportion) > 100) {
            $(this).width(($upvoteProportion - 0.5) + "%");
            $(this).closest('voting-bar-container').find(".downvotes").width(($downvoteProportion - 0.5) + "%");
        } else {
            $(this).width($upvoteProportion + "%");
            $(this).closest('voting-bar-container').width($downvoteProportion + "%");
        }
    });

    $(".downvote").click(function () {
        $downvoteCount++;
        $(this).find(".downvote-counter").text(" " + $downvoteCount);
        var $totalVoteCount = $upvoteCount + $downvoteCount;
        var $upvoteProportion = Math.round(($upvoteCount / $totalVoteCount) * 100);
        var $downvoteProportion = Math.round(($downvoteCount / $totalVoteCount) * 100);
        if (($upvoteProportion + $downvoteProportion) > 100) {
            $(this).closest('voting-bar-container').find(".upvotes").width(($upvoteProportion - 0.5) + "%");
            $(this).width(($downvoteProportion - 0.5) + "%");
        } else {
            $(this).closest('voting-bar-container').find(".upvotes").width($upvoteProportion + "%");
            $(this).width($downvoteProportion + "%");
        }
    });
});

DEMO

Note: this answer upon to your request .. you will need to work on it a little bit to reach a style you want

Upvotes: 5

Ohgodwhy
Ohgodwhy

Reputation: 50787

You need to be traversing the DOM to find the elements in question relative to the element that was clicked, instead of globally.

First, as you have multiple elements that have upvotes associated with them, the value of this and it's iteration needs to occur based on the existing upvote value of the element that is closest to upvote. Please observe below:

$(".upvote").click(function () {
    var upvote_counter = $(this).find('span'),
        downvote_counter = $(this).parent().find('.downvote-counter'),
        upvotes = $(this).parent().find('.upvotes'),
        downvotes = $(this).parent().find('.downvotes'),
        $upvoteCount = upvote_counter.text(),
        $downvoteCount = downvote_counter.text();

    $upvoteCount++;

    upvote_counter.text($upvoteCount);

    var $totalVoteCount = $upvoteCount + $downvoteCount;
    var $upvoteProportion = Math.round(($upvoteCount / $totalVoteCount) * 100);
    var $downvoteProportion = Math.round(($downvoteCount / $totalVoteCount) * 100);

    if (($upvoteProportion + $downvoteProportion) > 100) {
        upvotes.width(($upvoteProportion - 0.5) + "%");
        downvotes..width(($downvoteProportion - 0.5) + "%");
    } else {
        upvotes.width($upvoteProportion + "%");
        downvotes.width($downvoteProportion + "%");
    }       
});

This will allow you to properly select the elements that are closest associated with the upvote element that is clicked. Do something similar for the downvote function.

Upvotes: 1

Related Questions