0

Need help with my JS/HTML Kanban Board

I've been working on a selfmade Kanban Board in Ninox for some weeks now. I am a beginner and just starting courses + searching for code snippets everywhere.

Today I finally got a Kanban Board running on Ninox, with example cards that could be draged+dropped and an "add"-field.

Then I replaced the example content and succeeded filling the swimlanes with cards that represent one appointment from another table each. When you click on the card, the corresponding appointment pops up.

 

But unfortunately, now the JS-Functions (drag/drop and add) do not work anymore. Plus, after a while I restarted from scratch and now, I don't get the functions going, neither with my data nor with the example content.

Can someone with JS knowledge have a look, what I am doing wrong now?

 

let upApp := (select Appointments where Status = 1);
let finApp := (select Appointments where Status = 2);
let canApp := (select Appointments where Status = 3);
let css := "<style>
  * {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
  font-family: sans-serif;
  -ms-overflow-style: none; /* IE and Edge */
  scrollbar-width: none; /* Firefox */
}
*::-webkit-scrollbar {
  display: none;
}
.board {
  width: 100%;
  height: 100vh;
  overflow: scroll;

  background-position: center;
  background-size: cover;
}
/* ---- FORM ---- */
#todo-form {
  padding: 32px 32px 0;
}
#todo-form input {
  padding: 12px;
  margin-right: 12px;
  width: 225px;
  border-radius: 4px;
  border: none;
  box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.25);
  background: white;
  font-size: 14px;
  outline: none;
}
#todo-form button {
  padding: 12px 32px;
  border-radius: 4px;
  border: none;
  box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.25);
  background: #ffffff;
  color: black;
  font-weight: bold;
  font-size: 14px;
  cursor: pointer;
}
/* ---- BOARD ---- */
.lanes {
  display: flex;
  align-items: flex-start;
  justify-content: start;
  gap: 16px;
  padding: 24px 32px;
  overflow: scroll;
  height: 100%;
}
.heading1 {
  font-size: 22px;
  font-weight: bold;
  margin-bottom: 8px;
}
.swim-lane {
  display: flex;
  flex-direction: column;
  gap: 12px;
  background: #f4f4f4;
  box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.25);
  padding: 12px;
  border-radius: 4px;
  width: 225px;
  min-height: 120px;
  flex-shrink: 0;
}
.task {
  background: white;
  color: black;
  box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.15);
  padding: 12px;
  border-radius: 4px;
  font-size: 16px;
  cursor: move;
}
.is-dragging {
  scale: 1.05;
  box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.25);
  background: rgb(50, 50, 50);
  color: white;
}
  </style>";
let jsDrag := "<script>
const draggables = document.querySelectorAll('.task');
const droppables = document.querySelectorAll('.swim-lane');
draggables.forEach((task) => {
  task.addEventListener('dragstart', () => {
    task.classList.add('is-dragging');
  });
  task.addEventListener('dragend', () => {
    task.classList.remove('is-dragging');
  });
});
droppables.forEach((zone) => {
  zone.addEventListener('dragover', (e) => {
    e.preventDefault();
    const bottomTask = insertAboveTask(zone, e.clientY);
    const curTask = document.querySelector('.is-dragging');
    if (!bottomTask) {
      zone.appendChild(curTask);
    } else {
      zone.insertBefore(curTask, bottomTask);
    }
  });
});
const insertAboveTask = (zone, mouseY) => {
  const els = zone.querySelectorAll('.task:not(.is-dragging)');
  let closestTask = null;
  let closestOffset = Number.NEGATIVE_INFINITY;
  els.forEach((task) => {
    const { top } = task.getBoundingClientRect();
    const offset = mouseY - top;
    if (offset < 0 && offset > closestOffset) {
      closestOffset = offset;
      closestTask = task;
    }
  });
  return closestTask;
};
</script>";
let jsAdd := "<script>
const form = document.getElementById('todo-form');
const input = document.getElementById('todo-input');
const todoLane = document.getElementById('todo-lane');
form.addEventListener('submit', (e) => {
  e.preventDefault();
  const value = input.value;
  if (!value) return;
  const newTask = document.createElement('p');
  newTask.classList.add('task');
  newTask.setAttribute('draggable', 'true');
  newTask.innerText = value;
  newTask.addEventListener('dragstart', () => {
    newTask.classList.add('is-dragging');
  });
  newTask.addEventListener('dragend', () => {
    newTask.classList.remove('is-dragging');
  });
  todoLane.appendChild(newTask);
  input.value = '';
});
</script>";
let body := ---
<div class="board">
      <form id="todo-form">
        <input type="text" placeholder="New TODO..." id="todo-input" />
        <button type="submit">Add +</button>
      </form>
      <div class="lanes">
        <div class="swim-lane" id="todo-lane">
          <h3 class="heading1">Upcoming</h3>{ for app in upApp do }

          <aside class="task" draggable="true"><span  onclick=ui.popupRecord('{ app }')> { app.Projects.Clients.Name } </span> </aside>{ end }

        </div>
        <div class="swim-lane">
          <h3 class="heading1">Finished</h3>{ for app in finApp do }
           <aside class="task" draggable="true"><span  onclick=ui.popupRecord('{ app }')> { app.Projects.Clients.Name } </span> </aside>{ end }
        </div>
        <div class="swim-lane">
          <h3 class="heading1">Canceled</h3>{ for app in canApp do }
 <aside class="task" draggable="true"><span  onclick=ui.popupRecord('{ app }')> { app.Projects.Clients.Name } </span> </aside>{ end }
        </div>
      </div>
    </div>
    ---;
html(css + jsDrag + jsAdd + body)

Kanban.ninox 

4 replies

null
    • lime_owl
    • 2 wk ago
    • Reported - view

    When I build the Kanban in Visual Studio Code, it only works when I add "defer" to the script source in the head section:

        <link rel='stylesheet' href='styles.css' />
        <script src='drag.js' defer></script>
        <script src='todo.js' defer></script>
    

    any idea how I can achieve this in ninox (where I can't just refer to external scripts)?

    • szormpas
    • 2 wk ago
    • Reported - view

    Hi    I realize now that many of the problems I encounter when trying to run javascript snippets inside the html() function are precisely due to delay issues.

    See in this post how  uses the The setTimeout() method to achieve delay.

    It would be nice if an expert could give us general instructions about the subject!

    • Sean
    • 2 wk ago
    • Reported - view

    Hi 

    I got the drag and drop to work through trial and error elimination. I changed a little bit of the CSS just for clarity in my testing. I'm not sure about the adding part and don't know when I can work on it. I thought this was interesting and had a go at it. Hopefully, it will nudge you further down the path.

      • lime_owl
      • 2 wk ago
      • Reported - view

      Thank you so much! I'll need some time to figure out how your approach differs from mine but this will help me a lot for my learning experience ;)

      of course, if you eventually find some spare time to work on the adding part, i'd be gratefull

      here's another important question, the next big step in my project: as each card represents an entry in my  ninox "appointments"-table, I would want to change the entry when dragging it to another column. (just like the ninox-kanban where the status would change from "upcoming" to "finished" when dragging it over). 

      could you (or anyone else) point me in the direction how this would need to be constructed? any code or sample db's available where I could find a hint on how it could be done? many thanks in advance

Content aside

  • 2 wk agoLast active
  • 4Replies
  • 89Views
  • 3 Following