Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Enhancement] Allow tasks to be moved between boards (Real Kanban style) #94

Open
kjuulh opened this issue May 21, 2020 · 2 comments
Open

Comments

@kjuulh
Copy link

kjuulh commented May 21, 2020

I just completed the course, and I wondered why I couldn't move tasks between boards, Real Trello style. As such, I've included some code that makes just that possible.

All in all, there is probably only 15-20 lines of actual code changes for it to work. And I believe it is worth it =D.

// boards.component.ts
...

@Output() taskMoved = new EventEmitter<{ previous: string; next: string }>();

  constructor(private boardService: BoardService, private dialog: MatDialog) {}

  ngOnInit(): void {}

  taskDrop(event: any) {
    if (event.previousContainer === event.container) {
      moveItemInArray(
        this.board.tasks,
        event.previousIndex,
        event.currentIndex
      );
      this.boardService.updateTasks(this.board.id, this.board.tasks);
    } else {
      transferArrayItem(
        event.previousContainer.data,
        event.container.data,
        event.previousIndex,
        event.currentIndex
      );

      this.taskMoved.emit({
        previous: event.previousContainer.id,
        next: event.container.id,
      });
    }
  }

...

For this to work, the containerIds, have to have proper ids. Otherwise it wont work.

<!-- board.component.html -->
...

<div class="tasks">
    <div
      class="collection"
      cdkDropList
      [id]="board.id"
      [cdkDropListData]="board.tasks"
      (cdkDropListDropped)="taskDrop($event)"
    >
      <div
        class="inner-card"
        cdkDrag
        *ngFor="let task of board.tasks; let i = index"
        (click)="openDialog(task, i)"
      >
        <mat-card [ngClass]="task.label">{{ task.description }}</mat-card>
      </div>
    </div>

...

The board list now needs a new handler for the array move

// board-list.component.ts
...

taskMoved({ previous, next }) {
    const previousTasks = this.boards.find((b) => b.id === previous).tasks;
    const nextTasks = this.boards.find((b) => b.id === next).tasks;

    this.boardService.moveTask(previous, previousTasks, next, nextTasks);
  }

This will allow, the board list to make the actual commit.

Add the handler to the html

<!-- board-list.component.html -->
...

<div
  cdkDropList
  cdkDropListOrientation="horizontal"
  class="boards"
  (cdkDropListDropped)="drop($event)"
>
<div class="container" cdkDropListGroup>
    <angular-board
      cdkDrag
      *ngFor="let board of boards"
      [board]="board"
      (taskMoved)="taskMoved($event)"
    >
      <mat-icon cdkDragHandle class="handle">drag_indicator</mat-icon>
    </angular-board>

    <div class="board-button">
      <button
        mat-raised-button
        color="accent"
        cdkDragDisabled
        (click)="openBoardDialog()"
      >
        New Board
      </button>
    </div>
  </div>

...

Now to add the last task to move the item in the db.

// board.service.ts
...

moveTask(
    previousBoardId: string,
    previousTasks: Task[],
    boardId: string,
    tasks: Task[]
  ) {
    const db = firebase.firestore();
    const batch = db.batch();
    const previousRef = db.collection('boards').doc(previousBoardId);
    const nextRef = db.collection('boards').doc(boardId);
    batch.update(previousRef, { tasks: previousTasks });
    batch.update(nextRef, { tasks: tasks });
    batch.commit().catch((err) => console.error(err));
  }

All in all there was a fairly minimal amount of code for it to work. And I think it enhances the appeal of the application quite a bit, even if it is just a small project.

I haven't included the changes to the styles. But if people want it to work, then the only thing that needs to change is to take into account that there is another layer in the div in both files.

Like this.

// board.component.scss
.tasks .collection.cdk-drop
@1fxe
Copy link

1fxe commented May 23, 2020

Thanks this is really cool!
For the css it the class "container" in board-list.component.html makes the boards display vertically, if you want it horizontal again you can add (not sure if it was just my code)

// boards-list.component.css
.container {
  display: flex;
  flex-direction: row;
}

@kjuulh
Copy link
Author

kjuulh commented May 23, 2020

Thanks this is really cool!
For the css it the class "container" in board-list.component.html makes the boards display vertically, if you want it horizontal again you can add (not sure if it was just my code)

// boards-list.component.css
.container {
  display: flex;
  flex-direction: row;
}

Yes, as there is an extra div. The flexbox will only apply to the top level div, as such, it becomes vertical. You are correct that it should be moved down into the div.container.

Actually you could just do the following

// board-list.component.scss original
.boards {
  width: auto;
  padding: 24px;
  display: flex;
  flex-direction: row;
  overflow-x: scroll;

...

to

// board-list.component.scss new
.boards .container {
  width: auto;
  padding: 24px;
  display: flex;
  flex-direction: row;
  overflow-x: scroll;

...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants