Vue / Vuetify - this.$refs.form.reset() error in file input - vue.js

I was using this.$refs.form.reset() for my modal and all the fields are cleared not until I used the v-file-input field. The error produces Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'.
If I manually set the the value of the v-file-input into null, everything is working fine. How do I retain using this.$refs.form.reset() without this error?
<v-file-input
v-model="tableItem.photo"
accept="image/png, image/jpeg, image/bmp"
placeholder="Pick an avatar"
prepend-icon="mdi-camera"
label="Avatar"
#change="getImagePreviews()"
></v-file-input>
getImagePreviews() {
let reader = new FileReader();
reader.addEventListener("load", () => {
this.imageURL = reader.result
})
reader.readAsDataURL(this.tableItem.photo)
},
closeModal() {
this.tableItem.photo = null // this is working but I need to remove this.$refs.form.reset()
this.$refs.form.reset()
this.$refs.form.resetValidation()
}

Since the readAsDataURL() function accepts only Blob data, you can check if the parameter is of Blob type:
getImagePreviews() {
if (this.tableItem.photo instanceof Blob){
this.reader.readAsDataURL(this.tableItem.photo)
}else{
this.imageURL = null
}
},
Also, you may want to initialize the reader in the mounted hook:
data: ()=>({
reader: null
}),
mounted(){
this.reader = new FileReader();
this.reader.addEventListener("load", () => {
this.imageURL = this.reader.result
})
}

Related

How to convert image from file input to base64 url in vue?

I have tried to convert an image from file input in vue, I'm not so sure I did it in the proper way.
What I want to achieve is to get the Image url, assign it to a data variable and push it into my mongoose DB
That's what I tried based on a guide I read:
Input:
<div class="singleInput50">
<span>Personal Image:</span>
<input type="file" #change="handleImage" accept="image/*">
</div>
HandleImage:
handleImage(e) {
const selectedImage = e.target.files[0];
this.createBase64Image(selectedImage);
},
createBase64Image:
createBase64Image(fileObject) {
const reader = new FileReader();
reader.onload = (e) => {
this.userObject.imgPersonal = e.target.result;
};
reader.readAsBinaryString(fileObject)
console.log("file object", fileObject);
}
ImgPersonal value after the functions has been executed:
imgPersonal:"ÿØÿàJFIFÿÛC\n \n \n$ &%# #"(-90(*6+"#2D26;=###&0FKE>J9?#=ÿÛC =)#)==================================================ÿÀ"ÿÄ \nÿĵ}!1AQa"q2¡#B±ÁRÑð$3br \n%&'()*456789:CDEFGH
I have tried also with readAsDataURL(), seems like the same outcome
Any suggestions?
I'm using this function to convert files to base64. Works fine for me:
export default function (blob) {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onerror = reject
reader.onload = () => {
resolve(reader.result)
}
reader.readAsDataURL(blob)
})
}

Using dropzone.js in vue, calling function with image file name

