Jean-Paul Bardou
Jean-Paul Bardou

Reputation: 117

Jquery Create double array of .click functions on divs for interaction between the divs

This is a follow up to my question from yesterday (Jquery Create "array" of .click functions".)

Yesterday, I thought that I would simplify what I asked, hoping that I could extrapolate. I could not, and there is still something I can't figure out.

Therefore this new question, and PLEASE, I do admit that I am a newbie, and my question might seem soooo stupid for some of you, be patient with me!

I have a set of double divs:

<div id="div_a_1" class="pingpongdiv">hkh</div><div id="div_b_1" class="pingpongdiv">nuigyuig</div>
<div id="div_a_2" class="pingpongdiv">uynyn</div><div id="div_b_2" class="pingpongdiv">,jomoi</div>
<div id="div_a_3" class="pingpongdiv">yfvrcers</div><div id="div_b_3" class="pingpongdiv">rdcsers</div>

At present time, the above code is written by hand, and I plan on generating it with Jquery in the future, based on the number sets of divs I need.

They got the following css:

.pingpongdiv { /* make divs nearly invisible */
  opacity: .15;
}

What I want to achieve with them is the following:

When I click on an "a" or a "b" div, its opacity is brought from .15 to 1 (becomes visible) by an animation. There is a catch, though: I must have clicked on the "a" div at least one time before I get to "activate" the corresponding "b" div!

I have the following jquery code (remember, I am new to this, and I might be using very cumbersome methods where it could be a lot more elegant, help me to it):

// define the array of flags used to check whether an "a" div was clicked on.
var leftPictureSeen = [];
leftPictureSeen[0] = 0; // never used because divs names start at 1

for (var i = 1; ; i++) {
  if ($('#div_a_' + i.toString()).length) // If this div exists, add one more element to the array
    leftPictureSeen[i] = 0;
  else break;
}

// Attach the function that are needed for the divs to be seen and "unseen".
// ATTENTION: Here I mix what I learned yesterday about using "this"
// and I still have an "i" in the function definition, although I know that "i" is out of scope there.
// The idea is that I would like to know how I manage this issue properly so that it works
for (var i = 1; i < leftPictureSeen.length; i++)
{
    $("#div_a_" + i.toString()).click(function(){
        $(this).animate({opacity:1}, 1000);
        // How do I replace the line below so that it works?
        leftPictureSeen[i] = 1; // When an "a" div has been clicked, enable the "b" div click
    });

    $("#div_a_" + i.toString()).mouseout(function(){
        $(this).animate({opacity:.15}, 1000);
    });

    $("#div_b_" + i.toString()).click(function(){
        if (leftPictureSeen[i] === 1) // HOW DO I FIX THIS LINE SO THAT IT WORKS?
            $(this).animate({opacity:1}, 1000);
        else alert("You must click on the 'a' div first...");
    });

    $("#div_b_" + i.toString()).mouseout(function(){
        $(this).animate({opacity:.15}, 1000);
    });

};

It could be that there is a much simpler way to do all this, maybe by adding a css attribute to the "a" divs to indicate that they have been clicked on, what do I know!

And, if that was not enough, will somebody be kind enough to explain to me, or send me to a link somewhere that explains the issue of "i" being out of the scope of the .click function if that is what it is called?

Thank you very much for you patience ... and your help.

Upvotes: 0

Views: 47

Answers (4)

madalinivascu
madalinivascu

Reputation: 32354

Use the next() function to get the next element and add a active class to it

Try the following:

$(".pingpongdiv[id^='div_a']").click(function(){
        $(this).animate({opacity:1}, 1000);
        $(this).next().addClass('active');
        
    }).mouseout(function(){
        $(this).animate({opacity:.15}, 1000);
    });
$('body').on('click',".active",function(){
        $(this).animate({opacity:1}, 1000);           
    }).mouseout(function(){
        $('.active').animate({opacity:.15}, 1000);
    });
.pingpongdiv {
  opacity:.15;
  }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div id="div_a_1" class="pingpongdiv">hkh</div><div id="div_b_1" class="pingpongdiv">nuigyuig</div>
<div id="div_a_2" class="pingpongdiv">uynyn</div><div id="div_b_2" class="pingpongdiv">,jomoi</div>
<div id="div_a_3" class="pingpongdiv">yfvrcers</div><div id="div_b_3" class="pingpongdiv">rdcsers</div>

Upvotes: 0

David Thomas
David Thomas

Reputation: 253318

One approach to the problem is the following, though note that I've made no use of the unnecessary id properties of each of the elements, though I have introduced two data-* attributes which will allow CSS to handle the animations and the fade-in:

// binding the anonymous function of the on() method as
// the event-handler for the 'click' event received by
// any element with the 'pingpongdiv' class-name:
$('.pingpongdiv').on('click', function() {
  
  // here we store the current 'letter' of the clicked
  // element, retrieving it from the letter property of
  // the HTMLElement.dataset object, which is the
  // data-letter attribute from the element; then we
  // convert that letter to its lower-case form (this
  // ensures that it will always be lower-case in the
  // following comparison):
  let letter = this.dataset.letter.toLowerCase(),
      
    // we cache the previousElementSibling:
    previous = this.previousElementSibling;

  // if the data-letter attribute is exactly equal to 'a':
  if (letter === 'a') {
    
    // we assign the String 'true' to the value of
    // the HTMLElement.dataset.clicked property,
    // which is also placed in the data-clicked
    // attribute-value:
    this.dataset.clicked = 'true';
    
  // otherwise if the letter is exactly equal to 'b'
  // AND there is a previous element AND that previous
  // element has been clicked (its data-clicked is
  // exactly equal to 'true'):
  } else if (letter === 'b' && previous && previous.dataset.clicked === 'true') {
    
    // we then assign the String of 'true' to
    // the clicked 'b' element (having done this
    // the CSS can now handle the animation):
    this.dataset.clicked = 'true';
  }
  
  // you may notice there's no 'else' statement,
  // this is by design since in the else we'd
  // want nothing to happen anyway.
  
});
body {
  text-align: center;
}
div {
  box-sizing: border-box;
  width: 40%;
  height: 2em;
  line-height: 2em;
  display: inline-block;
  border: 2px solid #000;
  margin-bottom: 1em;
}
.pingpongdiv {
  opacity: 0.2;
  /* setting the transition/animation,
     we transition all properties,
     over a duration of 1 second, and
    use a linear animation to do so: */
  transition: all 1s linear;
}
.pingpongdiv[data-letter=a] {
  border-radius: 1em 0 0 1em;
}
.pingpongdiv[data-letter=b] {
  border-radius: 0 1em 1em 0;
}
.pingpongdiv[data-letter=a][data-clicked=true] {
  border-color: #f90;
}
.pingpongdiv[data-letter=b][data-clicked=true] {
  border-color: limegreen;
}

/* almost everything above this point is purely
   aesthetic; this part handles the animations
   which was defined above (and was the non-
   aesthetic part above): */

/* here we select an element with a class of
   'pingpongdiv' with a 'data-letter' attribute
   equal to 'a' *and* has a 'data-clicked'
   attribute equal to 'true': */
.pingpongdiv[data-letter=a][data-clicked=true],

/* here we select an element of class 'pingpongdiv'
   with a 'data-letter' attribute equal to 'b' *and*
   a 'data-clicked' attribute equal to 'true' which
   follows an element matching the previous selector: */
.pingpongdiv[data-letter=a][data-clicked=true] + .pingpongdiv[data-letter=b][data-clicked=true] {
  
  /* and updates the opacity property, which
     will transition according to the above
     transition property-value: */
  opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="div_a_1" class="pingpongdiv" data-letter="a">hkh</div>
<div id="div_b_1" class="pingpongdiv" data-letter="b">nuigyuig</div>
<div id="div_a_2" class="pingpongdiv" data-letter="a">uynyn</div>
<div id="div_b_2" class="pingpongdiv" data-letter="b">,jomoi</div>
<div id="div_a_3" class="pingpongdiv" data-letter="a">yfvrcers</div>
<div id="div_b_3" class="pingpongdiv" data-letter="b">rdcsers</div>

JS Fiddle demo.

As you may have noticed from the largely plain-JavaScript approach in the above code jQuery is not in any way necessary to meet the requirements of this question; so following is a pure JavaScript solution:

// here we create a named function to handle the checks
// and updates to the data-clicked attributes:
function pairAnimate() {
  // 'this' is passed automatically to the function
  // from the EventTarget.addEventListener() method
  // used later.

  // there are absolutely no changes to any parts
  // of what was the anonymous function (except
  // for its being named, to no longer be an
  // anonymous function):
  let letter = this.dataset.letter.toLowerCase(),
    previous = this.previousElementSibling;

  if (letter === 'a') {
    this.dataset.clicked = true;
  } else if (letter === 'b' && previous && previous.dataset.clicked === 'true') {
    this.dataset.clicked = true;
  }
}


// retrieving a NodeList of all <div> elements that have
// a 'data-letter' attribute, and using Array.from() to
// convert that Array-like NodeList into an Array:
var letterElements = Array.from(document.querySelectorAll('div[data-letter]'));


// iterating over each element in the Array of letterElements
// using Array.prototype.forEach():
letterElements.forEach(

  // here we use an Arrow function to bind the
  // the (poorly-named) 'pairAnimate' function as
  // handler for the 'click' event:
  letterElement => letterElement.addEventListener('click', pairAnimate)
);
body {
  text-align: center;
}
div {
  box-sizing: border-box;
  width: 40%;
  height: 2em;
  line-height: 2em;
  display: inline-block;
  border: 2px solid #000;
  margin-bottom: 1em;
}
.pingpongdiv {
  opacity: 0.2;
  transition: all 1s linear;
}
.pingpongdiv[data-letter=a] {
  border-radius: 1em 0 0 1em;
}
.pingpongdiv[data-letter=b] {
  border-radius: 0 1em 1em 0;
}
.pingpongdiv[data-letter=a][data-clicked=true] {
  border-color: #f90;
}
.pingpongdiv[data-letter=b][data-clicked=true] {
  border-color: limegreen;
}
.pingpongdiv[data-letter=a][data-clicked=true],
.pingpongdiv[data-letter=a][data-clicked=true] + .pingpongdiv[data-letter=b][data-clicked=true] {
  opacity: 1;
}
<div id="div_a_1" class="pingpongdiv" data-letter="a">hkh</div>
<div id="div_b_1" class="pingpongdiv" data-letter="b">nuigyuig</div>
<div id="div_a_2" class="pingpongdiv" data-letter="a">uynyn</div>
<div id="div_b_2" class="pingpongdiv" data-letter="b">,jomoi</div>
<div id="div_a_3" class="pingpongdiv" data-letter="a">yfvrcers</div>
<div id="div_b_3" class="pingpongdiv" data-letter="b">rdcsers</div>

JS Fiddle demo.

References:

Upvotes: 1

Use jquery fadeTo, it's more simple. And indexOf to search a string in your id, something like this:

$(".pingpongdiv").click(function(){
  if ($(this).attr("id").indexOf("a") > -1)
    $(this).fadeTo(1000, 1);      
  else
    alert("You must click on the 'a' div first...");
  
}).mouseout(function(){
  $(this).fadeTo(1000, .15);      
});
.pingpongdiv {
  opacity:.15;
  cursor:pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="div_a_1" class="pingpongdiv">hkh</div><div id="div_b_1" class="pingpongdiv">nuigyuig</div>
<div id="div_a_2" class="pingpongdiv">uynyn</div><div id="div_b_2" class="pingpongdiv">,jomoi</div>
<div id="div_a_3" class="pingpongdiv">yfvrcers</div><div id="div_b_3" class="pingpongdiv"></div>

Upvotes: 0

Mamdouh Saeed
Mamdouh Saeed

Reputation: 2324

var a = [];
    var b = [];
    for (var i = 1; i < leftPictureSeen.length; i++) {
      a.push("#div_a_" + i);
    }
    a = a.join(" , ");
    b = b.join(" , ");
    $(a).on("click", function() {
      var i = +$(this).attr("id").replace("div_a_", "");
      /*   code here for #div_a_x  and work with i   */
    });
    $(b).on("click", function() {
      var i = +$(this).attr("id").replace("div_b_", "");
      /*   code here for #div_b_x  and work with i   */
    });

    $(a).on("mouseout", function() {
      var i = +$(this).attr("id").replace("div_a_", "");
      /*   code here for #div_a_x  and work with i   */
    });
    $(b).on("mouseout", function() {
      var i = +$(this).attr("id").replace("div_b_", "");
      /*   code here for #div_b_x  and work with i   */
    });

Upvotes: 0

Related Questions