반응형
chart.js + ag-grid-vue3
문제사항
위와 같이 같은 데이터를 나타내는 차트와 그리드가 있습니다.
우측의 그리드에서 데이터가 변경되었을 때 차트 또한 업데이트되도록 구현하고 싶었습니다.
사용한 json 데이터는 다음과 같습니다.
[
{
"name": "mark",
"score": 100
},
{
"name": "Nick",
"score": 80
},
{
"name": "Jack",
"score": 60
},
{
"name": "Mary",
"score": 55
},
{
"name": "John",
"score": 90
}
]
해결 과정
순서
- Props 로 동일한 data 공유하기
- Grid 에서 변경된 데이터를 emit 을 이용해 App.vue 의 기존 데이터에 덮어쓰기
- :key 속성 이용하기 (Re-Rendering)
1. Props 를 사용해 동일한 Data 를 사용하도록 했습니다.
- App.vue
<template>
<div>
<div><h1>Chart And Grid</h1></div>
<div class="container">
<Chart :scoreData="state.scoreData"></Chart>
<Grid :scoreData="state.scoreData"></Grid>
</div>
</div>
</template>
<script setup>
import Chart from "./views/Chart.vue";
import Grid from "./views/Grid.vue";
import Score from "./database/score.json";
import { reactive } from "vue";
const state = reactive({
scoreData: Score,
});
</script>
- Grid.vue
<!-- template code -->
<ag-grid-vue
style="width: 500px; height: 300px"
class="ag-theme-alpine"
:columnDefs="GridData.columnDefs"
:rowData="GridData.rowData"
>
</ag-grid-vue>
<!-- script code -->
<script setup>
import "ag-grid-community/dist/styles/ag-grid.css";
import "ag-grid-community/dist/styles/ag-theme-alpine.css";
import { AgGridVue } from "ag-grid-vue3";
import { defineProps, reactive } from "@vue/runtime-core";
const props = defineProps({
scoreData: Array,
});
const GridData = reactive({
columnDefs: [
{ headerName: "이름", field: "name" },
{ headerName: "점수", field: "score", editable: true },
],
rowData: props.scoreData,
});
</script>
- Chart.vue
<!-- template code -->
<canvas style="width: 500px; height: 300px" id="myChart"></canvas>
<!-- script code -->
<script setup>
import { addColor, getNameAndScore } from "../utils/index.js";
import { onMounted, defineProps } from "vue";
import Chart from "chart.js";
const props = defineProps({
scoreData: Array,
});
// 이름과 점수만 들어있는 배열로 뽑아냅니다.
const nameArr = getNameAndScore(props.scoreData).name;
const scoreArr = getNameAndScore(props.scoreData).score;
console.log(scoreArr);
onMounted(() => {
var ctx = document.getElementById("myChart").getContext("2d");
var myChart = new Chart(ctx, {
type: "bar",
data: {
labels: nameArr,
datasets: [
{
data: scoreArr,
backgroundColor: addColor(props.scoreData), // 대충 랜덤색 생성
},
],
},
// options
});
});
</script>
위처럼 차트와 그리드에 입력될 데이터는 App.vue 에 있는 scoreData 를 Props 로 받아오도록 했습니다.
2. Ag-Grid-Vue3 의 onCellEditingStopped 속성을 사용해 셀 편집이 끝난 경우 emit 이벤트를 실행하도록 했습니다.
<!-- template code -->
<ag-grid-vue
style="width: 500px; height: 300px"
class="ag-theme-alpine"
:columnDefs="GridData.columnDefs"
:rowData="GridData.rowData"
:onCellEditingStopped="change"
>
</ag-grid-vue>
<!-- script code -->
<script setup>
// 생략 : 위 코드와 동일합니다.
// import { defineProps, defineEmits, reactive } from "@vue/runtime-core";
const emit = defineEmits(["changeScore"]);
const change = () => {
emit("changeScore", GridData.rowData);
};
</script>
- App.vue
<Grid @changeScore="changeData" :scoreData="state.scoreData"></Grid>
<!-- script code -->
<script setup>
// 생략 : 위 App.vue 코드와 동일합니다.
function changeData(data) {
for (let i = 0; i < data.length; i++) {
data[i].score = Number(data[i].score);
}
state.scoreData = data;
console.log(data);
}
</script>
emit 을 통해 변경된 값을 App.vue 로 보낸 다음, 기존의 scoreData 변수에 변경된 data 값을 넣었습니다.
3. :key 속성을 이용해 Chart 컴포넌트를 Re-Rendering 해주면 됩니다.
:key 속성은 가리키는 값에 변화가 일어나면 해당 컴포넌트를 Re-Render 해줍니다.
<!-- template code -->
<template>
<div>
<div><h1>Chart And Grid</h1></div>
<div class="container">
<Chart :key="state.render" :scoreData="state.scoreData"></Chart>
<Grid @changeScore="changeData" :scoreData="state.scoreData"></Grid>
</div>
</div>
</template>
<!-- script code -->
<script setup>
// 생략
const state = reactive({
scoreData: Score,
render: 0,
});
function changeData(data) {
for (let i = 0; i < data.length; i++) {
data[i].score = Number(data[i].score);
}
state.scoreData = data;
state.render++;
}
</script>
Vue 3 에서는 updateForce() 기능이 사라졌습니다.
구현을 위해 임시로 사용했기 때문에 이 방법이 가장 효율적인 방법은 아닐 수 있습니다.
더 효율적인 방법을 아시는 분은 좀 알려주세요..
결과
사용 라이브러리
ag-grid-vue3, chart.js@2.9.4 를 사용했습니다.
반응형
'Study > Vue' 카테고리의 다른 글
VueJS 3 ) <script setup> 과 setup() 의 차이 (0) | 2022.03.21 |
---|---|
VueJS 3 ) Composition API 를 기반으로 한 NewsWebApp (0) | 2022.03.21 |
VueJS 3 ) setup() 함수의 2 가지 인자 props, context (0) | 2022.03.20 |
VueJS 3 ) TodoApp 을 통한 OptionsAPI 와 Composition API 비교 (1) | 2022.03.20 |
Vuejs ) TodoApp (Vue2에서 Vue3으로) (0) | 2022.03.20 |
댓글