I'm having a hard time getting anything to work with this the way I need it, but I have a working dropzone instance in my Vue project.
I can upload the image and call functions within the dropzone code, however, I need to call a function directly from the form in the html in order to send the 'card' object.
All I need to do is call a function when a file is added through the dropzone form, with the filename.
My code:
<div class="uk-width-3-10">
<form v-on:change="imageChange(card)" method="post" action="{{url('product/parts/upload/store')}}" enctype="multipart/form-data"
class="dropzone" v-bind:id="'dropzone-'+i">
</form>
</div>
...
imageChange(Card){
console.log('working');
},
addCard(){
Vue.nextTick(function () {
new Dropzone("#dropzone-"+cardIndex, {
maxFilesize: 12,
renameFile: function (file) {
var dt = new Date();
var time = dt.getTime();
return time + file.name;
},
acceptedFiles: ".jpeg,.jpg,.png,.gif",
addRemoveLinks: true,
timeout: 50000,
removedfile: function (file) {
console.log(file.upload.filename);
var name = file.upload.filename;
var fileRef;
return (fileRef = file.previewElement) != null ?
fileRef.parentNode.removeChild(file.previewElement) : void 0;
},
init: function() {
this.on("addedfile",
function(file) {
instance.imageZoneNames.push({name: file.upload.filename});
console.log(file);
console.log(instance.imageZoneNames);
});
}
});
});
}
Dropzone has many events, You used removedfile() event! there is another event called addedfile() and executes when a file is added to the dropzone list
imageChange(card) {
console.log(card)
},
addCard() {
Vue.nextTick(() => {
new Dropzone('#dropzone-` + cardIndex, {
addedfile(file) {
this.imageChange(file);
}
}
}
}

Markers are not shown on leaflet map

I am working on a task in which I have to show coordinates from an API.
Currently i am successfully able to fetch the data. But when I show it on the Map, Markers are not visible.
When i look in console the following errors appears:-
Uncaught (in promise) TypeError: Cannot read property 'data' of undefined at eval
I have individually tried to pin point the source of error by putting console.log("done") at regular intervals and the exception occurs after the following line in my code:
this.map.addLayer(this.markers);
I have marked this line using comment in my code.
here's what i put in my html
<div id="mapApp">
<div class="container-fluid" style="padding: 0px; position:
relative; min-height: 90vh">
<div id="map" class="map"></div>
</div>
</div>
here's my Full JavaScript File
import Vue from 'vue'
import axios from 'axios'
import L from 'leaflet'
import googleMutant from 'leaflet.gridlayer.googlemutant'
import markercluster from 'leaflet.markercluster'
const baseUrl = 'http://127.0.0.1:8000/';
const vm = new Vue({
el: '#mapApp',
data: {
map: null,
tileLayer: null,
layers: [],
properties: [],
panState: 'closed',
foodIconUnselected: null,
foodIconSelected:null,
realEstateIconUnselected:null,
realEstateIconSelected:null,
zoomlevel:8,
firstLatitude:null,
firstLongitude:null,
roadMutant:null,
markers:null,
allPropertyLayer:null,
mcdPropertyLayer:null,
subwayPropertyLayer:null,
burgerkingPropertyLayer:null,
chickeriaPropertyLayer:null,
starbucksPropertyLayer:null,
kfcPropertyLayer:null,
spettacoloPropertyLayer:null,
holycowPropertyLayer:null,
query:'',
iconLabel:null,
labelName:null,
},
created(){
// execute the method to fetch propertis
let searchParams = new URLSearchParams(window.location.search);
let search_term_value = searchParams.get("search_term")
this.fetchPropertyData(search_term_value);
},
methods: {
initMap() {
this.$data.map = L.map('map').setView([this.$data.firstLatitude, this.$data.firstLongitude], this.$data.zoomlevel);
this.$data.roadMutant = L.gridLayer.googleMutant({
maxZoom: 24,
type: 'roadmap',
styles: /*removed on purpose to reduce size */,
}).addTo(this.$data.map);
L.control.zoom({
position:'topright'
}).addTo(this.$data.map);
this.$data.markers = L.markerClusterGroup({
iconCreateFunction: function (cluster) {
var markers = cluster.getAllChildMarkers();
var html = '<div class="marker-cluster">' + markers.length + '</div>';
return L.divIcon({html: html, className: 'mycluster', iconSize: L.point(40, 40)});
},
spiderfyOnMaxZoom: false, showCoverageOnHover: false, zoomToBoundsOnClick: true,
});
this.$data.allPropertyLayer = new L.FeatureGroup();
this.$data.mcdPropertyLayer = new L.FeatureGroup();
this.$data.subwayPropertyLayer = new L.FeatureGroup();
this.$data.burgerkingPropertyLayer = new L.FeatureGroup();
this.$data.chickeriaPropertyLayer = new L.FeatureGroup();
this.$data.starbucksPropertyLayer = new L.FeatureGroup();
this.$data.kfcPropertyLayer = new L.FeatureGroup();
this.$data.spettacoloPropertyLayer = new L.FeatureGroup();
this.$data.holycowPropertyLayer = new L.FeatureGroup();
console.log("Done Till Here");
this.fillDataInMap();
},
fillFirstData(){
this.$data.firstLatitude = this.$data.properties[0].latitude;
this.$data.firstLongitude = this.$data.properties[0].longitude;
},
fetchPropertyData(search_term_value){
const self = this;
axios.get(baseUrl + 'api/search/property', {
params:{
'search_term': search_term_value
}
}).then(function (response) {
self.$data.properties = response.data.search_results.data;
self.fillFirstData();
self.initMap();
}).catch(function (error) {
alert(error.response.data);
console.log(error);
})
},
fillDataInMap(){
for(let i =0;i<this.$data.properties.length;i++){
this.$data.iconLabel = this.getPropertyIconLabelUnSelected(this.$data.properties[i]);
this.$data.labelName = this.getPropertyLabelName(this.$data.properties[i]);
let marker = L.marker(new L.LatLng(this.$data.properties[i].latitude, this.$data.properties[i].longitude), {icon: this.$data.iconlabel, id: i+1});
marker.bindTooltip(this.$data.labelName, {permanent: true, direction: 'auto', className: 'map-icon-label',});
marker.bindPopup(this.$data.properties[i].address);
marker.title = this.$data.properties[i].id;
marker.on('click', function (e) {
//showDetails(e, e.target.title);
//changeMarkerIconOnClick(e);
});
marker.on('mouseover',function (e) {
e.target.openPopup();
});
marker.on('mouseout',function (e) {
e.target.closePopup();
});
this.$data.allPropertyLayer.addLayer(marker);
this.addMarkerToRespectiveLayer(this.$data.properties[i].property_sub_type,marker);
}
this.$data.markers.addLayer(this.$data.allPropertyLayer);
Next line throws the exception
this.map.addLayer(this.markers);
},
searchWithQuery(){
this.fetchPropertyData(this.$data.query)
},
showPropertyDetails(id) {
alert('property id is: ' + id)
},
}
});
I found the reason why it was causing exception. I declared variable for custom markers but somehow forgot to initialise them. After removing the Custom markers, markers show on the map but then i am unable to interact with map. It remains static like an image.

Vuejs. I can't transfer data to an Object

I would like to catch uploaded file in FilePond. but the base64 of the file isn't transfered to my object. Any solutions?
In template
<FilePond
v-on:addfile="catch"
/>
In Data
data:function() {
return {
image:'',
}}
in Method
catch: function(fieldName, file) {
console.log('#', file.file) // The Blop format file appears in console
const reader = new FileReader(); //convert to base64
reader.readAsDataURL(file.file);
reader.onloadend = function() {
console.log('yy',reader.result); // Base64 image appears in console
(600000 carac)
this.image= reader.result ; // HERE, the object still blank
} },
Error in console :
Uncaught TypeError: Cannot set property 'image' of undefined
at FileReader.reader.onloadend
this keyword is shadowed by the onloadend function, save this before defining the function and then reference it inside:
methods: {
catch: function(fieldName, file) {
// ...
var ref = this
reader.onloadend = function() {
ref.image= reader.result // use ref here
}
// ...
}
}

Getting reactivity from watch in Vue.js

Trying to make a component in Vue.js, which first shows image via thumbnail, loading full image in background, and when loaded, show full image.
The thing which does not work, component does not react on change of showThumb flag in watch section. What is wrong?
Vue.component('page-image',
{
props: ['data'],
template:
'<img v-if="showThumb == true" v-bind:src="thumbSrc"></img>'+
'<img v-else v-bind:src="fullSrc"></img>',
data: function()
{
return { thumbSrc: '', fullSrc: '', showThumb: true };
},
watch:
{
data: function()
{
this.thumbSrc = data.thumbImg.url;
this.fullSrc = data.fullImg.url;
this.showThumb = true;
var imgElement = new Image();
imgElement.src = this.fullSrc;
imgElement.onload = (function()
{
this.showThumb = false; // <<-- this part is broken
} );
}
}
} );
Note: there is a reason why I do it via 2 img tags - this example is simplified.
Your onload callback will have a different scope than the surrounding watch function, so you cannot set your data property like this. Change it to an arrow function to keep scope:
imgElement.onload = () =>
{
this.showThumb = false;
};
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions