Vuejs binding to img src only works on component rerender - vue.js

I got a component that let's the user upload a profile picture with a preview before sending it off to cloudinary.
<template>
<div>
<div
class="image-input"
:style="{ 'background-image': `url(${person.personData.imagePreview})` } "
#click="chooseImage"
>
<span
v-if="!person.personData.imagePreview"
class="placeholder"
>
<i class="el-icon-plus avatar-uploader-icon"></i>
</span>
<input
type="file"
ref="fileInput"
#change="previewImage"
>
</div>
</div>
</template>
The methods to handle the preview:
chooseImage() {
this.$refs.fileInput.click()
},
previewImage(event) {
// Reference to the DOM input element
const input = event.target;
const files = input.files
console.log("File: ", input.files)
if (input.files && input.files[0]) {
this.person.personData.image = files[0];
const reader = new FileReader();
reader.onload = (e) => {
this.person.personData.imagePreview = e.target.result;
}
// Start the reader job - read file as a data url (base64 format)
reader.readAsDataURL(input.files[0]);
}
},
This works fine, except for when the user fetches a previous project from the DB. this.person.personData.imagePreview get's set to something like https://res.cloudinary.com/resumecloud/image/upload/.....id.jpg Then when the user wants to change his profile picture, he is able to select a new one from his local file system, and this.person.personData.imagePreview is read again as a data url with base64 format. But the preview doesn't work. Only when I change routes back and forth, the correct image selected by the user is displayed.

Like I said in the comment on my post. Turns out I'm an idiot. When displaying the preview, I used this.person.personData.imagePreview . When a user fetches a project from the DB, I just did this.person.personData = response.data. That works fine, apart from the fact that I had a different name for imagePreview on my backend. So I manually set it on the same load method when fetching from the DB like: this.person.personData.imagePreview = this.loadedPersonData.file. For some reason, that screwed with the reactivity of Vue.

Related

Svelte: how to create a Blob from `writable store`?

How can I use a "writable store" to create a "blob"?
I am new to Svelte.
I am trying to code a simple markdown editor for visually impaired users. The content of the "textarea" is stored in a "writable store" for further use:
speech-synthesis
markdown-preview
the content of an existing text file is stored in it
save text to file
But saving the text content via download to a file does not work.
<script>
let blob = new Bob([$textStore], type:"text/plain");
let url = URL.createObjectURL(blob);
</script>
<button>
<a href={url} download="untitled.md" id="link">Download
</a>
</button>
An empty file is saved or it has the content "[object Object]", when I use curley brackets:
let blob = new Blob ([{$textStore}], {type: 'text/plain'});
File for testing:
// TextStore.js
import { writable } from "svelte/store";
export const textStore = writable('');
<!-- EditorTest.svelte -->
<script>
import { textStore } from "./TextStore.js";
let blob = new Blob ([{$textStore}], {type: 'text/plain'});
let url = URL.createObjectURL(blob);
</script>
<h1>Blob-Test</h1>
<textarea bind:value={$textStore} cols="20" rows="5"></textarea>
<hr>
<pre>{$textStore}</pre>
<br>
<button>
Save
</button>
Can someone help, thanks a lot already.
The main issue is, that the code is not reacting to the changes. The Blob is created once at the beginning, when the store is still empty. You could make it reactive using $:, but that is not a great idea, as it unnecessarily re-creates the Blob over and over.
I would recommend using a click handler on the button (the link inside it is invalid HTML anyway), and then creating the Blob there:
<button on:click={onDownload}>
Save
</button>
function onDownload() {
const blob = new Blob([$textStore], {type: 'text/plain'});
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.download = 'file.md';
link.href = url;
link.click();
URL.revokeObjectURL(url); // Object URLs should be revoked after use
}

variable in data property are updated to unexpected value in Vue.js2.6

