TechnoCorner
TechnoCorner

Reputation: 5165

Moving cards from Kanban board

I am trying to build this Custom Kanban (TODO) board from scratch (Vanilla JS, CSS, and no external libraries - jQuery is fine (preferred vanilla JS))

I'm currently stuck in a place where I'm trying to move cards from one row to another when user clicks on '>' (next) or '<' (previous). I'm not sure how to go about implementing something like this.

Here's my code: (Full page preferred) Codepen

.container {
  display: flex;
  flex-wrap: nowrap;
  justify-content: space-around;
  position: relative;
}

.board-column {
  display: flex;
  flex-direction: column;
  border: 1px solid grey;
  margin-left: 25px;
  box-sizing: border-box;
  background: #f0f0f0;
}

.board-column:last-child {
  margin-right: 25px;
}

.todo {
    width: 25%;
    text-align: center;
}

.board-column > .board-column-header {
  position: relative;
  height: 30px;
  line-height: 30px;
  text-align: center;
  color: white;
  padding: 0 36%;
  background: #333;
}

.board-column.todo .board-column-header {
  background: #4A9FF9;
}
.board-column.working .board-column-header {
  background: #f9944a;
}
.board-column.done .board-column-header {
  background: #2ac06d;
}

.board-column.backlog .board-column-header {
  background: red;
}

.board-column-content {
  position: relative;
  border: 10px solid transparent;
  min-height: 95px;
}

.board-item {
  width: 100%;
  margin: 10px 0;
}

.board-item-content {
  position: relative;
  padding: 20px;
  background: #fff; /* White */
  border-radius: 4px;
  font-size: 17px;
  cursor: pointer;
  box-shadow: 0px 1px 3px 0 rgba(0,0,0,0.2);
}

.next {
  position: relative;
  float: right;
  height: 21px;
  margin-right: -10px;
}

.prev {
  float: left;
  height: 21px;
  margin-left: -10px;
}
<article class="container">
  <section class="board-column todo">
    <section class="board-column-header"> TODO </section>
    <section class="board-column-content">
       <div class="board-item">
         <div class="board-item-content">
           <span>Item #</span>1<button class="action next"> > </button></div></div>
       <div class="board-item"><div class="board-item-content"><span>Item #</span>2<button class="action next"> > </button></div></div>
             <div class="board-item"><div class="board-item-content"><span>Item #</span>3<button class="action next"> > </button></div></div>
    </section>
  </section>
  
  <section class="board-column todo working">
    <section class="board-column-header"> Working </section>
    <section class="board-column-content">
       <div class="board-item"><div class="board-item-content">
         <button class="action prev"> < </button>
         <span>Item #</span>4<button class="action next"> > </button></div></div>
       <div class="board-item"><div class="board-item-content"><button class="action prev"> < </button><span>Item #</span>5<button class="action next"> > </button></div></div>
             <div class="board-item"><div class="board-item-content"><button class="action prev"> < </button><span>Item #</span>6<button class="action next"> > </button></div></div>
    </section>
  </section>
  
  <section class="board-column todo done">
    <section class="board-column-header"> Done </section>
    <section class="board-column-content">
       <div class="board-item"><div class="board-item-content"><button class="action prev"> < </button><span>Item #</span>7<button class="action next"> > </button></div></div>
       <div class="board-item"><div class="board-item-content"><button class="action prev"> < </button><span>Item #</span>8<button class="action next"> > </button></div></div>
             <div class="board-item"><div class="board-item-content"><button class="action prev"> < </button><span>Item #</span>9<button class="action next"> > </button></div></div>
    </section>
  </section>
  
    <section class="board-column todo backlog">
    <section class="board-column-header"> Backlog </section>
    <section class="board-column-content">
       <div class="board-item"><div class="board-item-content"><button class="action prev"> < </button><span>Item #</span>10</div></div>
       <div class="board-item"><div class="board-item-content"><button class="action prev"> < </button><span>Item #</span>11</div></div>
             <div class="board-item"><div class="board-item-content"><button class="action prev"> < </button><span>Item #</span>12</div></div>
    </section>
  </section>
  
</article>

How do I move cards from tow A to next row when user clicks on '>' (next) or '<' (previous)?

Can I make any optimizations for my current code to make it more readable?

Upvotes: 2

Views: 1275

Answers (1)

YellowAfterlife
YellowAfterlife

Reputation: 3202

Logic overview:

  • Find the item containing the button
  • Find the column containing that item
  • Find either next or previous column after that, depending on direction
  • Insert the item into that column's item list

As for structure, I wouldn't say it's too bad - one change I made was making it so that every item has previous/next buttons, but they are hidden via CSS where appropriate.

