Emit filtered rows count in ag grid vue - vue.js

I am trying to emit filtered rows count from ag grid table which is my child component to the parent component
<template>
<ag-grid-vue
style="width: 100%; height: 600px"
class="ag-theme-balham"
id="myGrid"
:enableRangeSelection="true"
:defaultColDef="{
resizable: true,
sortable: true,
filter: true,
width: 100
}"
:columnDefs="columnDefs"
:gridOptions="gridOptions"
:processCellForClipboard="processCellForClipboard"
:rowData="newRowData"
:modules="[...agModule, ...agCModule]"
></ag-grid-vue>
</template>
<script>
import { AgGridVue } from "ag-grid-vue";
import "ag-grid-enterprise";
import { LicenseManager } from "ag-grid-enterprise";
import { AllModules } from "ag-grid-enterprise/dist/ag-grid-enterprise";
import { AllCommunityModules } from "ag-grid-community/dist/ag-grid-community";
LicenseManager.setLicenseKey(process.env.VUE_APP_AG_KEY);
import axios from "axios";
export default {
name: "Table",
props: {
columnDefs: {
type: Array,
default() {
return null;
}
},
rowData: {
type: Array,
default() {
return null;
}
}
},
components: {
"ag-grid-vue": AgGridVue
},
data() {
return {
agModule: AllModules,
agCModule: AllCommunityModules,
newRowData: [],
gridApi: null,
gridOptions: {}
};
},
watch: {
rowData: function(newVal, oldVal) {
this.newRowData = newVal;
},
count: "getDisplayedRowCount"
},
computed: {
count() {
return this.gridApi.getDisplayedRowCount();
}
},
beforeMount() {
this.processCellForClipboard = params => {
return `${params.value.trim()},`;
};
},
methods: {
getDisplayedRowCount() {
console.log("getDisplayedRowCount() => " + this.count);
this.$emit("filteredrows", this.count);
}
},
mounted() {
this.newRowData = this.rowData;
this.gridApi = this.gridOptions.api;
}
};
</script>
<style lang="sass" scoped>
#import "../../../node_modules/ag-grid-community/dist/styles/ag-grid.css"
#import "../../../node_modules/ag-grid-community/dist/styles/ag-theme-balham.css"
</style>
This is how my child component looks.
But when the ag grid table loads the gridapi value is null, due to which i do not get the value of count defined in computed property. I want to call the function getDisplayedRowCount each time there is change in no of rows. How can I achieve this?

You can write your computed property like this
computed: {
count() {
if (this.gridApi) {
return this.gridApi.getDisplayedRowCount();
} else {
return this.newRowData.length;
}
}
},

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>

Initialization of variables with Vuex

