i'm learning vue and i have small problem.
I've created code, which receive some informations from webserwer (via socket) and this code works fine.
But i would like to do very simple thing - display info as variable in HTML and i have problem with it.
My code is:
export default {
components: {
BCard,
BButton,
},
data() {
return {
connection: null,
json: {
cmd: 'start',
width: 1024,
height: 800,
url: 'https://www.google.com',
token: '',
service_id: 1,
thumbnail_width: 100,
thumbnail_height: 100,
},
}
},
created() {
console.log('Starting Connection to WebSocket')
this.connection = new WebSocket('ws://127.0.0.1:8080/')
// this.connection = new WebSocket('ws://echo.websocket.org')
this.connection.onopen = function (event) {
console.log(event)
console.log('Success')
}
this.connection.onmessage = webSocketOnMSG
},
methods: {
sendMessage(message) {
console.log(this.connection)
console.log(message)
console.log(JSON.stringify(message))
const dat = this.connection.send(JSON.stringify(message))
console.log('TT', dat)
},
drawItem() {
const img = document.createElement('img')
const canvas = document.getElementById('canvasId')
img.src = 'http://image...'
img.onload = function (a) {
const h = a.target.height
const w = a.target.width
const c = canvas.getContext('2d')
canvas.width = w
canvas.height = h
c.drawImage(img, 0, 0)
document.getElementById('draw-image-test').appendChild(canvas)
}
},
webSocketOnMSG(msg) {
console.log(msg)
},
},
}
and i would like to add code like this:
data: {
xposition: 'xpos',
yposition: 'ypos'
}
but when i'm adding it to created earlier data() i have error, so this doesn't work:
data() {
xposition: 'xpos',
yposition: 'ypos',
return {...}
}
where should i add code to replace variables {{xposition}} and {{yposition}} in HMTL?
You must put your new variables inside your returned object in the data function, alongside your 'json' variable. You need to declare them first as empty values, and then add the proper values in your API call callback
data() {
return {
xposition: '',
yposition: '',
...
}
}
webSocketOnMSG(msg) {
// this will change your component's xposition property
this.xposition = msg.propertyYouWantToAccess
},
Related
I was define my chart as below (MainChart.vue).
import { Line, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins
// const brandPrimary = '#20a8d8'
export default {
extends: Line,
mixins: [reactiveProp],
props: ['options', 'chartData', 'height'],
mounted () {
this.renderChart(this.chartData, this.options)
var elements = 1
}
}
I tested this code and confirmed that it worked well.
<line-chart :chartData="myChartData"></line-chart>
but, I tried rendering chart dynamically, it is not working.
import lineChart from './MainChart';
// ...
let chartClass = Vue.extend(lineChart)
let chartInstance = new chartClass({
propsData: {
chartData: myChartData
}
})
chartInstance.$mount()
console.log(chartInstance.$el)
console.log(chartInstance.$el.querySelector("canvas").toDataURL('image/png'))
console.log(chartInstance.$refs.canvas)
console.log(chartInstance.$refs.canvas.toDataURL('image/png'))
Console messages:
I checked from the console and found that nothing was drawn in the canvas area.
How can I do render my chart dynamically?
Similar questions:
Is it possible to print a chart with vue-chartjs?
To get full image data, you have to wait until the chart is finished. Using 'Promise' is helpful.
async function addChart(d, i, w, h) {
var canvas = document.createElement("canvas")
canvas.width = 765
canvas.height = 382
//canvas.style.width = "765px"
//canvas.style.height = "382px"
//canvas.style.display = "none"
canvas.id = "dynamicChart"
document.body.appendChild(canvas)
var ctx = document.getElementById("dynamicChart").getContext('2d');
var draw = () => new Promise((resolve, reject) => {
new Chart(ctx, {
type: 'bar',
data: d,
options: {
responsive: false
}
})
setTimeout(() => resolve(), 100)
})
await draw()
let imageData = document.getElementById("dynamicChart").toDataURL("image/png")
console.log(imageData)
addImage(imageData, i, w, h)
document.body.removeChild(canvas)
}
// ...
await addChart(myChartData, 0, 400, 300)
If you want draw multiple chart for in the loop, try this:
let chartFunctions = []
myList.forEach((item) => {
chartFunctions.push(async function() {
await addChart(myChartData, 3, 160, 80)
})
}
for(let k in chartFunctions) {
await chartFunctions[k]()
}
Console messages:
I'm new to VueJs and currently trying to load some data only once and make it globally available to all vue components. What would be the best way to achieve this?
I'm a little bit stuck because the global variables occasionally seem to become null and I can't figure out why.
In my main.js I make three global Vue instance variables:
let globalData = new Vue({
data: {
$serviceDiscoveryUrl: 'http://localhost:40000/api/v1',
$serviceCollection: null,
$clientConfiguration: null
}
});
Vue.mixin({
computed: {
$serviceDiscoveryUrl: {
get: function () { return globalData.$data.$serviceDiscoveryUrl },
set: function (newUrl) { globalData.$data.$serviceDiscoveryUrl = newUrl; }
},
$serviceCollection: {
get: function () { return globalData.$data.$serviceCollection },
set: function (newCollection) { globalData.$data.$serviceCollection = newCollection; }
},
$clientConfiguration: {
get: function () { return globalData.$data.$clientConfiguration },
set: function (newConfiguration) { globalData.$data.$clientConfiguration = newConfiguration; }
}
}
})
and in my App.vue component I load all the data:
<script>
export default {
name: 'app',
data: function () {
return {
isLoading: true,
isError: false
};
},
methods: {
loadAllData: function () {
this.$axios.get(this.$serviceDiscoveryUrl)
.then(
response => {
this.$serviceCollection = response.data;
let configurationService = this.$serviceCollection.services.find(obj => obj.key == "ProcessConfigurationService");
this.$axios.get(configurationService.address + "/api/v1/clientConfiguration").then(
response2 => {
this.$clientConfiguration = response2.data;
}
);
this.isLoading = false;
})
}
},
created: function m() {
this.loadAllData();
}
}
</script>
But when I try to access the $clientConfiguration it seems to be null from time to time and I can't figure out why. For example when I try to build the navigation sidebar:
beforeMount: function () {
let $ = JQuery;
let clients = [];
if (this.$clientConfiguration === null)
console.error("client config is <null>");
$.each(this.$clientConfiguration, function (key, clientValue) {
let processes = [];
$.each(clientValue.processConfigurations, function (k, processValue) {
processes.push(
{
name: processValue.name,
url: '/process/' + processValue.id,
icon: 'fal fa-project-diagram'
});
});
clients.push(
{
name: clientValue.name,
url: '/client/' + clientValue.id,
icon: 'fal fa-building',
children: processes
});
});
this.nav.find(obj => obj.name == 'Processes').children = clients;
The most likely cause is that the null is just the initial value. Loading the data is asynchronous so you'll need to wait for loading to finish before trying to create any components that rely on that data.
You have an isLoading flag, which I would guess is your attempt to wait for loading to complete before showing any components (maybe via a suitable v-if). However, it currently only waits for the first request and not the second. So this:
this.$axios.get(configurationService.address + "/api/v1/clientConfiguration").then(
response2 => {
this.$clientConfiguration = response2.data;
}
);
this.isLoading = false;
would need to be:
this.$axios.get(configurationService.address + "/api/v1/clientConfiguration").then(
response2 => {
this.$clientConfiguration = response2.data;
this.isLoading = false;
}
);
If it isn't that initial value that's the problem then you need to figure out what is setting it to null. That should be prety easy, just put a debugger statement in your setter:
$clientConfiguration: {
get: function () { return globalData.$data.$clientConfiguration },
set: function (newConfiguration) {
if (!newConfiguration) {
debugger;
}
globalData.$data.$clientConfiguration = newConfiguration;
}
}
Beyond the problem with the null, if you're using Vue 2.6+ I would suggest taking a look at Vue.observable, which is a simpler way of creating a reactive object than creating a new Vue instance.
Personally I would probably implement all of this by putting a reactive object on Vue.prototype rather than using a global mixin. That assumes that you even need the object to be reactive, if you don't then this is all somewhat more complicated than it needs to be.
I have a Paper instance with a tool that just draws a path on mouseMove and deletes the segments at the start of that path if the number of segments is greater than 50. Everything works perfect this far. this is the code:
<template>
<div>
<canvas id="canvas" resize></canvas>
</div>
</template>
<script>
import paper from 'paper';
export default {
name: 'home',
components: {
},
created() {
paper.install(window);
},
mounted() {
const canvas = this.$el.querySelector('#canvas');
paper.setup(canvas);
const path = new Path();
path.strokeColor = '#f5bb56';
path.strokeWidth = 2;
this.tool = new Tool()
this.tool.onMouseMove = event => {
if (path.segments.length > 50) {
path.removeSegment(0)
};
path.add(event.point);
path.smooth({
type: 'continuous'
});
};
view.draw()
},
};
</script>
<style lang="scss">
#canvas {
width: 100%;
height: 100%;
}
</style>
The problem is that now i want to start deleting segments from that path with an interval of 50 miliseconds but stop executing that when a new segment is added. I'm looking for something to set a variable into a timeout(() => {eraseFunction()}), when the event is not fired for about two seconds.
i added a clearTimeout pointing to the variable that contains it at the start of the mouseMove event and setting it at the end, so if there's a timeout running, i remove it when the mouseMove starts:
export default {
name: 'home',
components: {
},
data() {
return {
tool: null,
path: null,
erase: null,
}
},
created() {
paper.install(window);
},
mounted() {
const canvas = this.$el.querySelector('#canvas');
paper.setup(canvas);
this.path = new Path();
this.path.strokeColor = '#f5bb56';
this.path.strokeWidth = 2;
this.tool = new Tool()
this.tool.onMouseMove = event => {
clearTimeout(this.erase);
if (this.path.segments.length > 50) {
this.path.removeSegment(0)
};
this.path.add(event.point);
this.path.smooth({
type: 'continuous'
});
this.erase = setTimeout(() => {
this.eraseFunction()
}, 2000);
};
view.draw()
},
methods: {
eraseFunction() {
setInterval(() => {
this.path.removeSegment(0);
}, 500);
}
}
};
</script>
the problem is that the timeout is not removed and given a certain amount of time, i can´t draw new segments because they´re deleted inmediately.
You need to clear setInterval also. You are only clearing setTimeout. setInterval is still running an deleting your segments.
ClearInterval need the intervalID you want to clear. The intervalID is given by setInterval call.
You should return the result of setTimout call in eraseFunction:
eraseFunction() {
return setInterval(() => {
this.path.removeSegment(0);
}, 500);
}
And you should assign to this.erase the result of eraseFunction call, instead of the setTimeout:
setTimeout(() => {
this.erase = this.eraseFunction()
}, 2000);
I am trying to add an object to an array but it is not working with me, the program can't read the property push
I defined an array in <script>:
Data: function() {
return {
Projects: [
{
name: '',
id: 0,
subscribers: 0,
products: {name:'',color:''},
}
],
}
And in the function:
GetAllWorkspaces: function(){
var app = this;
const instance = axios.create({
timeout: 1000,
headers: {
........
}
});
instance.get("XXXXXXX")
.then( function(response) {
console.log(response);
Object.keys(response.data.result).forEach( function (product) {
var subscribersCounter = 0;
let example = {
name: response.data.result[product].name,
id: response.data.result[product].id,
subscribers: response.data.result[product].subscribers,
products: response.data.result[product].products,
};
let uploadedExample = {
name: '',
id: '',
subscribers: '',
products: {name:'',color:''},
};
uploadedExample.name = example.name;
uploadedExample.id = example.id;
if ( example.subscribers ) {
Object.keys(example.subscribers).forEach(function (key) {
subscribersCounter++;
});
}
uploadedExample.subscribers = subscribersCounter;
if ( example.products ) {
Object.keys(example.products).forEach(function (Pkeys) {
uploadedExample.products.name = Pkeys;
Object.keys(example.products[Pkeys]).forEach(function (key) {
if (key == 'color') {
uploadedExample.products.color = example.products[Pkeys][key];
}
});
});
}
//add the new workspace to the list of workspaces.
app.Projects.push(uploadedExample);
});
})
.catch(function(error) {
console.log(error);
});
My problem is with this line
app.Projects.push(uploadedExample);
where when I try to push an object into the array, the error message is shown:
TypeError: Cannot read property 'push' of undefined
As the error says, the problem is that app.Projects is undefined. This happens because 'this' refers to the function scope inside GetAllWorkspaces and not to the component scope (you can try it by console.logging 'this' - anyway- it is a good practice under all circumstances because 'this' can change from context to context). If you want to keep the component scope inside the method, you should use an arrow function like this:
GetAllWorkspaces: () => {
// do all your stuff
}
I have the following code:
const scenarioList = []
const randomScenario = () => {
return scenarioList[Math.floor(Math.random() * scenarioList.length--)]
}
class Scenario{
setBG(){
//screen.bg = this.bg
//screen.redraw()
}
write(text, buttons, callback){
//$('#gametext > span').html(`<span>${text}</span>`)
//input.setText(buttons)
//input.bindAll(callback)
}
constructor(imgsrc, text, actions, callback){
let img = new Image()
img.src = imgsrc
this.bg = img
this.text = text
this.actions = actions
this.callback = callback
scenarioList.push(this)
console.log(scenarioList)
}
}
I init the class the following (and this is in the global scope)
new Scenario('./bg/1.png', 'You look around and see a huge mountain, what do you do?',[
'Climb It!!',
'Walk around',
'Other Direction',
'Rest',
], [
() => {
alert('a')
},
() => {
alert('a')
},
() => {
alert('a')
},
() => {
alert('a')
},
])
And verify with console.log(scenarioList)
[Scenario]
So its appended, but when I later try to do a console.log() on the same variable it is the following:
[]
Code that causes it:
const startGame = () => {
alert('were here') // this executes at the correct time, but later then variable init.
let scn = randomScenario()
console.log(scenarioList)
scn.write()
scn.setBG()
}
I am not seeing why this would happen, anyone can give me a push in the right direction?
I've found the solution, this code actually removed the element from the array:
const randomScenario = () => {
return scenarioList[Math.floor(Math.random() * scenarioList.length--)]
}
instead I did this:
return scenarioList[Math.floor(Math.random() * scenarioList.length -1)]