How to update the props for a child component in Vue.js? - vue.js

I have a parent component that will do an API call for some data. When the response gets back I update the data. I sent the data to a child component. This child component only renders the initial value, which is an empty array, but never the updated data. I know that in React updating a property will result in a re-render of the child component. How can I achieve this in Vue.js?
This is the parent component that will pass the data:
<template>
<div id="app">
<Table v-bind:users='users' />
</div>
</template>
<script>
import Table from './components/Table'
export default {
name: 'app',
components: {
Table
},
data () {
return {
users: []
}
},
created: () => {
fetch('http://jsonplaceholder.typicode.com/users').then((response) => {
response.json().then((data) => {
console.log(data)
this.users = data
})
})
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
This is the child component that will receive the data and update the view:
<template>
<ul>
<li v-for='user in users'>
{{ user.name }}
</li>
</ul>
</template>
<script>
export default {
name: 'Table',
data () {
return {
}
},
props: ['users'],
}
</script>
<style scoped>
</style>
The fetch response looks like this:
[
{
"id":1,
"name":"Leanne Graham",
"username":"Bret",
"email":"Sincere#april.biz",
"address":{
"street":"Kulas Light",
"suite":"Apt. 556",
"city":"Gwenborough",
"zipcode":"92998-3874",
"geo":{
"lat":"-37.3159",
"lng":"81.1496"
}
},
"phone":"1-770-736-8031 x56442",
"website":"hildegard.org",
"company":{
"name":"Romaguera-Crona",
"catchPhrase":"Multi-layered client-server neural-net",
"bs":"harness real-time e-markets"
}
},
{
"id":2,
"name":"Ervin Howell",
"username":"Antonette",
"email":"Shanna#melissa.tv",
"address":{
"street":"Victor Plains",
"suite":"Suite 879",
"city":"Wisokyburgh",
"zipcode":"90566-7771",
"geo":{
"lat":"-43.9509",
"lng":"-34.4618"
}
},
"phone":"010-692-6593 x09125",
"website":"anastasia.net",
"company":{
"name":"Deckow-Crist",
"catchPhrase":"Proactive didactic contingency",
"bs":"synergize scalable supply-chains"
}
},
{
"id":3,
"name":"Clementine Bauch",
"username":"Samantha",
"email":"Nathan#yesenia.net",
"address":{
"street":"Douglas Extension",
"suite":"Suite 847",
"city":"McKenziehaven",
"zipcode":"59590-4157",
"geo":{
"lat":"-68.6102",
"lng":"-47.0653"
}
},
"phone":"1-463-123-4447",
"website":"ramiro.info",
"company":{
"name":"Romaguera-Jacobson",
"catchPhrase":"Face to face bifurcated interface",
"bs":"e-enable strategic applications"
}
},
{
"id":4,
"name":"Patricia Lebsack",
"username":"Karianne",
"email":"Julianne.OConner#kory.org",
"address":{
"street":"Hoeger Mall",
"suite":"Apt. 692",
"city":"South Elvis",
"zipcode":"53919-4257",
"geo":{
"lat":"29.4572",
"lng":"-164.2990"
}
},
"phone":"493-170-9623 x156",
"website":"kale.biz",
"company":{
"name":"Robel-Corkery",
"catchPhrase":"Multi-tiered zero tolerance productivity",
"bs":"transition cutting-edge web services"
}
},
{
"id":5,
"name":"Chelsey Dietrich",
"username":"Kamren",
"email":"Lucio_Hettinger#annie.ca",
"address":{
"street":"Skiles Walks",
"suite":"Suite 351",
"city":"Roscoeview",
"zipcode":"33263",
"geo":{
"lat":"-31.8129",
"lng":"62.5342"
}
},
"phone":"(254)954-1289",
"website":"demarco.info",
"company":{
"name":"Keebler LLC",
"catchPhrase":"User-centric fault-tolerant solution",
"bs":"revolutionize end-to-end systems"
}
},
{
"id":6,
"name":"Mrs. Dennis Schulist",
"username":"Leopoldo_Corkery",
"email":"Karley_Dach#jasper.info",
"address":{
"street":"Norberto Crossing",
"suite":"Apt. 950",
"city":"South Christy",
"zipcode":"23505-1337",
"geo":{
"lat":"-71.4197",
"lng":"71.7478"
}
},
"phone":"1-477-935-8478 x6430",
"website":"ola.org",
"company":{
"name":"Considine-Lockman",
"catchPhrase":"Synchronised bottom-line interface",
"bs":"e-enable innovative applications"
}
},
{
"id":7,
"name":"Kurtis Weissnat",
"username":"Elwyn.Skiles",
"email":"Telly.Hoeger#billy.biz",
"address":{
"street":"Rex Trail",
"suite":"Suite 280",
"city":"Howemouth",
"zipcode":"58804-1099",
"geo":{
"lat":"24.8918",
"lng":"21.8984"
}
},
"phone":"210.067.6132",
"website":"elvis.io",
"company":{
"name":"Johns Group",
"catchPhrase":"Configurable multimedia task-force",
"bs":"generate enterprise e-tailers"
}
},
{
"id":8,
"name":"Nicholas Runolfsdottir V",
"username":"Maxime_Nienow",
"email":"Sherwood#rosamond.me",
"address":{
"street":"Ellsworth Summit",
"suite":"Suite 729",
"city":"Aliyaview",
"zipcode":"45169",
"geo":{
"lat":"-14.3990",
"lng":"-120.7677"
}
},
"phone":"586.493.6943 x140",
"website":"jacynthe.com",
"company":{
"name":"Abernathy Group",
"catchPhrase":"Implemented secondary concept",
"bs":"e-enable extensible e-tailers"
}
},
{
"id":9,
"name":"Glenna Reichert",
"username":"Delphine",
"email":"Chaim_McDermott#dana.io",
"address":{
"street":"Dayna Park",
"suite":"Suite 449",
"city":"Bartholomebury",
"zipcode":"76495-3109",
"geo":{
"lat":"24.6463",
"lng":"-168.8889"
}
},
"phone":"(775)976-6794 x41206",
"website":"conrad.com",
"company":{
"name":"Yost and Sons",
"catchPhrase":"Switchable contextually-based project",
"bs":"aggregate real-time technologies"
}
},
{
"id":10,
"name":"Clementina DuBuque",
"username":"Moriah.Stanton",
"email":"Rey.Padberg#karina.biz",
"address":{
"street":"Kattie Turnpike",
"suite":"Suite 198",
"city":"Lebsackbury",
"zipcode":"31428-2261",
"geo":{
"lat":"-38.2386",
"lng":"57.2232"
}
},
"phone":"024-648-3804",
"website":"ambrose.net",
"company":{
"name":"Hoeger LLC",
"catchPhrase":"Centralized empowering task-force",
"bs":"target end-to-end models"
}
}
]

I've figured it out myself!
The problem was the syntax I was using.
I had:
created: () => {
fetch('http://jsonplaceholder.typicode.com/users').then((response) => {
response.json().then((data) => {
console.log(data)
this.users = data
})
})
}
I changed it to:
created() {
fetch('http://jsonplaceholder.typicode.com/users').then((response) => {
response.json().then((data) => {
console.log(data)
this.users = data
})
})
}
I guess it's just a binding issue with the es6 fat arrow.

You can check it in this example, its ractive when you set props it will pass to child automatically and trigger re-render
Vue.component('child', {
template: '#child',
props: ['users']
});
new Vue({
el: '#app',
data: {
users: []
},
created: function() {
var vm = this;
setTimeout(function() {
vm.users = [{ name: 'hardik'}, { name: 'someone'}];
}, 2000)
},
methods: {
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.3/vue.js"></script>
<div id="app">
<child :users="users"></child>
</div>
<template id="child">
<ul>
<li v-for='user in users'>
{{ user.name }}
</li>
</ul>
</template>

Related

Flickering of charts and getcontext error with chartjs in the context of Vuejs

Hello i am trying to display different charts using the chartjs by calling the API. Below code shows how i have formatted the chart.vue
Chart.vue:
<template>
<div class="chart-container" style="position: relative; height: 40vh; width:100%;">
<slot name="test1"></slot>
<slot name="test2"></slot>
</div>
</template>
<script>
export default {
name: 'charts',
data () {
return {
date: [],
challenge: [],
data: []
}
},
mounted () {
this.check(8, 'chart_8')
this.check(7, 'chart_7')
},
methods: {
check (id, name) {
this.$http.get(`/api_chart/${ id }/full`)
.then((response) => {
this.date = response.data.date
this.challenge = response.data.challenge
this.data = this.date.map((date, index) => ({
x: new Date(date * 1000),
y: this.challenge[index]
}))
const ctx = document.getElementById([name]).getContext('2d')
let myChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [
{
label: 'Challenge',
data: this.data,
borderColor: ' #EA5455',
}
]
},
options: {
lineTension: 0,
maintainAspectRatio: false,
scales: {
yAxes: [
{
scaleLabel: {
display: false
},
ticks: {
beginAtZero: true,
callback (value) {
return `${value}%`
}
}
}
],
xAxes: [
{
type: 'time',
time: {
unit: 'month'
},
scaleLabel: {
display: true,
}
}
]
}
}
})
})
}
}
}
</script>
App.vue:
<template>
<div class="In order to display chart1">
<chart-display> <canvas slot="test1" id="chart_7" ></canvas> </chart-display>
</div>
<div class="In order to display chart1">
<chart-display> <canvas slot="test2" id="chart_8" ></canvas> </chart-display>
</div>
</template>
<script>
import chart-display from './Chart.vue'
export default {
component: {chart-display}
}
</script>
As you can see i have shared my Chart.vue and App.vue, i am able to see my chart in the browser, but whenever i run the code or refresh the page, the charts flickers and stops. And then in my console i get below error:
Please someone help me to get rid of this issue, and please tell me if any changes i should do in my code to solve it. Please send me the modification code.
As I wrote in my comment, the charts are rendered twice. This causes flickering.
// every time you use <chart-display>, 2 charts are rendered, this means chart 1 renders
// itself and chart 2, char 2 renders itself and chart 1, this is a bad pattern in Vue in general
mounted() {
this.check(8, "chart_8");
this.check(7, "chart_7");
}
Make the following changes:
ChartDisplay.vue
<template>
<div
class="chart-container"
style="position: relative; height: 40vh; width: 100%"
>
<canvas ref="chart_7"></canvas>
<canvas ref="chart_8"></canvas>
</div>
</template>
<script>
import Chart from "chart.js";
export default {
name: "ChartDisplay",
data() {
return {
date: [],
challenge: [],
data: [],
// save charts in an array
charts: [],
// charts options
options: {
lineTension: 0,
maintainAspectRatio: false,
scales: {
yAxes: [
{
scaleLabel: {
display: false,
},
ticks: {
beginAtZero: true,
callback(value) {
return `${value}%`;
},
},
},
],
xAxes: [
{
type: "time",
time: {
unit: "month",
},
scaleLabel: {
display: true,
},
},
],
},
},
};
},
mounted() {
this.render(7, this.$refs.chart_7);
this.render(8, this.$refs.chart_8);
},
methods: {
render(id, ctx) {
this.fetchData(id).then((response) => {
let data = response.date.map((date, index) => ({
x: new Date(date * 1000),
y: response.challenge[index],
}));
this.charts.push(
new Chart(ctx, {
type: "line",
data: {
datasets: [
{
label: "Challenge",
data: data,
borderColor: " #EA5455",
},
],
},
options: this.options,
})
);
});
},
fetchData(id) {
return this.$http.get(`/api_chart/${ id }/full`);
},
},
beforeDestroy() {
this.charts.forEach((chart) => chart.destroy());
},
};
</script>
<style >
[v-cloak] {
display: none;
}
</style>
App.vue
<template>
<div>
<div class="In order to display chart1">
<chart-display/>
</div>
</div>
</template>
<script>
import ChartDisplay from "./ChartDisplay.vue";
export default {
components: { ChartDisplay },
};
</script>
See it on sandbox
I found several errors on your code. I fix them in Sandbox
For Chat.vue :
I rename the file as ChartDisplay.vue as similar as the component name
import chart.js package for using Chart() function
I use a demo API
<template>
<div
class="chart-container"
style="position: relative; height: 40vh; width: 100%"
>
<slot name="test1"></slot>
<slot name="test2"></slot>
</div>
</template>
<script>
import Chart from "chart.js";
export default {
name: "ChartDisplay",
data() {
return {
date: [],
challenge: [],
data: [],
};
},
mounted() {
this.check(8, "chart_8");
this.check(7, "chart_7");
},
methods: {
check(id, name) {
fetch(
"https://api.wirespec.dev/wirespec/stackoverflow/fetchchartdataforvuejs"
)
.then((response) => response.json())
.then((response) => {
this.date = response.date;
this.challenge = response.challenge;
this.data = this.date.map((date, index) => ({
x: new Date(date * 1000),
y: this.challenge[index],
}));
const ctx = document.getElementById([name]).getContext("2d");
new Chart(ctx, {
type: "line",
data: {
datasets: [{
label: "Challenge",
data: this.data,
borderColor: " #EA5455",
}, ],
},
options: {
lineTension: 0,
maintainAspectRatio: false,
scales: {
yAxes: [{
scaleLabel: {
display: false,
},
ticks: {
beginAtZero: true,
callback(value) {
return `${value}%`;
},
},
}, ],
xAxes: [{
type: "time",
time: {
unit: "month",
},
scaleLabel: {
display: true,
},
}, ],
},
},
});
});
},
},
};
</script>
For App.vue
Your import should not carry any hyphen.
component should be components
render the component once to avoid flikering
<template>
<div>
<div class="In order to display chart1">
<chart-display>
<canvas slot="test1" id="chart_7"></canvas>
<canvas slot="test2" id="chart_8"></canvas>
</chart-display>
</div>
</div>
</template>
<script>
import ChartDisplay from "./ChartDisplay.vue";
export default {
components: {
ChartDisplay
},
};
</script>

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
}
]
},
},
}
},

