v7.3.0

Tutorial

Follow the steps in this tutorial to get this app up and running:

Project setup

To create an application, we will use Vitejs and choose vanilla JavaScript but you can use any other build tool of your choice.

To do so, execute:

npm create vite@latest my-taskboard-app -- --template vanilla

It will generate a vanilla JavaScript project.

Installing Dependencies

To install vite's dependencies:

cd my-taskboard-app
npm install

Next, add the bryntum dependencies. If you have the Bryntum Task Board distribution, it provides pre-build JavaScript bundle. Copy the /build/taskboard.module.js and /build/taskboard.stockholm.css files to the my-taskboard-app root folder.

After that, link the CSS in your index.html:

<head>
    <!-- Existing code -->

    <!-- Structural CSS -->
    <link rel="stylesheet" href="taskboard.css">
    <!-- Bryntum theme of your choice -->
    <link rel="stylesheet" href="svalbard-light.css" data-bryntum-theme>
</head>

Remove the counter.js from the root directory, we don't need it.

Minimal TaskBoard

Now we are going to add a minimal TaskBoard to the main.js file:

import { TaskBoard } from './taskboard.module.js';

const taskBoard = new TaskBoard({
    // Where to render to, accepts an element or an element id
    appendTo : 'app',

    // Normally sizing would be handled by CSS, but for simplicity
    // we use fixed with and height for the tutorial 
    width : 800,
    height : 600,

    // Columns to display
    columns : [
        'todo',
        'doing',
        'done'
    ],

    // Field used to pair a task to a column
    columnField : 'status',

    // Project that holds the data for the TaskBoard
    project : {
        // To get started quickly, we use minimal inline data
        tasks : [
            // Each entry will be turned into a task record
            {
                // Each record should have a unique "id"
                id : 1,
                // The "name" will be displayed in card headers
                name : 'Bug with rendering',
                // The "status" determines which column to put the card 
                // in (as declared above)
                status : 'doing'
            }
        ]
    }
});

The page should now show something similar to this:

Running the app

Run the development server by executing:

npm run dev

The application is now available on http://localhost:5173.

Loading data

TaskBoard accepts inline data or it can use its associated project to load remote data. Depending on your setup you will want to pick one or the other.

If you for example have multiple widgets on your page displaying the same data, you might already have it available on the client - supplying it as inline data can then be cheaper than remotely loading it also for TaskBoard. But for most cases loading it remotely will be the best fit.

To load data remotely, configure project with a url to load from. Modify the previous snippets project config to look like this:

const taskBoard = new TaskBoard({
    // Code from the previous step omitted for brevity
    // ...

    project : {
        // Url to load from. The tutorial uses a static resource for this, but it can point to any backend url
        loadUrl : 'data/data.json',
        // Load automatically at startup
        autoLoad : true
    }
});

The response is expected in a specific format (see this guide). The data used for this tutorial is available here: data.json. An extract from that file:

{
  "success": true,
  "tasks": {
    "rows": [
      {
        "id": 1,
        "name": "Bug with rendering",
        "description": "Try it on any demo, reproduces easily",
        "status": "done",
        "prio": "medium",
        "progress": 100
      },
      {
        "...": "..."
      }
    ]
  }
}

Make sure the url points to where you placed your data. With the correct load url now in place, you should be seeing the following:

As with our inline data, the "name" is mapped to the card header. We now also see that the "description" is mapped to the card body. We have a couple of additional fields in the data above, "prio" and "progress". Lets add them to the cards.

Saving changes

As for loading data, you have multiple options for saving changes. You can use the project's crud manager functionality to sync changes automatically to the backend (by configuring it with a syncUrl and autoSync), which requires your backend to follow the CrudManager protocol. Or you can listen for changes and send them to your backend manually, trading ease of use on the client for flexibility on the server.

In this step we will use the latter approach. We will listen for changes, but since we have no backend in place we will just log the changes to the console. Modify the previous snippet, adding the following:

const taskBoard = new TaskBoard({
    // Code from the previous step omitted for brevity
    // ...

    project : {
        loadUrl  : 'data/data.json',
        autoLoad : true,
        // New code ↓
        listeners : {
            // Listener for the `hasChanges` event, triggered when any store
            // handled by the project has changes
            hasChanges() {
                console.log(taskBoard.project.changes);

                // In a real app you would send the changes to the server here.
                // Then you would call `taskBoard.project.acceptChanges()` to 
                // clear local changes.
            }
        }
    }
});