I made a VueJS 3 project with VueX to store the data.
When I print the variable data.doughnutChart.data in the following code it displays
{ "labels": [ "OK", "WARNING", "ERROR" ], "datasets": [ {
"backgroundColor": [ "#d4efdf", "#fdebd0", "#fadbd8" ], "data": [ 3,
1, 2 ] } ] }
But the graph doesn't use these data [3,1,2], the graph uses the values of the initialization in the index.js of VueX.
Here my code :
<template>
{{data.doughnutChart.data}}
<div style="height:200px;width: 200px; position:center">
<vue3-chart-js
:id="data.doughnutChart.id"
:type="data.doughnutChart.type"
:data="data.doughnutChart.data"
:options="data.doughnutChart.options"
></vue3-chart-js>
</div>
</template>
<script>
import Vue3ChartJs from '#j-t-mcc/vue3-chartjs'
export default {
name: 'App',
components: {
Vue3ChartJs,
},
beforeMount() {
this.$store.dispatch("getData");
},
computed: {
data() {
return {
doughnutChart: {
id: 'doughnut',
type: 'doughnut',
data: {
labels: ['OK', 'WARNING', 'ERROR'],
datasets: [
{
backgroundColor: [
'#d4efdf',
'#fdebd0',
'#fadbd8'
],
data: [this.$store.state.nbOk, this.$store.state.nbWarning, this.$store.state.nbError]
}
]
},
options:
{
plugins: {
legend: {
display: false
},
title: {
display: true,
text: 'Current situation'
}
},
}
}
}
}
}
}
</script>
I read the value in my index.js (VueX) :
import axios from 'axios'
import { createStore } from 'vuex'
export default createStore({
state: {
data: [],
nbError : 0,
nbWarning : 0,
},
actions: {
getData({commit}){
axios.get('http://localhost:8080/data/mock.json')
.then(res => {
commit('SET_DATA', res.data)
})}
},
mutations: {
SET_DATA(state, data){
state.data = data.data;
state.nbWarning = 0;
state.nbError = 0;
for (let i = 0; i < state.data.length; i++) {
if(state.data[i].status == 'WARNING'){
state.nbWarning += 1;
};
if(state.data[i].status == 'ERROR'){
state.nbError += 1;
};
};
}
})
However it works when, in my Vuejs project, I go in an other page and come back but not when I just open the project or refresh the page.
Do you know why ?
data property should be defined as computed in order to receive store changes:
<template>
{{data}}
</template>
<script>
export default {
data() {
return {
}
},
computed:{
data(){
return [this.$store.state.nbWarning, this.$store.state.nbError]
}
},
beforeMount() {
this.$store.dispatch("getData");
}
}
</script>

Unable to display chart using API call in chartjs in the context of Vuejs

Im trying to display chart using chartjs by calling API, but unable to do so.
Here s my LineChart.vue:
<script>
import {Line, mixins} from 'vue-chartjs' // We specify what type of chart we want from vue-chartjs and the mixins module
const { reactiveProp } = mixins
export default { //We are extending the base chart class as mentioned above
extends: Line,
mixins: [reactiveProp],
data () {
return {
options: { //chart options
lineTension: 0,
maintainAspectRatio: false,
legend: {
display: false
},
scales: {
yAxes: [
{
scaleLabel: {
display: false
},
ticks: {
beginAtZero: true,
// eslint-disable-next-line no-unused-vars
callback (value, index, values) {
return `${value }%`
}
}
}
],
xAxes: [
{
type: 'time',
time: {
unit: 'month'
},
scaleLabel: {
display: true,
labelString: ''
}
}
]
}
}
}
},
mounted () {
// this.chartData is created in the mixin
this.renderChart(this.chartData, this.options)
}
}
</script>
And here is my Home.vue where i have imported the LineChart:
<template>
<div class="chart">
<line-chart :chart-data="datacollection"></line-chart>
</div>
</template>
<script>
import LineChart from './LineChart'
import axios from 'axios'
import DateTime from 'luxon'
export default {
data () {
return {
date: {},
challenge: {},
datacollection: {}
}
},
component: {LineChart},
created() {
this.fillData()
},
mounted () {
this.fillData()
},
methods: {
fillData () {
axios.get('https://my_api_goes_here')
.then(response => {
const results = response.data
const dateresult = results.map(a => a.date)
const challengeresult = results.map(a => a.challenge)
this.date = dateresult
this.challenge = challengeresult
this.datacollection = {
labels: [this.date].map(labels => DateTime.fromMillis(labels * 1000).toFormat('MMM yyyy')),
datasets: [
{
data: [this.challenge],
label: 'Africa',
borderColor: '#7367F0'
}
]
}
})
.catch(error => {
console.log(error)
})
}
}
}
</script>
Dont know why the chart did not appear even though my other resources have been loaded from the API call, when i checked out my console, this is what error im getting:
TypeError: results.map is not a function
Please check out my logic and let me where the error is.

Unable to Construct Stacked Vue-ChartJS Line Plot

I'm trying to make a stacked line chart using Vue-ChartJS but am having difficulties getting it to stack.
I tried adding the following into the fill data function but saw no change.
scales: {
yAxes: [{ stacked: true}]
}
I also tried creating a this.options entry but that didn't work either. The minimal reproducible code for the chart is as follows, any advice or help would be much appreciated!
## LineChart.js
import { Line, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins
export default {
extends: Line,
mixins: [reactiveProp],
props: ['options'],
mounted() {
this.renderChart(this.chartData, this.options)
}
}
## LineChart.vue
<template>
<div class="small">
<line-chart :chart-data="chartData"></line-chart>
<button #click="fillData()">Randomize</button>
</div>
</template>
<script>
import LineChart from '../store/LineChart.js'
export default {
components: {
LineChart
},
data() {
return {
chartData: null
}
},
mounted() {
this.fillData()
},
methods: {
fillData() {
this.chartData = {
labels: [this.getRandomInt(), this.getRandomInt()],
datasets: [
{
label: 'Data One',
backgroundColor: '#f87979',
data: [this.getRandomInt(), this.getRandomInt()]
},
{
label: 'Data Two',
backgroundColor: '#C23596',
data: [this.getRandomInt(), this.getRandomInt()]
}
]
}
},
getRandomInt() {
return Math.floor(Math.random() * (50 - 5 + 1)) + 5
}
}
}
</script>
<style>
.small {
max-width: 600px;
margin: 150px auto;
}
</style>
You need to pass scales in the options:
...
<div class="small">
<line-chart :chart-data="chartData" :options="options"></line-chart>
<button #click="fillData()">Randomize</button>
</div>
...
data() {
return {
chartData: null,
options: {
scales: {
yAxes: [
{
stacked: true
}
]
},
},
}
},

How to render dynamic the quantity of svg shape element in Vue.js?

My svg shape elements and they attributes was query from server side then
how to render that dynamically in vue to use v-for without static html tag?
Sounds like a job for a Render Function. For example:
Create SvgElement.vue:
render: function (createElement) {
return createElement(
this.shapeType,
{
attrs: this.attrObj
},
this.$slots.default
)
},
props: {
shapeType: {
type: String,
required: true
},
attrString: {
type: string
}
},
computed: {
attrObj() {
// Convert this.attrString into an object
// eg return { cx: 50, cy: 50, r: 10, fill: 'red' }
}
}
Then use in MyComponent.vue
<template>
<svg width="400" height="400">
<SvgElement
v-for="svg in svgArray"
:key="svg.key"
:shapeType="svg.type"
:attrString="svg.attr"
/>
</svg>
</template>
<script>
import SvgElement from './SvgElement'
export default {
components: {
SvgElement
},
data () {
return {
svgArray: [
{ type: 'rect', attr: 'attrString', key: 'shape1' },
{ type: 'circle', attr: 'attrString', key: 'shape2' }
]
}
}
}
</script>