FilePond upload error using Validate Size plugin? - vue.js

I'm using the Vue-FilePond library to upload user avatars, and am trying to implement a max-file-size. For testing purposes, I've set it to 1MB. When I try uploading anything larger than 1MB, I receive an error:
TypeError: Cannot read property 'data' of undefined
This happens in my addFile method where I attempt to use the method getFileENcodeDataURL(), so that I can send it along to my GraphQL server. Does anybody have any suggestions for how to fix this?
<template>
<file-pond
ref="filepondUploader"
accepted-file-types="image/jpeg, image/png"
:allow-multiple="false"
:instant-upload="false"
max-file-size="1MB"
name="avatar"
#addfile="addFile"
#removefile="removeFile" />
</template>
<script>
import vueFilePond, { setOptions } from 'vue-filepond';
import FilePondPluginFileValidateType from 'filepond-plugin-file-validate-type';
import FilePondPluginFileValidateSize from 'filepond-plugin-file-validate-size';
import FilePondPluginImagePreview from 'filepond-plugin-image-preview';
import FilePondPluginFileEncode from 'filepond-plugin-file-encode';
import 'filepond/dist/filepond.min.css';
import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.min.css';
const FilePond = vueFilePond(
FilePondPluginFileValidateType,
FilePondPluginFileValidateSize,
FilePondPluginImagePreview,
FilePondPluginFileEncode
);
setOptions({
labelIdle: 'Drag & Drop your picture<br/>or <span class="filepond--label-action">Browse</span>',
imagePreviewHeight: 170,
imageCropAspectRatio: '1:1',
imageResizeTargetWidth: 200,
imageResizeTargetHeight: 200,
stylePanelLayout: 'compact circle',
styleLoadIndicatorPosition: 'center bottom',
styleButtonRemoveItemPosition: 'center bottom'
});
export default {
methods: {
addFile () {
const initial = this.$refs.filepondUploader.getFile(0);
const file = initial.getFileEncodeDataURL(); <--- where error occurs
this.$emit('handle-image-upload', file);
}
}
}
</script>

I found a simple fix for this issue when I was looking through the docs, specifically this part that discusses the methods. In the addFile method, I realized that it passes an event which contains the error if a file is too large. If the file is not too large, the event is null. So I simply do a check, remove the file and return before it gets to the point that it was causing me issues, like so:
addFile (e) {
if (e) {
this.error = e;
this.$refs.filepondUploader.removeFile();
return;
}
const initial = this.$refs.filepondUploader.getFile(0);
const file = initial.getFileEncodeDataURL();
this.$emit('handle-image-upload', file);
}

Related

What is the proper way to set BPM in Tone.js

I have tried simply setting Tone.Transport.bpm but it is ignored. My content just plays at the default 120 BPM. I then looked at some of the docs and it implies you can pass parameters to a constructor to make a Transport with custom parameters. However when I try this is tells me Transport is not a constructor, which I guess it isn't in v14 :/
I am using v14 / Ubuntu / Version 104.0.5112.79 (Official Build) (64-bit) in the latest React.
Here is my code, it is very close to their official example code. The interesting (and confusing!) thing is un-commenting the rampTo line does change the tempo, but over the course of 200ms. Setting this value too low causes an error and I don't want the Tempo to shift once playback is started. I want it to start at a set tempo from sample 0...
import React, {useState} from 'react'
import * as Tone from 'tone'
function App() {
const [toneStarted, setToneStarted] = useState(false)
const [playing, setPlaying] = useState(false)
const [setup, setSetup] = useState(false)
async function goHandler(event) {
if(!toneStarted) await Tone.start()
setToneStarted(true)
setPlaying(!playing)
if(playing) return Tone.Transport.stop()
if(!setup){
var kick = new Tone.Player("/samples/Kicks/003.WAV").toDestination()
var snare = new Tone.Player("/samples/Snares/003.WAV").toDestination()
await Tone.loaded()
// play a note every quarter-note
new Tone.Loop(time => {
kick.start(time)
}, "4n").start(0)
// play another note every off quarter-note, by starting it "8n"
new Tone.Loop(time => {
snare.start(time)
}, "4n").start("8n")
// Tone.Transport.bpm.rampTo(50, 0.2);
setSetup(true)
}
Tone.Transport.bmp = 50;
Tone.Transport.start()
}
return (
<div className="App">
<header className="App-header">
<button onClick={goHandler}>{playing ? "STOP" : "PLAY"}</button>
</header>
</div>
);
}
export default App;
You have to use the .value notation at the end:
Tone.Transport.bpm.value = 50
and you got a wrong typo = bpm instead of bmp