Try it out here (be sure to open the console to see the output):

Add content to cards

A card has three sections: header, body and footer. Each section can hold task items, small widgets bound to fields in the tasks data. There are multiple task items to pick from, see the Customize task contents guide for more info.

We are going to add a progress bar bound to the "progress" field to the body and a template bound to "prio" to the footer. Add the following to your TaskBoard config:

const taskBoard = new TaskBoard({
    // Field used to pair a task to a column
    columnField : 'status',

    // NEW CODE

    // Add a progress bar to card body
    bodyItems : {
        progress : { type : 'progress' }
    },

    // Add a template displaying priority to card footer
    footerItems : {
        prio : { type : 'template', template : ({ value }) => `Prio ${value}` }
    },

    // END OF NEW CODE

    // Project that holds the data for the TaskBoard
    project : {
        /*...*/
    }
});

The app should now look something like this:

Enabling features

TaskBoard ships with a set of features that can be enabled/disabled and configured to affect the functionality of the component (see the TaskBoard features guide). We are going to enable the TaskMenu feature (which supplies a context menu for cards) and add a convenient button to cards to show it.

Alter your TaskBoard config, add:

const taskBoard = new TaskBoard({
    // Field used to pair a task to a column
    columnField : 'status',

    // NEW CODE

    // Enable the task context menu
    features : {
        taskMenu : true
    },

    // Add a button to show the context menu to card header
    headerItems : {
        menu : { type : 'taskMenu', order : 200 }
    },

    // END OF NEW CODE

    // Add a progress bar to card body
    bodyItems : {}
});

That change yields the following app:

Reacting to events

TaskBoard, its features and data stores fire a number of events that you can listen to, TaskBoard for example fires taskClick when clicking a task card, the taskStore fires add when a new task is added, etc. See the API docs for each class for all events (TaskBoard's events are for example listed here).

To catch an event, you can either specify declarative listeners in the config, or add them programmatically using the on method. In this step we will add a declarative listener for the taskClick event, and a programmatic listener for the beforeTaskEdit event.

const taskBoard = new TaskBoard({
    // Code from the previous steps omitted for brevity
    // ...

    // Declarative listener
    listeners : {
        taskClick({ taskRecord }) {
            Toast.show(`Clicked ${taskRecord.name}`);
        }
    }
});

// Programmatic listener
taskBoard.on('beforeTaskEdit', ({ taskRecord }) => {
    Toast.show(`Editing ${taskRecord.name}`);
});

Adding some style and color

For the last step of this tutorial we are going to apply some color and styling to the TaskBoard. For more info on the topic, see the Styling guide.

A tasks color is derived from three sources: the column, the swimlane and the task itself. We are going to define a color per column. Change the column definition of the app to the following:

const taskBoard = new TaskBoard({
    // Columns to display, each with a color used for styling
    columns : [
        { id : 'todo', text : 'Todo', color : 'blue' },
        { id : 'doing', text : 'Doing', color : 'orange' },
        { id : 'done', text : 'Done', color : 'green' },
    ]
});

The app got a little more colorful, since some task items use the derived color by default:

Lets make it look a bit nicer using some g. TaskBoard uses CSS variables for most of its looks, allowing you to manipulate how it looks either through code or CSS. To not have to include a CSS file, we will style our app using code. The CSS to achieve the same result is included at the end.

To style TaskBoard using code, you can either set the CSS variables using the standard approach (by manipulating the style attribute of TaskBoards element) or use a convenient shortcut in form of TaskBoards css property. Add the this to your config:

const taskBoard = new TaskBoard({
    // Custom styling
    css : {
        background  : '#fff',
        bodyPadding : '.5em',

        columnBackground      : '#f9f9f9',
        columnHeaderBorderTop : '5px solid var(--b-primary)',

        cardBorderTop      : '5px solid var(--b-primary)',
        cardFooterFontSize : '.8em'
    }
});

And the app looks much nicer:

If you prefer, including this CSS yields the same result:

.b-task-board {
    --b-task-board-background               : #fff;
    --b-task-board-body-padding             : .5em;

    --b-task-board-column-background        : #f9f9f9;
    --b-task-board-column-header-border-top : 5px solid var(--b-primary);

    --b-task-board-card-border-top          : 5px solid var(--b-primary);
    --b-task-board-card-footer-font-size    : .8em;
}

That's it, you finished the tutorial 👍 Happy coding!

Contents