I have two input tags for uploading images and tow variables(imgFile1,imgFile2) in data section . I'm sure imgFile1 gets correct value on my console but when I upload second image, this images's value goes to wrong variable. The images d57f0.... in the picture below supposes to be in imgFile2. Why does it happen ?? Thank you so much .
html
<div class="img-field-container1">
upload img
<input type="file" class="input-img-field1" #change="uploadFile" accept="image/*" ref="img1">
</div>
<div class="img-field-container2">
upload img
<input type="file" class="input-img-field2" #change="uploadFile" accept="image/*" ref="img2">
</div>
data () {
return {
imgFile1:'',
imgFile2:'',
}
methods: {
uploadFile: function () {
var img_file1 = this.$refs.img1.files[0]
this.imgFile1 = URL.createObjectURL(img_file1)
console.log(imgFile1)→ correct value in console
var img_file2 = this.$refs.img2.files[0]
this.imgFile2 = URL.createObjectURL(img_file2)
console.log(imgFile2)→ correct value in console but updated into imgFile1
}
I solved problem by wrapping correctly

Element is undefined because it is not rendered yet. How to wait for it?

In my Vue app I have an image element with a bound src. this code is in a stepper. In one step the user selects a picture to upload an in the next step the image gets shown (which works as intended). However I am trying to initiate a library on the element in the next step (the Taggd library) but the element seems to be undefined.
I tried the nextTick() to wait for the image to load but without luck.
the image element:
<div class="orientation-landscape">
<div class="justify-center q-px-lg">
<img v-if="photo.url" :src="photo.url" id="workingPhoto"
style="width: 80vw;" ref="workingPhoto"/>
</div>
</div>
The functions. I first use uploadFile to set the url of the image element and go to the next step where the image will be loaded. then I call initTaggd() on the nextTick however that fails because the element is undefined.
uploadFile(file) {
const self = this;
self.photo.file = file;
self.setPhotoUrl(file);
self.$refs.stepper2.next();
console.log('We should be at next step now. doing the init');
self.nextTick(self.initTaggd());
},
setPhotoUrl(file) {
const self = this;
self.photo.url = URL.createObjectURL(file);
console.log('ping1');
},
initTaggd() {
const self = this;
const image = document.getElementById('workingPhoto');
console.log('image:', image); //THIS RETURNS UNDEFINED
console.log('Trying ANOTHER element by refs:', self.$refs.stepper2); // This returns the element
console.log('trying the real element by reference', self.$refs.workingPhoto); // Returns undefined again
const taggd = new Taggd(image); //All this here fails because image is undefined.
console.log('ping2.5');
taggd.setTags([
self.createTag(),
self.createTag(),
self.createTag(),
]);
console.log('ping3');
},
I think I am looking for a way to wait for the image to fully load before calling initTaggd() but I am lost on how to achieve this.
You could listen for the load event:
<img
v-if="photo.url"
id="workingPhoto"
ref="workingPhoto"
:src="photo.url"
style="width: 80vw;"
#load="initTaggd"
/>

Storing Image to remote server using Http Adapter

I want to display Image and store Image on remote server.I am using Ibm Worklight Version 6.2.I Have gone through many links but didn't find the solution
My HTML Page code is
<fieldset style="height:auto;width:100% ">
<div id="Image" style="float:left;">
</div>
<div id ="delImage">
</div>
</fieldset>
and my Js Code is
uploadImage = function (){
navigator.camera.getPicture(onSuccessCallBack, onFailCallBack, {
quality: 50,
sourceType: Camera.PictureSourceType.CAMERA,
destinationType: Camera.DestinationType.FILE_URI
});
};
function onSuccessCallBack (imageData){
var img = document.createElement("img");
img.style.width = "60px";
img.style.height="60px";
img.src = imageData;
var Image = document.getElementById("Image");
Image.appendChild(img);
var delImg = document.createElement("img");
delImg.style.width = "60px";
delImg.style.height="60px";
delImg.src = "images/brws_gal.png";
var deleteImg = document.getElementById("delImage");
deleteImg.appendChild(delImg);
var invocationData = {
adapter : 'DisbursalRequestImageAdapter',
procedure : "uploadImageForDisbursal",
parameters : [ requestObject, sessionId, operationFlag,'','' ]
};
var options = {
timeout : timeout,
onSuccess : successCreateImg,
onFailure : failureCreateImg
};
WL.Client.invokeProcedure(invocationData, options);
};
Here, I am appending Dynamic Image in a div.
My Question is
I want to store the image to remote server using Http Adapter
I want to open the picture on the click of Picture.
I am not arrange the div vertically i.e. every time the photo is taken a new div should be created.
If you want to send an image to a remote server, you need to base64 encode the image and then send this string to be stored in the remote server's database.
If you want to then retrieve it you need to get the string and then decode the base64 string back to an image filetype and display the image in your HTML (the image should be stored in the device storage using Cordova APIs as you have demonstrated use of).
In fact, had you searched, the above is what you would've found in searches.

Google Script for Uploading File Not Working

I wrote a script for uploading files to my Google Drive using the Google Script. I deployed it as a WebApp but it's not working and I don't know why. The button just gets stuck on "Subiendo..." and never changes anything inside my Drive. I'm sure I gave the script all the permissions and I already tried to see what's happening on my own without any sucess. Can you maybe help me find what should I do? I post the code here:
Code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile('main').setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function serverFunc(theForm) {
try{
var folder_name = "publicaciones";
var folder,folders = DriveApp.getFoldersByName(folder_name);
if(folders.hasNext()){
folder = folders.next();
}else{
folder = DriveApp.createFolder(folder_name);
}
Logger.log("TheForm", theForm == null);
var blob = theForm.theFile;
Logger.log("Blob!", blob == null);
var file = folder.createFile(blob);
Logger.log("File:", file.getName());
return "Archivo subido exitosamente: " + file.getUrl();
} catch(error){
Logger.log("error: ", error.toString());
return error.toString();
}
}
** main.html **
<div>
<form id="myForm">
<input type="file" name="theFile">
<input type="hidden" name="anExample">
<br>
<input type="button" value="Subir Archivo" onclick="this.value='Subiendo...';
google.script.run.withSuccessHandler(fileUploaded).serverFunc(this.parentNode);
return false;">
</form>
</div>
<div id="output">
</div>
<script>
function fileUploaded(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('output').innerHTML = status;
}
</script>
I'd appreaciate any help or pointers you can give me. Thanks a lot!
Looks like there is a bug currently that Google is working on. I found a possible fix:
Change your input tag to this:
<input type="button" value="Subir Archivo" onclick="callServerCode()"/>
Add a function to the <script> tag:
<script>
function callServerCode() {
var formToSend = document.getElementById('myForm');
google.script.run
.withSuccessHandler(fileUploaded)
.serverFunc(formToSend);
};
function fileUploaded(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('output').innerHTML = status;
}
</script>
Note that inside the new function, it gets the form using var formToSend = document.getElementById('myForm');
And change IFRAME to NATIVE.
It's a doc issue needs to fix with Google when using SandBoxMode=IFRAME currently. See here. I've tested it works by swapping IFRAME to NATIVE. You can simply do it:
function doGet() {
return HtmlService.createHtmlOutputFromFile('main');
}
Google has turned of NATIVE for SandBoxMode. It is now set to IFRAME only.
See here