how can a Buefy toast be made available to all components in a Vue app?

In a component in a Vue app the following method runs after a user clicks a Submit button on a form:
execute() {
let message = '';
let type = '';
const response = this.actionMode == 'create' ? this.createResource() : this.updateResource(this.data.accountId);
response.then(() => {
message = 'Account ' + this.actionMode + 'd for ' + this.data.name;
type = 'is-success';
})
.catch(e => {
message = 'Account <i>NOT</i> ' + this.actionMode + 'd<br>' + e.message;
type = 'is-danger';
})
.then(() => {
this.displayOutcome(message, type);
this.closeModal();
});
}
The displayOutcome() method in that same component looks like this:
displayOutcome(message, type) {
this.$buefy.toast.open({
duration: type == 'is-danger' ? 10000 : 3500,
position: 'is-bottom',
message: message,
type: type
});
}
The code is working fine within the component. Now I'm trying to move the displayOutcome() method into a helpers.js file and export that function so any component in the app can import it. This would centralize maintenance of the toast and prevent writing individual toasts within each component that needs one. Anyhow, when displayOutcome() gets moved over to helpers.js, then imported into the component an error appears in the console when the function is triggered:
I suspect it has to do with referring to the Vue instance so I experimented with the main.js file and changed this
new Vue({
router,
render: h => h(App),
}).$mount('#app');
to this
var vm = new Vue({
router,
render: h => h(App),
}).$mount('#app');
then in helpers.js
export function displayOutcome(message, type) {
// this.$buefy.toast.open({
vm.$buefy.toast.open({
duration: type == 'is-danger' ? 10000 : 3500,
position: 'is-bottom',
message: message,
type: type
});
}
but that resulted in a "Failed to compile." error message.
Is it possible to make displayOutcome() in helpers.js work somehow?
displayOutcome() requres a reference to this to work, which is fine if you define it as a method on your component object (the standard way). When you define it externally however, you just supply any function instead of a method, which is a function "targeted" on an object. This "targeting" is done through this. So when you're passing a simple function from an external file, there's no association to a specific object, and thus no this available.
To overcome this, you can use displayOutcome.apply(thisArg, methodArgs), where thisArg will be whatever is the this reference in your function, and methodArgs are the remaining arguments that are being passed to the function.
So displayOutcome.apply(4, ['some', 'thing']) would imply that the this reference in displayOutcome() becomes 4 in this case.
Further reading:
Understanding "This" in JavaScript
this on MDN
import { displayOutcome } from './component-utils'
// when calling displayOutcome() from within your component
displayOutcome.apply(this, ['Hello World', 'is-info'])
// component-utils.js
export function displayOutcome(message, type) {
// this.$buefy.toast.open({
this.$buefy.toast.open({
duration: type == 'is-danger' ? 10000 : 3500,
position: 'is-bottom',
message: message,
type: type
});
}
You can create an action in Vuex store and dispatch it from any component.

Unable to set focus to a textarea, when the page loads

