vue component data watch outside - vue.js

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>

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>

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));
}

badge position for nodes

I'm trying to add badges to my cytoscape.js nodes. Badges are HTML elements. I'm using bootstrap badges
Here are elements with badges. (the colors of the badges are irrelevant)
When I zoom out, the position of the badges is not set correctly. They go down and right a bit. WHY IS THAT?
Here is my code to set the positions. I but badges to to top left of the node. But I remove width of the HTML element to make it look like inside the node
let z1 = cy.zoom() / 2; // badges look too big with normal size so I downscale them
// e is cytoscape.js element, a node
const p = e.renderedPosition();
const eW = e.renderedWidth() / 2;
const eH = e.renderedHeight() / 2;
// div is an HTML element which is the badge
const w = div.clientWidth;
div.style.transform = `translate(${p.x + eW - w * z1}px, ${p.y - eH}px) scale(${z1})`;
I would personally prefer a solution using cytoscape.js resources/extensions, namely the popper.js extension.
As far as I understand your problem, you add bootstrap elements to cytoscape.js in some way (you didn't specify this, so I have to guess).
Nomrally, a sticky popper div does the trick for this problem:
var cy = (window.cy = cytoscape({
container: document.getElementById("cy"),
style: [{
selector: "node",
css: {
content: "data(id)",
"text-valign": "center",
"text-halign": "center",
height: "60px",
width: "160px",
shape: "round-rectangle"
}
},
{
selector: "edge",
css: {
"target-arrow-shape": "triangle"
}
}
],
elements: {
nodes: [{
data: {
id: "n0"
}
},
{
data: {
id: "n1"
}
},
{
data: {
id: "n2"
}
},
{
data: {
id: "n3"
}
},
{
data: {
id: "n4"
}
},
{
data: {
id: "n5"
}
},
{
data: {
id: "n6"
}
},
{
data: {
id: "n7"
}
},
{
data: {
id: "n8"
}
},
{
data: {
id: "n9"
}
},
{
data: {
id: "n10"
}
},
{
data: {
id: "n11"
}
},
{
data: {
id: "n12"
}
},
{
data: {
id: "n13"
}
},
{
data: {
id: "n14"
}
},
{
data: {
id: "n15"
}
},
{
data: {
id: "n16"
}
}
],
edges: [{
data: {
source: "n0",
target: "n1"
}
},
{
data: {
source: "n1",
target: "n2"
}
},
{
data: {
source: "n1",
target: "n3"
}
},
{
data: {
source: "n4",
target: "n5"
}
},
{
data: {
source: "n4",
target: "n6"
}
},
{
data: {
source: "n6",
target: "n7"
}
},
{
data: {
source: "n6",
target: "n8"
}
},
{
data: {
source: "n8",
target: "n9"
}
},
{
data: {
source: "n8",
target: "n10"
}
},
{
data: {
source: "n11",
target: "n12"
}
},
{
data: {
source: "n12",
target: "n13"
}
},
{
data: {
source: "n13",
target: "n14"
}
},
{
data: {
source: "n13",
target: "n15"
}
}
]
},
layout: {
name: "dagre",
padding: 5,
rankSep: 100
}
}));
var makeTippy = function(node, text) {
var ref = node.popperRef();
var dummyDomEle = document.createElement("div");
var tip = tippy(dummyDomEle, {
onCreate: function(instance) {
instance.popperInstance.reference = ref;
},
lazy: false, // mandatory
trigger: "manual", // mandatory
// dom element inside the tippy:
content: function() {
var div = document.createElement("div");
div.innerHTML = text;
return div;
},
// your own preferences:
arrow: false,
placement: 'top-end',
hideOnClick: false,
multiple: true,
sticky: true
});
return tip;
};
cy.ready(function() {
cy.zoom(0.75);
cy.center();
cy.ready(function() {
let nodes = cy.nodes();
nodes.each(function(node) {
let tippy = makeTippy(node, node.id());
tippy.show();
});
});
});
body {
font: 14px helvetica neue, helvetica, arial, sans-serif;
}
#cy {
height: 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
}
.tippy-popper {
transition: none !important;
}
<html>
<head>
<script src="https://unpkg.com/cytoscape/dist/cytoscape.min.js"></script>
<script src="https://unpkg.com/dagre#0.7.4/dist/dagre.js"></script>
<script src="https://cdn.jsdelivr.net/npm/cytoscape-dagre#2.1.0/cytoscape-dagre.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js#1.16.1/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/cytoscape-popper#1.0.6/cytoscape-popper.min.js"></script>
<script src="https://unpkg.com/tippy.js#5.1.3/dist/tippy-bundle.iife.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/tippy.js#5.1.3/dist/tippy.css" />
</head>
<body>
<div id="cy"></div>
</body>
</html>
This snippet cuts some of the container off, so try this in your application for better results and take a look at the extensions used here
The problem stems from CSS scale. When I scale the element, the center point of the element remains invariant. The below sample shows What I mean
div {
position: absolute;
}
span {
font-size: 64px;
}
.s1 {
transform: scale(1);
background: red;
}
.s2 {
transform: scale(0.5);
background: blue;
}
<div class="s1"><span>00</span></div>
<div class="s2"><span>00</span></div>
So I have to consider the center point of the div. Below code does that
let z1 = this._g.cy.zoom() / 2;
const bb = e.renderedBoundingBox({ includeLabels: false, includeOverlays: false });
const w = div.clientWidth;
const h = div.clientHeight;
const deltaW4Scale = (1 - z1) * w / 2;
const deltaH4Scale = (1 - z1) * h / 2;
div.style.transform = `translate(${bb.x2 - deltaW4Scale - w * z1}px, ${bb.y1 - deltaH4Scale}px) scale(${z1})`;

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

How to update the props for a child component in 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>