Hello all,
I am having problems with the Kanban component in Vue3 when using the templates. The problem is as follows:
I want to use templates for cards, headers and columns. I followed the documentation and I just can't get it to work.
Let's take the card template as an example. The code looks like this:
Planner.vue:
<template>
<div class='row justify-between q-col-gutter-sm'>
<div class='col-12 container'>
<ejs-kanban
ref='KanbanObj'
id='Kanban'
keyField='ScheduledId'
cssClass='kanban-header-template'
height='550px'
:dataSource='kanbanData'
:query='query'
:cardSettings='cardSettings'
:swimlaneSettings='swimlaneSettings'
enablePersistence='true'
>
<e-columns>
<e-column
v-for='workstation in workstations'
:key='workstation.keyField'
:headerText='workstation.headerText'
:keyFields='workstation.keyField'
:allowToggle='workstation.allowToggle'
:width='workstation.width'
:isExpanded='workstation.isExpanded'
>
</e-column>
</e-columns>
</ejs-kanban>
</div>
</div>
</template>
<script>
import '../../../node_modules/@syncfusion/ej2-vue-kanban/styles/material.css'
import { apiUrlV1 } from 'src/env'
import { computed, defineComponent, onMounted, reactive, toRefs, watch } from 'vue'
import { DataManager, UrlAdaptor, Query } from '@syncfusion/ej2-data'
import { KanbanComponent, ColumnsDirective, ColumnDirective} from '@syncfusion/ej2-vue-kanban'
import { useStore } from 'vuex'
import { createApp } from 'vue/dist/vue.esm-bundler'
import KanbanCardTemplate from 'components/Planner/KanbanCardTemplate'
import SwimlaneTemplate from 'components/Planner/SwimlaneTemplate'
const app = createApp()
let cardTemplateVue = app.component('cardTemplate', KanbanCardTemplate) // 'cardTemplate' not working
let swimlaneTemplateVue = app.component('swimlaneTemplate', SwimlaneTemplate) // 'swimlaneTemplate' not working
const APIManager = new DataManager({
url: `${apiUrlV1}/manufacture/read?token=` + localStorage.getItem('token'),
crudUrl: `${apiUrlV1}/manufacture/update?token=` + localStorage.getItem('token'),
adaptor: new CustomAdaptor(),
crossDomain: true
})
export default defineComponent({
name: 'Planner',
props: {
isoWeek: {
type: Number,
required: true
}
},
components: {
'ejs-kanban': KanbanComponent,
'e-columns': ColumnsDirective,
'e-column': ColumnDirective
},
setup (props) {
const store = useStore()
const event = reactive({
kanbanData: APIManager,
query: null,
workstations: computed(() => { return store.getters['workstation/kanban'] }),
shift: computed(() => { return store.getters['shiftWeek/shift'] })
})
function updateView () {
let kanbanObj = document.getElementById('Kanban').ej2_instances[0]
kanbanObj.columns = event.workstations
}
function setQueryParameters () {
event.query = new Query().addParams('IsoWeek', String(props.isoWeek) || '20')
}
function setKanbanRemoteData () {
event.kanbanData = APIManager
}
function fetchData () {
setKanbanRemoteData()
setQueryParameters()
}
watch(() => event.shift, () => {
fetchData()
updateView()
})
onMounted(() => {
fetchData()
updateView()
})
return {
...toRefs(event),
swimlaneSettings: {
keyField: 'ProjectId',
enableFrozenRows: true,
template: function () {
return {
template: SwimlaneTemplateVue
}
}
},
cardSettings: {
contentField: 'ProcessingTimeTotal',
headerField: '_id',
template: function () {
return {
template: cardTemplateVue
}
}
}
}
}
})
When I define new template components via app.component('cardTemplate', KanbanCardTemplateVue), the card template is not rendered. The only way to get it to work is to define the template by changing the template name from 'cardTemplate' to 'template'. The same applies to the other templates (swimlane, columns).
But obviously there are conflicts if all templates are declared as 'template'.
Additionally, I would like to collapse all swimlanes when the kanban control is rendered and if the containing data changes. Maybe you could also provide a solution for this.
Many thanks in advance!
Beste regards
Hi Vinitha,
I wanted to ask whether there is news on this? Many thanks in advance!
Regards
|
<template>
<div>
<div class="col-md-12 control-section">
<div class="content-wrapper">
<ejs-kanban id="kanban" cssClass="kanban-overview" keyField="Status" :dataSource="kanbanData"
:enableTooltip="enableTooltip" :cardSettings="cardSettings" :swimlaneSettings="swimlaneSettings" :dialogSettings="dialogSettings" :cardRendered='cardRendered'>
<e-columns>
<e-column headerText="To Do" keyField="Open" :allowToggle="allowToggle" :template="columnsTemplate"></e-column>
<e-column headerText="In Progress" keyField="InProgress" :allowToggle="allowToggle" :template="columnsTemplate"></e-column>
<e-column headerText="In Review" keyField="Review" :allowToggle="allowToggle" :template="columnsTemplate"></e-column>
<e-column headerText="Done" keyField="Close" :allowToggle="allowToggle" :template="columnsTemplate"></e-column>
</e-columns>
</ejs-kanban>
</div>
</div>
</div>
</template>
<script>
import { extend, addClass } from "@syncfusion/ej2-base";
import { KanbanComponent, ColumnsDirective, ColumnDirective } from "@syncfusion/ej2-vue-kanban";
import { cardData } from "./datasource";
import { createApp } from "vue";
const app = createApp({
template: '<hello></hello>'
});
var columnTemplate = app.component('columnsTemplate', {
template:`<div class="header-template-wrap">
<div :class="getClassName(data)"></div>
<div class="header-text">{{data.headerText}}</div>
</div>`,
data () {
return {
}
},
methods: {
getClassName: function(data) {
return "header-icon e-icons " + data.keyField;
}
}
});
var cardTemplate = app.component('cardRowTemplate', {
template:`<div class="card-template">
<div class="e-card-header">
<div class="e-card-header-caption">
<div class="e-card-header-title e-tooltip-text">{{data.Title}}</div>
</div>
</div>
<div class="e-card-content e-tooltip-text">
<div class="e-text">{{data.Summary}}</div>
</div>
<div class="e-card-custom-footer" v-html="getCardFooter(data)"></div>
</div>
`,
data () {
return {
}
},
methods: {
getString: function(name) {
return name.match(/\b(\w)/g).join("").toUpperCase();
},
getCardFooter: function(data) {
let tagDiv = "";
let tags = data.Tags.split(",");
for (let tag of tags) {
tagDiv += "<div class='e-card-tag-field e-tooltip-text'>" + tag + "</div>";
}
tagDiv += "<div class='e-card-avatar'>" + this.getString(data.Assignee) + "</div>";
return tagDiv;
}
}
});
var rowTemplate = app.component('swimlaneRowTemplate', {
template:`<div class='swimlane-template e-swimlane-template-table'>
<div class="e-swimlane-row-text">
<span>{{data.textField}}</span></div>
</div>
`,
data () {
return {
}
},
methods: {
image: function(data) {
return 'source/kanban/images/' + data.keyField + '.png';
}
}
});
export default {
name: "App",
components: {
'ejs-kanban' : KanbanComponent,
'e-columns': ColumnsDirective,
'e-column': ColumnDirective,
},
data() {
var swimlaneRowTemplate = function() {
return { template: rowTemplate };
};
var cardRowTemplate = function() {
return { template: cardTemplate };
};
return {
kanbanData: extend([], cardData, null, true),
allowToggle: true,
enableTooltip: true,
swimlaneSettings: {
keyField: "Assignee",
template: swimlaneRowTemplate
},
cardSettings: {
headerField: "Title",
template: cardRowTemplate,
selectionType: "Multiple"
},
columnsTemplate: function() {
return { template: columnTemplate };
},
dialogSettings: {
fields: [
{ text: 'ID', key: 'Title', type: 'TextBox' },
{ key: 'Status', type: 'DropDown' },
{ key: 'Assignee', type: 'DropDown' },
{ key: 'RankId', type: 'TextBox' },
{ key: 'Summary', type: 'TextArea' }
]
}
};
},
methods: {
cardRendered: function (args) {
let val = args.data.Priority;
addClass([args.element], val);
}
}
};
</script>
<style>
@import '../node_modules/@syncfusion/ej2-base/styles/material.css';
@import '../node_modules/@syncfusion/ej2-buttons/styles/material.css';
@import '../node_modules/@syncfusion/ej2-layouts/styles/material.css';
@import '../node_modules/@syncfusion/ej2-dropdowns/styles/material.css';
@import '../node_modules/@syncfusion/ej2-inputs/styles/material.css';
@import '../node_modules/@syncfusion/ej2-navigations/styles/material.css';
@import '../node_modules/@syncfusion/ej2-popups/styles/material.css';
@import '../node_modules/@syncfusion/ej2-vue-kanban/styles/material.css';
</style> |
The same code fails (I mean I see a blank template) on a new project started using Vite development server (that is actually the suggested environment for vue 3). Any working example with Vite?
I found how to solve it, using different Vue.js instances to register the templates globally, I debugged the card template compilation step and found that it was loading the column template instead of the card template:
Hi Mauro,
Currently, we are validating your reported query. We will update you with further details on or before June 16, 2022.
Regards,
Buvana S
Hi Mauro,
Thank you for your patience.
We have created a sample using vite with the vue 3
application and provided a column, card, and swimlane template using the slot.
In the below sample, we have rendered the Kanban component using slot
template support instead of creating different components. Please find
the below code and sample for your reference.
App.vue
|
<script> import { extend } from "@syncfusion/ej2-base"; import { KanbanComponent, ColumnsDirective, ColumnDirective, } from "@syncfusion/ej2-vue-kanban"; const cardData = [ { Id: "Task 1", Title: "Task - 29001", Status: "Open", Summary: "Analyze customer requirements.", Priority: "High", Tags: "Bug, Release Bug", RankId: 1, Assignee: "Nancy Davloio", }, { Id: "Task 2", Title: "Task - 29002", Status: "InProgress", Summary: "Add responsive support to applicaton", Priority: "Low", Tags: "Story, Kanban", RankId: 1, Assignee: "Andrew Fuller", } ];
export default { components: { "ejs-kanban": KanbanComponent, "e-columns": ColumnsDirective, "e-column": ColumnDirective, }, data() { return { kanbanData: extend([], cardData, null, true), swimlaneSettings: { keyField: "Assignee", template: "swimlaneTemplate" }, cardSettings: { headerField: "Title", template: "cardsTemplate", selectionType: "Multiple", }, }; }, methods: { getClassName: function(data) { return "header-icon e-icons " + data.keyField; }, image: function(data) { return 'source/kanban/images/' + data.keyField + '.png'; }, }, }; </script>
<template> <ejs-kanban id="kanban" keyField="Status" :dataSource="kanbanData" :cardSettings="cardSettings" :swimlaneSettings="swimlaneSettings" > <e-columns> <e-column headerText="To Do" keyField="Open" :template="'columnsTemplate'"> <template v-slot:columnsTemplate={data}> <div class="header-template-wrap"> <div :class="getClassName(data)"></div> <div class="header-text">{{data.headerText}}</div> </div> </template> </e-column> …………. </e-columns> <template v-slot:swimlaneTemplate={data}> <div class='swimlane-template e-swimlane-template-table'> <div class="e-swimlane-row-text"><img :src="image(data)" :alt="data.keyField" /> <span>{{data.textField}}</span> </div> </div> </template> <template v-slot:cardsTemplate={data}> <div class="card-template"> <div class="e-card-header"> <div class="e-card-header-caption"> <div class="e-card-header-title e-tooltip-text">{{data.Title}}</div> </div> </div> </div> </template> </ejs-kanban> </template>
<style> @import "../node_modules/@syncfusion/ej2-base/styles/material.css"; @import "../node_modules/@syncfusion/ej2-buttons/styles/material.css"; @import "../node_modules/@syncfusion/ej2-layouts/styles/material.css"; @import "../node_modules/@syncfusion/ej2-dropdowns/styles/material.css"; @import "../node_modules/@syncfusion/ej2-inputs/styles/material.css"; @import "../node_modules/@syncfusion/ej2-navigations/styles/material.css"; @import "../node_modules/@syncfusion/ej2-popups/styles/material.css"; @import "../node_modules/@syncfusion/ej2-vue-kanban/styles/material.css"; </style> |
Sample: https://www.syncfusion.com/downloads/support/directtrac/general/ze/ej2-vue-vite-with-kanban771028638
Please check the above code and sample and let us know if you have any further assistance.
Regards,
Buvana S
Thx! the solution using v-slot was really helpful.
You are welcome. Please get back to us if you need any other assistance.