I am trying to set the focus on a syncfusion textarea but I am unable to do so. I have used the this.$nextTick when the component mounts as defined here but the system still does not focus on the textarea.
I have added the same "focus to textarea" code in the created event because somehow the created event is triggered after the mounted event.
I have re-created the issue here.
I also see that this.$refs.vocabularies.$el returns input#vocabularies.e-control.e-textbox.e-lib.
What am I doing wrong?
<template>
<ejs-textbox cssClass="height:500px;" id='vocabularies' :multiline="true" placeholder="Enter your vocabularies" floatLabelType="Auto" :input= "inputHandler" v-model="vocabularies" ref="vocabularies"/>
</template>
<script>
import '#syncfusion/ej2-base/styles/material.css';
import '#syncfusion/ej2-vue-inputs/styles/material.css';
export default
{
data() {
return {
vocabularies: '',
inputHandler: (args) =>
{
args.event.currentTarget.style.height = "auto";
args.event.currentTarget.style.height = (args.event.currentTarget.scrollHeight)+"px";
},
}
},
mounted()
{
this.$nextTick(function()
{
this.$refs.vocabularies.$el.style.height = "auto";
this.$refs.vocabularies.$el.style.height = (this.$refs.vocabularies.$el.scrollHeight)+"px";
this.$refs.vocabularies.$el.focus();
console.log(`mounted run`);
});
},
async created()
{
this.$nextTick(function()
{
this.$refs.vocabularies.$el.style.height = "auto";
this.$refs.vocabularies.$el.style.height = (this.$refs.vocabularies.$el.scrollHeight)+"px";
this.$refs.vocabularies.$el.focus();
console.log(`created run`);
});
},
</script>
So, here's how I've solved it. I am not so sure regarding how good of an approach this is as I haven't worked with syncfusion, so can't say if there might be a better way.
<ejs-textbox cssClass="test" id='vocabularies' :multiline="true" placeholder="Enter your vocabularies" floatLabelType="Auto" :input= "inputHandler" v-model="vocabularies" ref="vocabularies"/>
Then in mounted I did
mounted() {
let a = document.getElementsByClassName('test')[0];
a.children[1].focus();
}
I was able to fix the issue by using this.$refs.vocabularies.focusIn(); in the mounted() method, based on the documentation here
You can focus the text area by using the focusIn public method of the TextBox component in the created event. Kindly refer the below code,
<ejs-textbox cssClass="height:500px;" id='vocabularies' :multiline="true" placeholder="Enter your vocabularies" floatLabelType="Auto" :input= "inputHandler" v-model="vocabularies" ref="vocabularies" :created='onCreated' />
onCreated:function(){
this.$refs.vocabularies.ej2Instances.focusIn()
}
Please find the sample from the below link,
Sample Link:
https://www.syncfusion.com/downloads/support/directtrac/general/ze/quickstart1111977605

vuejs router.go(-1) not showing on second time

I'm currently using vue-router to manage the differents Vue of my project.
My main.js
import Vue from 'vue'
import App from './App.vue'
import jQuery from 'jquery'
import 'bootstrap'
import 'bootstrap/dist/css/bootstrap.css'
global.jQuery = jQuery
global.$ = jQuery
import './assets/css/animate.css'
import router from './router'
import store from './vuex'
Vue.config.productionTip = false
new Vue({
store,
router,
render: h => h(App)
}).$mount('#app')
When I'm on my dashboard ('/dashboard') for the first time, the 'created' methods is called. Data are retrieved from the API and shows up in my array.
After that I click on one element of my array that route me to '/details/:id' (with id the id of my element). Everything works well and then I click on a 'Go back' button.
I finish again on my dashboard page, i see that the 'create' methods is called again, data are well retrived from the API but nothing shows up and my array stays empty.
I really don't understand why.
There is the code of the the 'created' function:
export default {
created: function() {
console.log('created => dashboard');
let store = this.$store;
let q = this.rows;
//get rows
if (store.state.socket.io._callbacks["$rows"] == undefined) {
console.log("Binding rows");
//Where I receive the rows from API
store.state.socket.io.on("rows", data => {
console.log("rows reponse:", data);
if (data.success) {
this.nbrItems = data.rows.length;
q.splice(0, q.length); //Clean the array without replacing the instance
data.rows.map(a => q.push(a));
console.log("Queue length: " + q.length);
}
});
}
//get the queue
this.refresh(); // This send a request to the API to ask it to send us back the datas
},
And I use this.$router.go(-1) to navigate back on the '/dashboard' page.
Edit: Is there a problem of state or something like that? I do not understand why, because in-memory I can access to all data, there is just no more binding anymore...
Do you pop every element of the array before you call the created function?
I'm still an apprentice but it seems to me like you have to pop everything before adding new elements to the array.
I figure it out:
The problem was coming from socket.io. I'm checking if the event is bind already before to subscribe to a function and this function contains 'this' that was still referring to the previous Vue instance.
Simply fixed by replacing this:
//get rows
if (store.state.socket.io._callbacks["$rows"] == undefined) {
console.log("Binding rows");
//Where I receive the rows from API
store.state.socket.io.on("rows", data => {
console.log("rows reponse:", data);
if (data.success) {
this.nbrItems = data.rows.length;
q.splice(0, q.length); //Clean the array without replacing the instance
data.rows.map(a => q.push(a));
console.log("Queue length: " + q.length);
}
});
}
by this:
if (store.state.socket.io._callbacks["$rows"] != undefined) {
store.state.socket.io.off("rows");
}
console.log("Binding rows");
store.state.socket.io.on("rows", data => {
console.log("rows reponse:", data);
if (data.success) {
this.nbrItems = data.rows.length;
q.splice(0, q.length);
data.rows.map(a => q.push(a));
console.log("Queue length: " + q.length);
}
});
But this makes me wonder, if I can still access to a previous Vue instance is it meaning that it will be some kind of memory leak with time?
I suppose that no with the garbage collector but would mean that nothing else refers to the previous instance.

Vue.js - Highmaps - Redraw map on series change

I have a highmaps 'chart' and the only thing that I want is to redraw the whole map inside an external function. Let me explain better. The map draws itself immediatly when the page loads up but I fetch some data from an external service and set it to a variable. Then I would like to just redraw the chart so that the new data appears in the map itself. Below is my code.
<template>
<div>
<highmaps :options="chartOptions"></highmaps>
</div>
</template>
<script>
import axios from 'axios';
import HighCharts from 'vue-highcharts';
import json from '../map.json'
let regions = [];
export default {
data: function () {
return {
chartOptions: {
chart: {
map: json, // The map data is taken from the .json file imported above
},
map: {
/* hc-a2 is the specific code used, you can find all codes in the map.json file */
joinBy: ['hc-key', 'code'],
allAreas: false,
tooltip: {
headerFormat: '',
pointFormat: '{point.name}: <b>{series.name}</b>'
},
series: [
{
borderColor: '#a0451c',
cursor: 'pointer',
name: 'ERROR',
color: "red",
data: regions.map(function (code) {
return {code: code};
}),
}
],
}
},
created: function(){
let app = this;
/* Ajax call to get all parameters from database */
axios.get('http://localhost:8080/devices')
.then(function (response) {
region.push(response.parameter)
/* I would like to redraw the chart right here */
}).catch(function (error){
console.error("Download Devices ERROR: " + error);
})
}
}
</script>
As you can see I import my map and the regions variable is set to an empty array. Doing this results in the map having only the borders and no region is colored in red. After that there is the created:function() function that is used to make the ajax call and retrieve data. After that I just save the data pushing it into the array and then obviously nothing happens but I would like to redraw the map so that the newly imported data will be shown. Down here is the image of what I would like to create.
If you have any idea on how to implement a thing like this or just want to suggest a better way of handling the problem, please comment.
Thanks in advance for the help. Cheers!
After a few days without any answer I found some marginal help online and came to a pretty satisfying conclusion on this problem so I hope it can help someone else.
So the first thing I did was to understand how created and mounted were different in Vue.js. I used the keyword created at first when working on this project. Because of that, inside this function, I placed my ajax call that gave me data which I then loaded inside the 'chart' by using the .addSeries method of the chart itself.
To reference the chart itself I used this: let chart: this.$refs.highcharts.chart. This searches for the field refs in any of your components/html elements and links it to the variable. So in the html there was something like this:
<template>
<div>
<highmaps :options="chartOptions" ref="highcharts"></highmaps>
</div>
</template>
The real problem was that the chart didn't even start rendering while all this process was going on so I changed the created keyword with mounted which means that it executes all the code when all of the components are correctly mounted and so my chart would be already rendered.
To give you (maybe) a better idea of what I am talking about I will post some code down below
mounted: function(){
let errorRegions = [];
let chart = this.$refs.highcharts.chart;
axios.get('localhost:8080/foo').then(function(response)
{
/* Code to work on data */
response.forEach(function(device){
errorRegions.push(device);
}
chart.addSeries({
name: "ERROR",
color: "red",
data: errorRegions
}
/* ...Some more code... */
})
}
And this is the result (have been adding some more series in the same exact manner)
Really hoping I have been of help to someone else. Cheers!