dynamic interpolation computed method name in v-for element in vuejs

In my project vuejs a create a list element with ul li and v-for directive vuejs like this:
<ul>
<li :class="{active: 'isActive+index'}" v-for="(car, index) in cars"></li>
</ul>
Those elements are dynamics. Sometimes are 2 sometimes are 3 or 4 elements
But I need to have a specific logic active class css for each like this:
'isActive+index'
Where this represent a dynamic computed name (already exist). But obviously this code not run and generate basic string word not a link to computed method. I want to execute those computed methods:
computed:
{
isActive1: function ()
{
return myLogic
},
isActive2: function ()
{
return myLogic
},
isActive3: function ()
{
return myLogic
},
isActive4: function ()
{
return myLogic
},
}
How can I link element with dynamic method name for execute computed with vuejs ?
new Vue({
el: '#app',
template: `
<div>
<ul>
<li v-for="(item, index) in cars" :key="index" :class="{ active: statusActive[index] }">
<strong>Car:</strong> {{item.name}} ,
</li>
</ul>
<button #click="changeCars">Change cars</button>
</div>
`,
data() {
return {
cars1: [{
name: "car1",
},
{
name: "car2",
},
{
name: "car3",
},
],
cars2: [{
name: "car1",
},
{
name: "car2",
},
{
name: "car3",
},
{
name: "car4",
},
],
cars3: [{
name: "car1",
},
{
name: "car2",
},
],
carsIndex: 1,
};
},
computed: {
cars() {
return this["cars" + this.carsIndex];
},
statusActive() {
return {
0: this.statusActive0,
1: this.statusActive1,
2: this.statusActive2,
3: this.statusActive3,
};
},
statusActive0() {
return false;
},
statusActive1() {
return true;
},
statusActive2() {
return false;
},
statusActive3() {
return true;
},
},
methods: {
changeCars() {
if (this.carsIndex < 3) {
this.carsIndex++;
} else {
this.carsIndex = 1;
}
},
},
})
.active {
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app"></div>
or
new Vue({
el: '#app',
template: `
<div>
<ul>
<li v-for="(item, index) in cars" :key="index" :class="{ active: isActive(index) }">
<strong>Car:</strong> {{item.name}} ,
</li>
</ul>
<button #click="changeCars">Change cars</button>
</div>
`,
data() {
return {
cars1: [{
name: "car1",
},
{
name: "car2",
},
{
name: "car3",
},
],
cars2: [{
name: "car1",
},
{
name: "car2",
},
{
name: "car3",
},
{
name: "car4",
},
],
cars3: [{
name: "car1",
},
{
name: "car2",
},
],
carsIndex: 1,
};
},
computed: {
cars() {
return this["cars" + this.carsIndex];
},
statusActive0() {
return false;
},
statusActive1() {
return true;
},
statusActive2() {
return false;
},
statusActive3() {
return true;
},
},
methods: {
changeCars() {
if (this.carsIndex < 3) {
this.carsIndex++;
} else {
this.carsIndex = 1;
}
},
isActive(index) {
return this["statusActive" + index];
},
},
})
.active {
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app"></div>

Using component area to show various content

I have a relatively simple task although I am just a beginner so it's difficult to proceed.
I have a list of users on the left and a right panel to show that users info. The information about the user has an edit button that I want to take over that right panel and then save will return back to the user details.
What is the best approach to go about this?
Should the 2 pages be different components or should I just use javascript to show and hide content? Is there a better approach then either of those?
Sorry I'm new and just trying to get my had around the concept.
Thanks
I wrote a simple example for you:
const data = [{
id: 1,
name: 'user1',
age: 21
},{
id: 2,
name: 'user2',
age: 33
}]
const mixin = {
props: {
userId: {
required: true
}
},
data () {
return {
user: {}
}
},
methods: {
loadUser () {
/*ajax to get user detail data here*/
setTimeout(_=>{
this.user = data.filter(o=>o.id==this.userId)[0]
},10)
}
},
created () {
this.loadUser()
},
watch: {
userId (newVal) {
if(newVal){
this.loadUser()
}
}
}
}
Vue.component('user-viewer',{
template: `<div>
name:{{user.name}}<br>
age: {{user.age}}<br>
<button #click="edit">edit</button>
</div>`,
mixins: [mixin],
methods: {
edit () {
this.$emit('switch-edit-mode',true)
}
}
});
Vue.component('user-editor',{
template: `<div>
name:<input type="text" v-model="user.name"><br>
age: <input type="text" v-model="user.age"><br>
<button #click="sendData">save</button>
</div>`,
mixins: [mixin],
methods: {
sendData () {
/*ajax send user data here*/
setTimeout(_=>{
/*false means edit complete,so that user list must be reloaded*/
this.$emit('switch-edit-mode',false);
},10)
}
}
});
var app = new Vue({
el: '#app',
data () {
return {
users: [],
isModify: false,
userId: null
}
},
methods: {
toggleModify (modify) {
this.isModify = modify
if(!modify){
this.fetchUsers();
}
},
fetchUsers () {
/*load your user list data here*/
this.users = data.map(o=>({
id: o.id,
name: o.name
}))
}
},
created () {
this.fetchUsers()
}
})
*{
padding:0;
margin:0;
}
ul,li{
list-style:none;
}
.main{
display: flex;
}
.user-list{
width: 250px;
}
.user-list>li{
border:1px solid skyblue;
border-bottom: none;
}
.user-list>li:last-child{
border-bottom:1px solid skyblue;
}
.content-wrapper{
flex:1;
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
<style>
*{
padding:0;
margin:0;
}
ul,li{
list-style:none;
}
.main{
display: flex;
}
.user-list{
width: 250px;
}
.user-list>li{
border:1px solid skyblue;
border-bottom: none;
}
.user-list>li:last-child{
border-bottom:1px solid skyblue;
}
.content-wrapper{
flex:1;
}
</style>
<div id="app">
<div class="main">
<ul class="user-list">
<li v-for="user in users" #click="userId=user.id">{{user.name}}</li>
</ul>
<div class="content-wrapper">
<component v-if="userId" :is="isModify?'user-editor':'user-viewer'" #switch-edit-mode="toggleModify" :user-id="userId"></component>
<div v-else>please choose a user to view or edit</div>
</div>
</div>
</div>
your mixin file:(mixin.js)
export default{
props: {
userId: {
required: true
}
},
data () {
return {
user: {}
}
},
methods: {
loadUser () {
/*ajax to get user detail data here*/
setTimeout(_=>{
this.user = data.filter(o=>o.id==this.userId)[0]
},10)
}
},
created () {
this.loadUser()
},
watch: {
userId (newVal) {
if(newVal){
this.loadUser()
}
}
}
}
usage:
import mixin from 'mixin.js'
export default{
...
mixins: [mixin]
}

vue component data watch outside

In my application i have a component and i want wath his properties outside of the component.
I've created this example:
Vue.component('vue-table', {
template: '<div><template v-for="row in apiData.content"><span>{{row.name}}</span><button #click="remove(row)">remove</button><br></template></div>',
data: function() {
return {
//this data will be loaded from api
apiData: {
total: 20,
content: [
{id: 10, name: 'Test'},
{id: 12, name: 'John'},
{id: 13, name: 'David'},
],
},
};
},
methods: {
remove(row) {
this.apiData.content.splice(this.apiData.content.indexOf(row), 1);
},
},
})
new Vue({
el: '#app',
methods: {
isActive(){
//how can i check if in vue-table apiData.content > 0?
//return this.$refs.table.apiData.data.length > 0;
},
},
})
http://jsfiddle.net/z11fe07p/2806/
So i want to change class of span to 'active' when the length of vue-table apiData.content.length > 0
How can i do this?
The standard practice would be to emit an event in the child and have the parent receive and act on it. You might wonder whether you can watch the length of an array -- one that doesn't even exist when the component is instantiated -- and the answer is yes.
Look at the watch section. IMO, this is so cool that it's probably frowned upon.
Vue.component('vue-table', {
template: '<div><template v-for="row in apiData.content"><span>{{row.name}}</span><button #click="remove(row)">remove</button><br></template></div>',
data: function() {
return {
//this data will be loaded from api
apiData: {},
};
},
methods: {
remove(row) {
this.apiData.content.splice(this.apiData.content.indexOf(row), 1);
},
},
watch: {
'apiData.content.length': function(is, was) {
this.$emit('content-length', is);
}
},
created() {
this.apiData = {
total: 20,
content: [{
id: 10,
name: 'Test'
}, {
id: 12,
name: 'John'
}, {
id: 13,
name: 'David'
}, ],
};
}
})
new Vue({
el: '#app',
data: {
isActive: false
},
methods: {
setActive(contentLength) {
this.isActive = contentLength > 0;
}
},
})
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
.active {
font-weight: bold;
}
<script src="//unpkg.com/vue#latest/dist/vue.js"></script>
<div id="app">
<p>
<span :class="{active: isActive}">Users:</span>
</p>
<vue-table refs="table" #content-length="setActive"></vue-table>
</div>