Fuxi
Fuxi

Reputation: 7599

jQuery: selecting 2 elements next to each other with same class

here's my markup:

<button>next</button
<div class="seats">
  <div class="seat taken">1</div>
  <div class="seat taken">2</div>
  <div class="seat">3</div>
  <div class="seat">4</div>
  <div class="seat taken">5</div>
  <div class="seat">6</div>
  <div class="seat">7</div>
  <div class="seat taken">8</div>
  <div class="seat taken">9</div>
</div>

i'm looking for a way to select the first 2 free seats (which don't have class "taken"), given example should return seat 3+4. would there be an easy way to have a variable amount of seats, eg. selecting 4 seats next to each other? is it possible defining a offset where to start searching free seats? i mean i want to hit the next button and it should pick the next 2 free seats (6+7). thanks in advance.

Upvotes: 3

Views: 1230

Answers (2)

Josh Crozier
Josh Crozier

Reputation: 241198

You could utilize the :not() pseudo-class and the methods .eq(), .nextUntil(), and .addBack() in order to achieve this in a single line:

$('.seat.taken + .seat:not(.taken)').eq(index).nextUntil('.taken').addBack()

It's also worth pointing out that this will work for groups of elements of varying lengths (not just groups of two elements).

Explanation:

  • The initial query, $('.seat.taken + .seat:not(.taken)') will select .seat elements without a class of .taken that follow an element with the classes .seat and .taken.

  • The .eq(index) method will reduce the set based on the index variable (where index denotes which group of available seats that you want to select).

  • The .nextUntil('.taken') method will select all the following elements until another .taken element.

  • Then the initial element is added back to the query with .addBack().

Basic example:

var index = 0;
$('.next').on('click', function () {
  $('.seat.taken + .seat:not(.taken)').eq(index).nextUntil('.taken').addBack().toggleClass('selected');
  
  index++;
});
.selected { background-color: #f00; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="next">next</button>
<div class="seats">
  <div class="seat taken">1</div>
  <div class="seat taken">2</div>
  <div class="seat">3 - Not taken</div>
  <div class="seat">4  - Not taken</div>
  <div class="seat taken">5</div>
  <div class="seat">6 - Not taken</div>
  <div class="seat">7 - Not taken</div>
  <div class="seat">8 - Not taken</div>
</div>

And if you want to cycle through the elements, you could create a basic function that returns a group of available seats based on the index:

function getNextGroup (index) {
  return $('.seat.taken + .seat:not(.taken)').eq(index).nextUntil('.taken').addBack();
}

Then you can call the function to determine if index + 1 yields any elements. If it doesn't, then you would reset index back to 0 like in the example below:

Updated example:

var index = 0;
$('.next').on('click', function () {  
  $('.seat.selected').removeClass('selected');
  getNextGroup(index).toggleClass('selected');
  
  index = getNextGroup(index + 1).length ? index + 1 : 0;
});

function getNextGroup (index) {
  return $('.seat.taken + .seat:not(.taken)').eq(index).nextUntil('.taken').addBack();
}
.selected { background-color: #f00; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="next">next</button>
<div class="seats">
  <div class="seat taken">1</div>
  <div class="seat taken">2</div>
  <div class="seat">3 - Not taken</div>
  <div class="seat">4  - Not taken</div>
  <div class="seat taken">5</div>
  <div class="seat">6 - Not taken</div>
  <div class="seat">7 - Not taken</div>
  <div class="seat">8 - Not taken</div>
  <div class="seat taken">9</div>
  <div class="seat taken">10</div>
  <div class="seat">11 - Not taken</div>
  <div class="seat">12 - Not taken</div>
  <div class="seat">13 - Not taken</div>
  <div class="seat">14 - Not taken</div>
  <div class="seat taken">15</div>
  <div class="seat">16 - Not taken</div>
</div>

Upvotes: 1

Glubus
Glubus

Reputation: 2855

Assuming you're allowed and able to add some more information to each chair: I'd extend your current html so that it'd look like this:

<button>next</button>
<div class="seats">
  <div class="seat taken" data-chairNumber="0">1</div>
  <div class="seat taken" data-chairNumber="1">2</div>
  <div class="seat" data-chairNumber="2">3</div>
  <div class="seat" data-chairNumber="3">4</div>
  <div class="seat taken" data-chairNumber="5">5</div>
  <div class="seat" data-chairNumber="6">6</div>
  <div class="seat" data-chairNumber="7">7</div>
  <div class="seat taken" data-chairNumber="8">8</div>
  <div class="seat taken" data-chairNumber="9">9</div>
</div>

Then use jQuery to only select the non taken chairs:

var chairs = $(".seat:not(.taken)");

Then walk over these chairs and check whether or not there exists a pair (probably extend this for bigger combinations):

var chairs = $(".seat:not(.taken)");
var currentChair = -2; //idunnkno
$.each(chairs, function(chair) {
    var chairnumber = $(chair).data("chairNumber");
    if(chairnumber - 1 === currentChair)
    {
         return { chairA : currentChair, chairB : chairNumber };
    }
    else {
         currentChair = chairnumber;
    }
});

Return an object with the chairs if you find a pair.

Upvotes: 1

Related Questions