I have a GET request with axios and get a .png file back and want to show this inside my template. I can't use a path url, because the image is each time differently.
This is my fastapi route.
from io import BytesIO
from fastapi.responses import Response
#app.get("/image", response_class=Response)
def load_image():
...
buffer = BytesIO()
img.save(buffer, format="PNG")
return Response(content=buffer.getvalue(), media_type="image/png")
This is the vue component:
<script>
export default {
name: "Example",
data() {
return {
image: null;
};
},
methods: {
async loadImage() {
const url = "/image";
const response = await $axios.get(url, { responseType: "arraybuffer" });
if (response.status == 200) {
const base64string = btoa(String.fromCharCode(...new Uint8Array(response.data)));
console.log(base64string); // -> this is a empty string
this.image = 'data:image/png;base64,' + base64string;
}
},
mounted() {
this.loadImage();
},
};
</script>
<template>
<div>
<img :src="image" title="Image" />
</div>
</template>
You can...
get the data as a blob by passing { responseType: "blob" } to axios
convert the blob to base64 with FileReader (used blobToData function from https://stackoverflow.com/a/63372663/197546)
use the base64 data as the image src
example:
const app = Vue.createApp({
data() {
return {
imageSrc: null,
};
},
methods: {
async loadImage() {
const url =
"https://images.unsplash.com/photo-1664300067908-84e8beb52a8f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwyNXx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60";
const response = await axios.get(url, { responseType: "blob" });
if (response.status == 200) {
const base64data = await blobToData(response.data);
this.imageSrc = base64data;
}
},
},
mounted() {
this.loadImage();
},
});
app.mount("app");
function blobToData(blob) {
return new Promise((resolve) => {
const reader = new FileReader()
reader.onloadend = () => resolve(reader.result)
reader.readAsDataURL(blob)
})
}
<script src="https://unpkg.com/vue#next/dist/vue.global.prod.js"></script>
<script src="https://unpkg.com/axios#0.27.2/dist/axios.min.js"></script>
<app>
<img :src="imageSrc" v-if="imageSrc"/>
</app>
As Chris pointed out, you can also...
get the data as an array buffer by passing { responseType: "arraybuffer" } to axios
convert array to base64 data using btoa(String.fromCharCode(...new Uint8Array(response.data)))
build the src data by adding prepending the content type to the base64 data
example:
const app = Vue.createApp({
data() {
return {
imageSrc: null,
};
},
methods: {
async loadImage() {
const url =
"https://images.unsplash.com/photo-1664300067908-84e8beb52a8f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwyNXx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60";
const response = await axios.get(url, { responseType: "arraybuffer" });
if (response.status == 200) {
const b64 = btoa(String.fromCharCode(...new Uint8Array(response.data)));
const imgData = "data:" + response.headers['content-type'] + ";base64," + b64;
this.imageSrc = imgData;
}
},
},
mounted() {
this.loadImage();
},
});
app.mount("app");
<script src="https://unpkg.com/vue#next/dist/vue.global.prod.js"></script>
<script src="https://unpkg.com/axios#0.27.2/dist/axios.min.js"></script>
<app>
<img :src="imageSrc" v-if="imageSrc"/>
</app>
Related
I am trying to make bulk post with elasticsearch and axios ,
I have a problem with post request :
axios.put('http://localhost:9200/indexrandom881', {'products-bulk.json'
});
For adding and deleting index it work :
Deleting and index
axios.delete('http://localhost:9200/indexrandom'+x, {
});
Adding an index
axios.put('http://localhost:9200/indexrandom881'+x, {
});
Please do anyone has an idea.
In brief I need this command in axios form
curl -H "Content-Type: application/x-ndjson" -XPOST http://localhost:9200/products/_bulk --data-binary "#products-bulk.json"
Thanks
Thanks #Joe Sorocin but that working only in node js , I need to implement it in react , in react it shows error fs.readfile is not a function
the full essay is :
File : App.js
function App() {
const axios = require('axios');
const fs = require('fs');
const filePath = __dirname + '/national-es-bulk-index22.json';
const indexName = 'indexrandom881';
const url = `http://localhost:9200/${indexName}/_bulk`;
fs.readFile(filePath, async (err, jsonData) => {
if (err) {
console.error({ err });
return;
}
const { data } = await axios.post(url, jsonData, {
headers: {
'Content-Type': 'application/x-ndjson'
}
});
console.info({ data });
});
return (
<div className="App">
<h1>test</h1>
</div>
);
}
export default App;
Use post instead of put. Also, you'll need to first read the file using fs before you pass it along to Elasticsearch with the application/x-ndjson header:
const axios = require('axios');
const fs = require('fs');
const filePath = __dirname + '/products-bulk.json';
const indexName = 'indexrandom881';
const url = `http://localhost:9200/${indexName}/_bulk`;
fs.readFile(filePath, async (err, jsonData) => {
if (err) {
console.error({ err });
return;
}
const { data } = await axios.post(url, jsonData, {
headers: {
'Content-Type': 'application/x-ndjson'
}
});
console.info({ data });
});
After successfully deleting an item from an api, the list of items updates only after the second click on the same item.
Using fetch, vue 3 composition API and django rest api. Created an async function for both getting data from an api and deleting data from it. How can you update/ make a get request for the objects once one of the items in the list is deleted?
<template>
<div id="restTodo">
<div class="TodoContainer">
<div v-for="todo in todos" v-bind:key="todo.id" class="TodoComponent">
<div class="TodoValue">{{ todo.todo }}</div>
<div class="TodoValue">{{ todo.completion }}</div>
<button class="TodoValue" id="buttonComplete">+</button>
<button
class="TodoValue"
id="buttonDelete"
#click="removeTodo(todo.id)"
>
X
</button>
</div>
</div>
</div>
</template>
<script>
import { ref, onMounted } from "vue";
export default {
setup() {
const todos = ref([]);
const API_URL = "http://127.0.0.1:8000/api/todo-list/";
const API_DELETE = "http://127.0.0.1:8000/api/todo-delete";
async function getTodos() {
const response = await fetch(API_URL);
const json = await response.json();
todos.value = json;
}
// // // // // // // // // // // //
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== "") {
const cookies = document.cookie.split(";");
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === name + "=") {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
const csrftoken = getCookie("csrftoken");
// // // // // // // // // // // //
async function removeTodo(id) {
var csrftoken = getCookie("csrftoken");
fetch(`${API_DELETE}/${id}/`, {
method: "DELETE",
headers: {
"Content-type": "application/json",
"X-CSRFToken": csrftoken,
},
})
// .then(console.log(`deleted item ${id}`))
.then(getTodos())
}
// // // // // // // // // // // //
onMounted(() => {
getTodos();
});
// // // // // // // // // // // //
return {
todos,
removeTodo,
csrftoken,
};
},
};
</script>
Ok, changing the removeTodo function .then updates things.
async function removeTodo(id) {
var csrftoken = getCookie("csrftoken");
fetch(`${API_DELETE}/${id}/`, {
method: "DELETE",
headers: {
"Content-type": "application/json",
"X-CSRFToken": csrftoken,
},
}).then((response) => {
getTodos()
return response
})
}
i'm working in Laravel. i need to upload file with Vuejs. but it's not working. I add this code:
Blade (File upload):
<input class="form-control" type="file" >
Script Vuejs :
var app = new Vue({
el: '#app',
data: {
person: {
id: 0,
user_name:'',
position_id:'',
image:'',
},
},
methods: {
addPerson: function () {
axios.post('/addperson', this.person)
.then(response => {
console.log(response.data);
if (response.data.etat) {
this.person = {
id: 0,
user_name: response.data.etat.user_name,
position_name: response.data.etat.position_id,
image: response.data.etat.image
};
}
})
.catch(error => {
console.log('errors: ', error)
})
},
Controller:
public function addPerson(Request $request){
$person = new Person;
$person->user_name=$request->user_name;
$person->position_id=$request->position_id;
if($request->hasFile('photo')){
$person->image= $request->image->store('image');
}
$person->save();
return back()->with('success', 'New Position added successfully.');
My Axios post function is working without the image upload line code. I just don't know how to add the upload code.
Thank you if someone can help.
In your blade file
<input type="file" #change="onFileChange" name="id_image" id="id_image" class="inputFile">
In your vue.js file, under methods:
onFileChange(e) {
let files = e.target.files || e.dataTransfer.files;
if (!files.length)
return;
this.createImage(files[0]);
},
createImage(file) {
let reader = new FileReader();
reader.onload = (e) => {
this.person.image = e.target.result;
};
reader.readAsDataURL(file);
},
That should allow your axios code to upload the image. Note, that it uploads in base64, so if you need validators you will have to create a custom Validator for base64 images.
I struggled to find out how to do this, but I've now found a way. Hopefully this makes someones life easier(I have the uploadUserImage method in a mixin):
HTML:
<input type="file" #change="uploadImage($event)">
JS:
uploadImage (e) {
this.file = e.currentTarget.files[0]
let formData = new FormData()
formData.append('img', this.file)
this.uploadUserImage(formData)
}
uploadUserImage: function (formData) {
axios.post('http://snowdon-backend.local:8000/api/users/img', formData,
{
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(function (response) {
console.log(response)
})
}
Make sure file is set in the data method as well:
data () {
return {
file: ''
}
}
I've created two components to send an image in base-64 encoded format to a server. When the parent component is mounted it's supposed to set the child reference to file.
Vue.component('some-form', {
template: '#some-form',
data: function() {
return {
logoImage: '',
coverImage: ''
}
},
methods: {
onSubmit: function(event) {
var dataForm = {};
var that = this;
dataForm['logo-image'] = this.logoImage;
dataForm['cover-image'] = this.coverImage;
// AJAX REQUEST HERE with posting data
},
},
mounted: function(){
var $this = this;
// AJAX REQUEST HERE with getting data
}
});
Vue.component('upload-photo', {
template: '#upload-photo',
data: function () {
return {
image: {
body: '',
'content-type': '',
'content-length': '',
url: ''
},
imageBody: ''
}
},
props: ['logoImage', 'title', 'description'],
watch: {
'image': function() {
this.$emit('input', this.image);
}
},
created: function(){
this.image = this.logoImage;
},
mounted: function () {
var that = this;
//AJAX REQUEST HERE to get data
},
methods: {
onFileChange: function(e) {
var files = e.target.files || e.dataTransfer.files;
if (!files.length)
return;
this.createImage(files[0]);
},
createImage: function(file){
var image = new Image();
var reader = new FileReader();
var vm = this;
vm.image = {};
reader.onload = function(e) {
vm.image.body = e.target.result;
vm.imageBody = e.target.result;
};
vm.$set(vm.image, 'content-type', file.type);
vm.$set(vm.image, 'content-length', file.size);
reader.readAsDataURL(file);
},
removeImage: function (e) {
this.image = '';
}
}
});
var app = new Vue({
el: '#app',
data: function() {
},
methods: {
},
mounted: function() {
}
});
Full example https://codepen.io/anon/pen/ZvzwzO
How can it be implemented?
P.S. I have no idea how to implement it in the same component. I send data as a string with two more property, however get as a string to, however it's link.
P.S.S. need just way to search.
It is difficult to tell exactly what you are asking but it sounds like you want to pass data from the parent component to the child. If you haven't already, read about Composing components and Dynamic Props for passing properties from a parent component to a child component.
One way to do this is to make the imageBody a property of the upload-photo component instead of part of the data.
props: ['logoImage', 'title', 'description', 'imageBody'],
Then have the parent supply a value for that property:
<upload-photo v-model="logoImage" title="TITLE 1" description="description_1" v-bind:image-body="imageBody">
Take a look at this phpfiddle. When the form is mounted, it sends an AJAX call back to the server to retrieve a URL, then sets the property on that first upload-photo child element to the URL sent back from the server in the AJAX response. Note that the upload-photo template was changed to show the image if imageBody is truthy instead of image.
I'm trying to access xhttp.responseText by calling it from another component but it shows undefined. Than I tried to access it from outside xtthp.onreadystatechange. Again it shows undefined. Kindly help me. I want to access it from another Component(login.component.ts).
Here's the files.
filedata.component.ts
import { Component, OnInit } from '#angular/core';
#Component(
{
selector: "file",
templateUrl: "./filedata.component.html",
})
export class FileData
{
makeRequest(): string
{
let input;
let xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function()
{
if (this.readyState === 4 && this.status === 200)
{
// here it's good
document.getElementById("demo").innerHTML = this.responseText;
input = this.responseText;
}
};
document.getElementById("demo").innerHTML = input; //here it's undefined
xhttp.open("GET", 'http://localhost/Angular-cli/login/employees.txt', true);
xhttp.send();
return input; //I want to call it from login.component.ts
}
}
filedata.component.html
<div>
<button type = "button" (click) = "makeRequest()">File Test</button>
<p id = "demo"></p>
</div>
login.component.ts
import { Component, OnInit } from '#angular/core';
import { AdminAccount } from '../admin/admin.component';
import { Router } from "#angular/router";
import {ReactiveFormsModule, FormsModule} from "#angular/forms";
import { FileData } from "../filedata/filedata.component";
#Component(
{
selector: "login",
templateUrl: "./login.component.html"
})
export class LoginForm
{
data = {username: "", password: ""};
input = {username: "", password: ""};
constructor(private router: Router, private filedata: FileData){}
formSubmit()
{
console.log("Input file data for login:", typeof(this.filedata.makeRequest()));
if(this.filedata.makeRequest()) //here it is undefined.
{
this.input.username = this.filedata.makeRequest().split("??")[0];
this.input.password = this.filedata.makeRequest().split("??")[1];
if(this.data.username == this.input.username && this.data.password == this.input.password)
{
this.router.navigate(["/admin"]);
}
else
console.log("Wrong User or Pass");
}
else
console.log("Undefined!");
this.data.username = "";
this.data.password = "";
}
}
I want to access responseText here by calling makeRequest. Any suggestions what's going on? What should I do to access responseText here.
this.input.username = this.filedata.makeRequest().split("??")[0];
this.input.password = this.filedata.makeRequest().split("??")[1];
if(this.data.username == this.input.username && this.data.password ==
this.input.password)
{
this.router.navigate(["/admin"]);
}
UPDATED: I think you need return async function. Try like this:
makeRequest(): any {
return new Promise(resolve => {
let xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.open("GET", 'http://localhost/Angular-cli/login/employees.txt', true);
xhr.onreadystatechange = () => {if(xhr.readyState === 4 && xhr.status === 200) resolve(xhr.responseText);};
xhr.send();
});
}
then use this function:
this.filedata.makeRequest().then(res => { if(res) {/* do what u want */} })
UPDATED 2: better use requests like this:
import { Http, RequestOptions, Response, Headers} from '#angular/http';
import { Observable } from "rxjs";
constructor(private http: Http){}
functionName() {
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ withCredentials: true, headers });
return this.http.get(`your url here`, options)
.map((res: Response) => {
return res.json();
})
.catch((error: Response) => {
return Observable.throw(`error: ${error}`);
})
}
then call function in component