Our flexible Kanban board for managing tasks with drag drop


Post by methodeuser1 »

Hi,

is it possible to use an Angular component inside the task renderer function?

The documentation says it can be done for column renderer, header renderer or tooltip renderer.
(https://bryntum.com/products/taskboard/docs/guide/TaskBoard/integration/angular/guide#using-angular-components-as-renderers)

Can I do something similar inside the 'taskRenderer' function?
If so, can you please provide a simple example?

Thanks


Post by ghulam.ghous »

Hi there,

Custom renderer in angular can be used wherever renderer function is available. The implementation for taskRenderer is similar to the one's we have here https://bryntum.com/products/taskboard/docs/guide/TaskBoard/integration/angular/guide#using-angular-components-as-renderers. You just need to define a custom component like this:

import { Component, Input } from '@angular/core';

@Component({
    selector : 'app-task-renderer',
    template : `
        <div class="custom-task-renderer">
        <h3>{{name}}</h3>
        </div>
    `
})
export class TaskRendererComponent {
    @Input() name : string;
}

Create a custom element in the app.module.ts file, something like this:

import { Injector, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { BryntumTaskBoardModule } from '@bryntum/taskboard-angular';
import { TaskRendererComponent } from './task-renderer/task-renderer.component';
import { createCustomElement } from '@angular/elements';

@NgModule({
    declarations : [
        AppComponent,
        TaskRendererComponent
    ],
    imports : [
        BrowserModule,
        BryntumTaskBoardModule
    ],
    providers : [],
    bootstrap : [AppComponent]
})
export class AppModule {
    constructor(injector: Injector) {
        // convert Angular Components to Custom Elements and register them with the browser
        customElements.define('task-renderer', createCustomElement(TaskRendererComponent, { injector }));
    }
}

Now you need to use the custom renderer in the app.config.ts:

    taskRenderer : ({ cardConfig }) => {

    cardConfig.children.body.html = `
            <task-renderer
                name="${StringHelper.encodeHtml('Hello')}"
            ></task-renderer>
        `;
},

Also add it in the markup file app.component.html:

[taskRenderer] = "taskBoardConfig.taskRenderer"
Screenshot 2024-01-11 at 4.32.28 PM.png
Screenshot 2024-01-11 at 4.32.28 PM.png (59.42 KiB) Viewed 1164 times

Here's the example code:

undo-redo.zip
(270.59 KiB) Downloaded 64 times

Regards,
Ghous


Post by methodeuser1 »

Thank you so much!


Post by ghulam.ghous »

No worries! If you need any further assistance please don't hesitate to reach out to us.


Post by methodeuser1 »

Is it also possible to listen to events generated by the rendered Angular component?

<task-renderer
	name="${StringHelper.encodeHtml('Hello')}"
	(click)="?"
</task-renderer>

Maybe using a vanilla addEventListener() in the underlying HTMLElement?


Post by ghulam.ghous »

Hi,

Yes you can do something like this to listen to events:

import { Component, Input, HostListener } from '@angular/core';

@Component({
    selector : 'app-task-renderer',
    template : `
        <div class="custom-task-renderer">
        <h3>{{name}}</h3>
        </div>
    `
})
export class TaskRendererComponent {
    @Input() name : string;


@HostListener('click') onClick() {
    console.log('User Click using Host Listener');
}
}

Screenshot 2024-01-15 at 9.47.44 PM.png
Screenshot 2024-01-15 at 9.47.44 PM.png (775.25 KiB) Viewed 983 times

Hope it helps!

Regards,
Ghous


Post by methodeuser1 »

Yeah, that works. Thanks.

One more thing... is it possible to use the DomConfig properties to "render" the Angular component? (instead of providing the string template).

This:

cardConfig.children.body = {
	tag: 'task-renderer',
	class: {
		big: true
	},
	(?)attributes: {
		name: 'Hello'
	}
}

instead of this one

cardConfig.children.body.html = `
            <task-renderer
                name="${StringHelper.encodeHtml('Hello')}"
            ></task-renderer>
        `;

In the documentation I can't find a way to specifiy custom attributes (the 'attributes' property in the example) for Angular's input properties.

I'm asking this because I tried to render a Kanban with 80 tasks (with header,body and footer as Angular components) and now the board is really lagging.

Thanks in advance


Post by tasnim »

Hi,

Looks like that has some problems rendering angular component inside of domConfig object. I've opened a ticket to investigate that https://github.com/bryntum/support/issues/8284

For now, please use the way Ghulam showed you to render custom components inside of renderer

Best regards,
Tasnim


Post by Animal »

methodeuser1 wrote: Tue Jan 16, 2024 6:28 pm

Yeah, that works. Thanks.

One more thing... is it possible to use the DomConfig properties to "render" the Angular component? (instead of providing the string template).

I can see no reason to use a heavy framework to put content into a card.

Just use a DomConfig object directly in the taskRenderer

    taskRenderer : ({ cardConfig, taskRecord }) => {
        cardConfig.children.body.children = {
            class : "custom-task-renderer",
            children : [
                "hello",
                {
                    tag : 'h3',
                    text : taskRecord.name

                }
            ]
        };
    }

Post by Animal »

Specifying a custom element works in DomSync. See below:

Screenshot 2024-01-23 at 07.38.14.png
Screenshot 2024-01-23 at 07.38.14.png (649.18 KiB) Viewed 559 times

So the code implements that custom element must not be doing it right. Have you got the source code for it?

It should be as simple as this:

customElements.define('my-element', class extends HTMLElement {
    static observedAttributes = ['name'];

    constructor() {
        super();

        const root = this._root = this.attachShadow({
            mode : 'open',
        });
        this.nameElement = document.createElement('h3');
        root.appendChild(this.nameElement);
    }

    connectedCallback() {
        this._root.appendChild(this.nameElement);
    }

    attributeChangedCallback(name, oldValue, value) {
        if (name === 'name') {
            this.nameElement.innerHTML = value;
        }
    }
});

Post Reply