function findParentWithClass(el, className) {
  while (el && !el.classList.contains(className)) {
    el = el.parentElement;
  }
  return el;
}
function getElementChildIndex(el) {
  let i = 0;
  while (el = el.previousElementSibling) i++;
  return i;
}
function swapClick(btn, dir) {
  let item = findParentWithClass(btn, "board-item");
  let sct1 = findParentWithClass(item, "board-column");
  let sct2 = dir > 0 ? sct1.nextElementSibling : sct1.previousElementSibling;
  if (!sct2) return;
  //
  let dest = sct2.querySelector('.board-column-content');
  let pos = getElementChildIndex(item);
  dest.insertBefore(item, dest.children[pos]);
}
for (let el of document.getElementsByClassName('prev')) {
  el.addEventListener('click', (e) => swapClick(el, -1));
}
for (let el of document.getElementsByClassName('next')) {
  el.addEventListener('click', (e) => swapClick(el, 1));
}
.container {
  display: flex;
  flex-wrap: nowrap;
  justify-content: space-around;
  position: relative;
}

.board-column {
  display: flex;
  flex-direction: column;
  border: 1px solid grey;
  margin-left: 25px;
  box-sizing: border-box;
  background: #f0f0f0;
}

.board-column:last-child {
  margin-right: 25px;
}

.todo {
    width: 25%;
    text-align: center;
}

.board-column > .board-column-header {
  position: relative;
  height: 30px;
  line-height: 30px;
  text-align: center;
  color: white;
  padding: 0 36%;
  background: #333;
}

.board-column.todo .board-column-header {
  background: #4A9FF9;
}
.board-column.working .board-column-header {
  background: #f9944a;
}
.board-column.done .board-column-header {
  background: #2ac06d;
}

.board-column.backlog .board-column-header {
  background: red;
}

.board-column-content {
  position: relative;
  border: 10px solid transparent;
  min-height: 95px;
}

.board-item {
  width: 100%;
  margin: 10px 0;
}

.board-item-content {
  position: relative;
  padding: 20px;
  background: #fff; /* White */
  border-radius: 4px;
  font-size: 17px;
  cursor: pointer;
  box-shadow: 0px 1px 3px 0 rgba(0,0,0,0.2);
}

.next {
  position: relative;
  float: right;
  height: 21px;
  margin-right: -10px;
}

.prev {
  float: left;
  height: 21px;
  margin-left: -10px;
}

.board-column:first-child .action.prev { display: none }
.board-column:last-child .action.next { display: none }
<article class="container">
  <section class="board-column todo">
    <section class="board-column-header"> TODO </section>
    <section class="board-column-content">
      <div class="board-item"><div class="board-item-content">
          <button class="action prev"> &lt; </button>
          <span>Item #</span>1
          <button class="action next"> &gt; </button>
      </div></div>
      <div class="board-item"><div class="board-item-content">
          <button class="action prev"> &lt; </button>
          <span>Item #</span>2
          <button class="action next"> &gt; </button>
      </div></div>
      <div class="board-item"><div class="board-item-content">
          <button class="action prev"> &lt; </button>
          <span>Item #</span>3
          <button class="action next"> &gt; </button>
      </div></div>
    </section>
  </section>

  <section class="board-column todo working">
    <section class="board-column-header"> Working </section>
    <section class="board-column-content">
      <div class="board-item">
        <div class="board-item-content">
          <button class="action prev"> &lt; </button>
          <span>Item #</span>4
          <button class="action next"> &gt; </button></div>
      </div>
      <div class="board-item">
        <div class="board-item-content"><button class="action prev"> &lt; </button><span>Item #</span>5
          <button class="action next"> &gt; </button></div>
      </div>
      <div class="board-item">
        <div class="board-item-content"><button class="action prev"> &lt; </button><span>Item #</span>6
          <button class="action next"> &gt; </button></div>
      </div>
    </section>
  </section>

  <section class="board-column todo done">
    <section class="board-column-header"> Done </section>
    <section class="board-column-content">
      <div class="board-item">
        <div class="board-item-content"><button class="action prev"> &lt; </button><span>Item #</span>7
          <button class="action next"> &gt; </button></div>
      </div>
      <div class="board-item">
        <div class="board-item-content"><button class="action prev"> &lt; </button><span>Item #</span>8
          <button class="action next"> &gt; </button></div>
      </div>
      <div class="board-item">
        <div class="board-item-content"><button class="action prev"> &lt; </button><span>Item #</span>9
          <button class="action next"> &gt; </button></div>
      </div>
    </section>
  </section>

  <section class="board-column todo backlog">
    <section class="board-column-header"> Backlog </section>
    <section class="board-column-content">
      <div class="board-item"><div class="board-item-content">
        <button class="action prev"> &lt; </button>
        <span>Item #</span>10
        <button class="action next"> &gt; </button>
      </div></div>
      <div class="board-item"><div class="board-item-content">
        <button class="action prev"> &lt; </button>
        <span>Item #</span>11
        <button class="action next"> &gt; </button>
      </div></div>
      <div class="board-item"><div class="board-item-content">
        <button class="action prev"> &lt; </button>
        <span>Item #</span>12
        <button class="action next"> &gt; </button>
      </div></div>
    </section>
  </section>

</article>

Upvotes: 1

Related Questions