Error in ag-grid-vue Could not find component XXX, did you forget to configure this component? - vue.js

I'm using ag-grid-vue and i'm trying to create custom tool tip.
This is my code:
CustomToolTipVue.js component:
export default {
template: `
<div class="custom-tooltip" v-bind:style="{ backgroundColor: color }">
<p><span>{{ data.athlete }}</span></p>
<p><span>Country: </span>{{ data.country }}</p>
<p><span>Total: </span>{{ data.total }}</p>
</div>
`,
data: function () {
return {
color: null,
athlete: null,
country: null,
total: null,
};
},
beforeMount() {
this.data = this.params.api.getDisplayedRowAtIndex(
this.params.rowIndex
).data;
this.color = this.params.color || 'white';
},
};
Grid component - where i'm using it (Attached only the main code):
<script>
import { AgGridVue } from "ag-grid-vue";
import "ag-grid-community";
import CustomToolTipVue from './CustomToolTipVue.js'
export default {
name: "Grid",
data: () => ({
gridOptions: null,
gridApi: null,
gridColumnApi: null,
selectedRows: [],
noRowsTemplate: "",
loadingTemplate: "",
rowClassRules:null
}),
components: {
AgGridVue,
CustomToolTipVue
},
created() {
this.gridOptions = {};
this.gridOptions.columnDefs = this.columnDefs;
this.gridOptions.components = {
};
},
computed: {
defaultColDef() {
return {
resizable: true,
menuTabs: ["filterMenuTab", "generalMenuTab", "columnsMenuTab"],
sortable: true,
filter: true,
tooltipComponentParams: { color: '#ececec' },
tooltipComponent: "CustomToolTipVue",
};
},
},
And i keep getting this error:
"Could not find component CustomToolTipVue, did you forget to configure this component?"
Any idea why?

Managed to solve it by upgrde ag-grid to latest version - 27.0.0

Related

how to create vue-shepperd component

I am trying to develop guided tour with shepherd: https://www.npmjs.com/package/vue-shepherd but I cannot get the element. So here is my component for guide tour:
<template>
<div></div>
</template>
<script>
import { useShepherd } from 'vue-shepherd';
export default {
props: {
element: {
required: true,
},
id: {
type: Number,
required: true,
},
title: {
type: String,
},
text: {
type: String,
required: true,
},
position: {
type: String,
required: true,
},
},
mounted() {
this.tour.start();
},
data() {
return {
tour: null,
};
},
methods: {
createTour() {
this.tour = useShepherd({
useModalOverlay: true,
});
this.tour.addStep({
title: this.title,
text: this.text,
attachTo: { element: this.element, on: this.position },
buttons: [
{
action() {
return this.back();
},
classes: 'shepherd-button-secondary',
text: 'Back',
},
{
action() {
return this.next();
},
text: 'Next',
},
],
id: this.id,
});
this.tour.start();
},
},
created() {
this.createTour();
},
};
</script>
and here is my parent component:
<button ref="button">
Click
</button>
<guide :element="element" :title="'Tour'" :text="'Example'" :position="'bottom'" :id="1" />
and the mounted of the parent element:
mounted() {
this.element = this.$refs.button;
},
but the tour doesnt attach the the button element. it just appears in the middle of the page. Why do you think it is?
Looks like a usage problem in vue hooks. The child component's hooks fire before the parent component's hooks. Therefore, at the time of the creation of the tour, the element does not exist. Vue-shepherd does not use vue reactivity.
Use
mounted() {
this.$nextTick(() => {
this.createTour();
});
},
Codesanbox
But it's better to change the component structure. If you are using vue3 you can use my package
In this case it will look like this
<template>
<button v-tour-step:1="step1">
Click
</button>
</template>
<script>
import { defineComponent, inject, onMounted } from "vue";
export default defineComponent({
setup() {
const tour = inject("myTour");
onMounted(() => {
tour.start();
});
const step1 = {
/* your step options */
}
return {
step1,
};
}
});
</script>

setText error in quill text editor for Vue3.js

I created a text editor component for my Vue3 project which is based on Quill (for documentation --> https://quilljs.com/docs/api/#setcontents):
<template>
<div class="form-control" v-bind:class="inputClasses" ref="editor"></div>
</template>
<script>
import Quill from 'quill';
import 'quill/dist/quill.core.css';
import 'quill/dist/quill.bubble.css';
import 'quill/dist/quill.snow.css';
import GENERAL_COMPONENT_CONSTANTS from "../constants/GeneralComponentConstants";
export default {
props: {
modelValue: { type: String, default: '' },
},
data() {
return {
editor: null
};
},
mounted() {
var _this = this;
this.editor = new Quill(this.$refs.editor, {
modules: {
toolbar: [
[{ header: [1, 2, 3, 4, false]} ],
["bold", "italic", "underline", "link", "image"],
],
},
//theme: 'bubble',
theme: "snow",
formats: ["bold", "underline", "header", "italic", "link"],
placeholder: this.placeholder,
});
this.editor.root.innerHTML = this.modelValue;
this.editor.setText('Default Value');
this.editor.on("text-change", function () {
return _this.update();
});
},
methods: {
update: function update() {
this.$emit(
"update:modelValue",
this.editor.getText() ? this.editor.root.innerHTML : ""
);
},
},
computed: {
}
}
</script>
It works fine and as a default value, I set the text this.editor.setText('Default Value'); But I am getting Uncaught DOMException: Failed to execute 'setStart' on 'Range': The offset 4294967294 is larger than the node's length error when I try to delete the whole default value.

Vue.js: Child Component mutates state, parent displays property as undefined

I have a parent component that lists all the tasks:
<template>
<div class="tasks-wrapper">
<div class="tasks-header">
<h4>{{ $t('client.taskListingTitle') }}</h4>
<b-button variant="custom" #click="showAddTaskModal">{{ $t('client.addTask') }}</b-button>
</div>
<b-table
striped
hover
:items="tasks"
:fields="fields"
show-empty
:empty-text="$t('common.noResultsFound')">
</b-table>
<AddTaskModal />
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
import AddTaskModal from '#/components/modals/AddTaskModal'
import moment from 'moment'
export default {
name: 'TaskListing',
components: {
AddTaskModal
},
data () {
return {
tasks: [],
fields: [
{ key: 'createdOn', label: this.$t('tasks.tableFields.date'), formatter: 'formatDate' },
{ key: 'domain', label: this.$t('tasks.tableFields.task') },
{ key: 'comment', label: this.$t('tasks.tableFields.comment') },
{ key: 'status', label: this.$t('tasks.tableFields.status') }
]
}
},
computed: {
...mapGetters('users', ['user'])
},
methods: {
...mapActions('tasks', ['fetchTasks']),
...mapActions('users', ['fetchUserById']),
formatDate: function (date) {
return moment.utc(date).local().format('DD.MM.YYYY HH:mm')
},
showAddTaskModal () {
this.$bvModal.show('addTaskModal')
}
},
async mounted () {
const currUserId = this.$router.history.current.params.id
if (this.user || this.user.userId !== currUserId) {
await this.fetchUserById(currUserId)
}
if (this.user.clientNumber !== null) {
const filters = { clientReferenceNumber: { value: this.user.clientNumber } }
this.tasks = await this.fetchTasks({ filters })
}
}
}
</script>
Inside this component there is a child which adds a task modal.
<template>
<b-modal
id="addTaskModal"
:title="$t('modals.addTask.title')"
hide-footer
#show="resetModal"
#hidden="resetModal"
>
<form ref="form" #submit.stop.prevent="handleSubmit">
<b-form-group
:invalid-feedback="$t('modals.requiredFields')">
<b-form-select
id="task-type-select"
:options="taskTypesOptions"
:state="taskTypeState"
v-model="taskType"
required
></b-form-select>
<b-form-textarea
id="add-task-input"
:placeholder="$t('modals.enterComment')"
rows="3"
max-rows="6"
v-model="comment"
:state="commentState"
required />
</b-form-group>
<b-button-group class="float-right">
<b-button variant="danger" #click="$bvModal.hide('addTaskModal')">{{ $t('common.cancel') }}</b-button>
<b-button #click="addTask">{{ $t('modals.addTask.sendMail') }}</b-button>
</b-button-group>
</form>
</b-modal>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
export default {
name: 'AddTaskModal',
data () {
return {
comment: '',
commentState: null,
taskTypesOptions: [
{ value: null, text: this.$t('modals.addTask.taskType') },
{ value: 'OnBoarding', text: 'Onboarding' },
{ value: 'Accounts', text: 'Accounts' },
{ value: 'TopUp', text: 'Topup' },
{ value: 'Overdraft', text: 'Overdraft' },
{ value: 'Aml', text: 'Aml' },
{ value: 'Transfers', text: 'Transfers' },
{ value: 'Consultation', text: 'Consultation' },
{ value: 'TechnicalSupport', text: 'TechnicalSupport' },
{ value: 'UnblockPin', text: 'UnblockPin' },
{ value: 'Other', text: 'Other' }
],
taskType: null,
taskTypeState: null
}
},
computed: {
...mapGetters('users', ['user']),
...mapGetters('tasks', ['tasks'])
},
methods: {
...mapActions('tasks', ['addNewTask', 'fetchTasks']),
...mapActions('users', ['fetchUserById']),
async addTask (bvModalEvt) {
bvModalEvt.preventDefault()
if (!this.checkFormValidity()) { return }
const currUserId = this.$router.history.current.params.id
if (this.user || this.user.userId !== currUserId) {
await this.fetchUserById(currUserId)
}
const data = {
clientPhone: this.user.phoneNumber,
comment: this.comment,
clientReferenceNumber: this.user.clientNumber,
domain: this.taskType
}
await this.addNewTask(data)
if (this.user.clientNumber !== null) {
const filters = { clientReferenceNumber: { value: this.user.clientNumber } }
this.tasks = await this.fetchTasks({ filters })
// this.tasks may be useless here
}
console.log(this.tasks)
this.$nextTick(() => { this.$bvModal.hide('addTaskModal') })
},
checkFormValidity () {
const valid = this.$refs.form.checkValidity()
this.commentState = valid
this.taskTypeState = valid
return valid
},
resetModal () {
this.comment = ''
this.commentState = null
this.taskTypeState = null
}
}
}
</script>
When I add a task I call getalltasks to mutate the store so all the tasks are added. Then I want to render them. They are rendered but the property createdOn on the last task is InvalidDate and when I console log it is undefined.
The reason I need to call gettasks again in the modal is that the response on adding a task does not return the property createdOn. I do not want to set it on the front-end, I want to get it from the database.
I logged the store and all the tasks are added to the store.
Why is my parent component not rendering this particular createdOn property?
If I refresh the page everything is rendering fine.
If you add anything into a list of items that are displayed by v-for, you have to set a unique key. Based on your explanation, I assume that your key is the index and when you add a new item, you mess with the current indexes. Keys must be unique and unmutateable. What you need to do is to create a unique id for each element.
{
id: Math.floor(Math.random() * 10000000)
}
When you create a new task, use the same code to generate a new id, and use id as key. If this doesn't help, share your d-table and related vuex code too.

AG-Grid data update after drag & drop

I'm new to AG-Grid and I'm trying to use it inside my Vue app.
I'm try to figure out why, after a drag&drop event, the data doesn't get update.
I created a little example here: https://plnkr.co/edit/vLnMXZ5y1VTDrhd5
import Vue from 'vue';
import { AgGridVue } from '#ag-grid-community/vue';
import { ClientSideRowModelModule } from '#ag-grid-community/client-side-row-model';
import '#ag-grid-community/core/dist/styles/ag-grid.css';
import '#ag-grid-community/core/dist/styles/ag-theme-alpine.css';
const VueExample = {
template: `
<div style="height: 100%">
<button #click="logData">Log data</button>
<ag-grid-vue
style="width: 100%; height: 100%;"
class="ag-theme-alpine"
id="myGrid"
:gridOptions="gridOptions"
#grid-ready="onGridReady"
:columnDefs="columnDefs"
:defaultColDef="defaultColDef"
:rowDragManaged="true"
:animateRows="true"
:modules="modules"
:rowData="rowData"></ag-grid-vue>
</div>
`,
components: {
'ag-grid-vue': AgGridVue,
},
data: function () {
return {
gridOptions: null,
gridApi: null,
columnApi: null,
columnDefs: null,
defaultColDef: null,
modules: [ClientSideRowModelModule],
rowData: null,
};
},
beforeMount() {
this.gridOptions = {};
this.columnDefs = [
{
field: 'Month',
rowDrag: true,
},
{ field: 'Max temp (C)' },
{ field: 'Min temp (C)' },
{ field: 'Days of air frost (days)' },
{ field: 'Sunshine (hours)' },
{ field: 'Rainfall (mm)' },
{ field: 'Days of rainfall >= 1 mm (days)' },
];
this.defaultColDef = {
width: 100,
sortable: true,
filter: true,
};
},
mounted() {
this.gridApi = this.gridOptions.api;
this.gridColumnApi = this.gridOptions.columnApi;
},
methods: {
logData() {
this.rowData.forEach(function(item) {
console.log(item.Month);
});
},
onGridReady(params) {
const httpRequest = new XMLHttpRequest();
const updateData = (data) => {
this.rowData = data;
};
httpRequest.open(
'GET',
'https://raw.githubusercontent.com/ag-grid/ag-grid/master/grid-packages/ag-grid-docs/src/weather_se_england.json'
);
httpRequest.send();
httpRequest.onreadystatechange = () => {
if (httpRequest.readyState === 4 && httpRequest.status === 200) {
updateData(JSON.parse(httpRequest.responseText));
}
};
},
},
};
new Vue({
el: '#app',
components: {
'my-component': VueExample,
},
});
if you click on the "Log data" button you can see in console that data isn't updated in sync with the view.
How can I do that?
Thank you!
I found a solution adding a #row-drag-end="rowDragEnd" event; I updated the example here: https://plnkr.co/edit/vLnMXZ5y1VTDrhd5
<ag-grid-vue
style="width: 100%; height: 100%;"
class="ag-theme-alpine"
id="myGrid"
:gridOptions="gridOptions"
#grid-ready="onGridReady"
:columnDefs="columnDefs"
:defaultColDef="defaultColDef"
:rowDragManaged="true"
#row-drag-end="rowDragEnd"
:animateRows="true"
:modules="modules"
:rowData="rowData"></ag-grid-vue>
rowDragEnd: function(event) {
var itemsToUpdate = [];
this.gridApi.forEachNodeAfterFilterAndSort(function (rowNode) {
itemsToUpdate.push(rowNode.data);
});
this.rowData = itemsToUpdate;
},
According to this page, changing the row order in the grid will not change the rowData order.
If you want to log the order of months as they are in the grid, you may use this.gridApi.forEachNode(node, index), as described in State 3 of the same page. You can write your logData() method like this:
logData() {
this.gridApi.forEachNode(node => console.log(node.data.Month));
}

ag-Grid does not support .vue component as cellRenderer?

So I have this itemlist.vue file
<div>
<div>
<ag-table
style=" height: 650px;"
class="ag-theme-balham"
:column-defs="columnDefs"
:row-data="rowData"
/>
</div>
</div>
</template>
<script>
import AgTable from "../components/AgTable";
import editRenderer from "../components/AgGridRenderers/editDeleteRenderer.vue";
export default {
components: {
AgTable
},
data: () => ({
users: [],
columnDefs: null,
rowData: null,
editR: editRenderer
}),
mounted () {
this.columnDefs = [
{ headerName: "Name", field: "name", sortable: true, filter: true },
{ headerName: "e-Mail", field: "email", sortable: true, filter: true },
{ headerName: "Contact", field: "contact", sortable: true, filter: true },
{ headerName: "Contact", field: "contact", sortable: true, filter: true, cellRenderer: editRenderer }
];
this.rowData = [
{ name: "Robin Sharma", email: "robin#sharma.com", contact: 8508035076 },
{ name: "Amish Tripathi", email: "amish#tripathi.com", contact: 9250035054 },
{ name: "Zig Ziglar", email: "zig#ziglar.com", contact: 9206635030 },
{ name: "Paulo Coelho", email: "paolo#coelho.com", contact: 7288012335 }
];
},
methods: {
loadUsers () {
// console.log("Loading Users from api.");
}
}
};
</script>
And index.vue file for Ag grid table as
<template>
<div>
<ag-grid-vue
style=" height: 650px;"
class="ag-theme-balham"
:column-defs="_props.columnDefs"
:row-data="_props.rowData"
:framework-components="frameworkComponents"
/>
</div>
</template>
<script>
import "ag-grid-community/dist/styles/ag-grid.css";
import "ag-grid-community/dist/styles/ag-theme-balham.css";
import { AgGridVue } from "ag-grid-vue";
import editRenderer from "../AgGridRenderers/editDeleteRenderer.vue";
export default {
components: {
AgGridVue
},
props: [
"column-defs", "row-data"
],
data: () => ({
frameworkComponents: {
editRenderer
}
}),
mounted () {
console.log(this._props.columnDefs, this._props.rowData);
}
};
</script>
And editrenderer.vue file as:
<template>
<div>
<span>
<button #click="sayHi"> Edit Item </button>
</span>
</div>
</template>
<script>
export default {
created () {
console.log("Hello from Edit");
},
methods: {
sayHi () {
alert("Hi");
}
}
};
</script>
And all I am getting in the DOM is empty edit-renderer tags
Doesn't AgGrid support cellRenderers in Vue Js?
In the end the imported component appears as a vue component in the Dom if used separately as a common Dom element. Does that mean we explicitly have to compile it somehow? I also tried using setTimeOut before initializing columnDefs and rowData where AgTable is used. but still it doesn't show anything in the table.
Ok, so what I did was add some missing properties to ag-grid-vue element such as grid-options, context and grid-ready, and add refresh function to the renderer component, and convert all related components from simple "export default{" to "export default Vue.extends({".
I think this problem was resolved.
Though, I am getting 'this is undefined' error now.
Ag-grid should clarify which parameters are compulsory other than rowData and colDefs with their purpose.