Is there a special way to upload url images to firebase? - firebase

Blockquote
I'm building my app in Nuxt and Vuetify and I want to upload url images to Firebase with Axios using inputs (v-file-input). I have no problems with names but when I upload an url image and when I make the get call the response is just the url link, not the picture. So, is there any particular way to upload url pictures?
Is not as simple as any other input?
Thanks in advance.
<template>
<div>
<v-app>
<v-container>
<h2>Movies</h2>
<ul>
<li v-for="movi in moviesData" :key="movi.id">
{{movi.name}}
{{movi.director}}
{{movi.image}}
</li>
</ul>
</v-container>
</v-app>
</div>
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
moviesData: [],
}
},
methods:{
getMovies(){
axios.get('https://proyecto-final-cf888-default-
rtdb.firebaseio.com/' + 'movies.json')
.then( (res)=>{
let results=[];
console.log(res);
for (let id in res.data){
console.log(id);
console.log(res.data[id]);
results.push({
id: id,
name: res.data[id].name,
director: res.data[id].director,
image: res.data[id].image,
});
}
this.moviesData= results;
})
.catch((error)=>{
console.log(error)
})
}
},
created(){
this.getMovies();
}
};
</script>

Storing an URL in Firestore will not store the referenced image itself.
You might upload the image to Storage and a reference it in Firestore.
Or you store the URL in Firestore and initiate a HTTP-GET request in your app to load the image from the web.
Note:
Firestore limits a single document to 1MB. Many images are larger than that.
Storage also offer functions to scale uploaded images automatically etc.

This was the way:
<li v-for="movi in moviesData" :key="movi.id">
{{movi.name}}
{{movi.director}}
<v-img :src='movi.image'></v-img>
</li>
Incredibly simple.
Thanks everyone!

Related

Using pick in array Nuxt 3 useFetch

I'm trying to replicate the nuxt 3 useFetch sample but no luck so far.
https://v3.nuxtjs.org/getting-started/data-fetching#usefetch
My post.vue page contains the below code:
<template>
<section>
<div v-for="mountain in mountains" :key="mountain">{{mountain}}</div>
</section>
</template>
<script setup>
const runtimeConfig = useRuntimeConfig()
const { data: mountains, pending, error, refresh } = await useFetch('/mountains',{
baseURL: runtimeConfig.public.apiBase,
pick: ['title']
})
console.log(mountains.value)
</script>
For some reason the data is not shown in template.
The console.log() shows Proxy {title: undefined}
I've realized that removing the pick option solves the issue, so I'm wondering if pick only works for objects and can't be used in arrays.
It's odd because the sample is using an array https://v3.nuxtjs.org/api/composables/use-fetch.
The pick option currently works only if you are fetching one document (one Js object).
In the official docs you can see they are fetching a specific document in their API: https://nuxt.com/docs/getting-started/data-fetching.
One option you have is to make an API route that returns one object only.
Inside of your <div>, you are trying to return {{mountain}}, but at the time this page loads there is no such variable--because the const mountains hasn't been fetched yet. What you need to do is add a <div v-if="mountains" v-for="mountain in mountains" :key="mountain">{{mountain}}</div>
For the brief moment it takes before the useFetch function to return mountains,the <div> will not try to show {{mountains}}, because the v-if prevents the <div> from being shown in the first place.

Consuming external API using SvelteKit works but only after reloading route

Using SvelteKit 1.0.0-next.95 to get a JSON array back from an external API endpoint and display in a template like this:
<script context="module">
export async function load({ fetch }) {
const url = 'https://www.schoolhouseyoga.com/api/announcement'
const res = await fetch(url, {
method: 'GET',
mode: 'cors',
headers: {
'content-type': 'application/json'
}
})
if (res.ok) {
return {
props: {
sections: await res.json()
}
}
}
return {
status: res.status,
error: new Error(`Could not load ${url}`)
}
}
</script>
<script>
export let sections = []
</script>
<template>
<section>
{#if sections.length > 0}
<div class="callout">
<h1>Announcements</h1>
{#each sections as section}
<div>
{#if section.announcements.length > 0}
<h2>{section.section}</h2>
{/if}
{#each section.announcements as announcement}
<p><b>{announcement.title} </b>- {#html announcement.description}</p>
{/each}
</div>
{/each}
</div>
{/if}
</section>
</template>
If you try https://www.schoolhouseyoga.com/api/announcement (CORS) in a browser or using curl, you'll get a JSON array with two elements.
When I run this in dev mode, npm run dev -- --open and navigate to this route on Safari 14.1 (macOS), I get a 500 error and the message, "Origin http://localhost:3000 is not allowed by Access-Control-Allow-Origin." If I try to navigate to that route on Google Chrome, I get a 500 error and "TypeError: Failed to fetch".
But with either browser, if I refresh the page, the data loads successfully. Navigating to a different route then back again, the error reappears.
I am guessing this has to do with SSR but not sure what to do about it.
Any thoughts?
The problem was related to server-side rendering and a CORS issue with the endpoint. When the server-side code performed the fetch, it worked fine. Subsequent fetches were being performed by the client (which ran into the CORS issue).
While the endpoint appeared to have CORS enabled...
import { Router } from 'express';
import cors from 'cors';
import * as controller from './announcement.controller';
const router = Router();
router.get('/', cors(), controller.index);
But the endpoint was also using helmet and needed
app.use(helmet.permittedCrossDomainPolicies());
prior to loading the routes.
Hope this helps others.

firestore database with Vue: when I refresh the page I don't get the data on screen,

I use Firestore with Vue and the problem is: I can't get the data from the database but when I change the :key="Profiles['.key']" to this :key="Profiles" then I see the data on my screen but when I refresh the page the data is gone it doesn't see it any more.
This is the code:
<template>
<div>
<h1 class="text-center mt-16">Admin</h1>
<div v-for="Profiles in Profile" :key="Profiles" class="text-center mt-16">
<p>{{Profiles.username}}</p>
<p>{{Profiles.email}}</p>
<p>{{Profiles.userId}}</p>
<p>{{Profiles.role}}</p>
<p>{{Profiles.haveAccess}}</p>
<p>{{Profiles.createdAt}}</p>
</div>
</div>
</template>
<script>
/*eslint-disable-line*/import { db } from '../../Database';
import firebase from 'firebase';
export default {
data() {
return {
currentUser: firebase.auth().currentUser
}
},
created() {
this.currentUser = firebase.auth().currentUser;
},
firestore: {
Profile: db.collection('Profile')
}
}
</script>
Here is the data from the database.
But when I refresh the page I don't get the data anymore.
This happens because the "Created" is only called during the creation of the page, for the request to be made every time it is accessed try to change the "Created" for "Mounted".
For more information search on Vue.js Life Cycle.

VueJS rendering data from REST service

I've attempted to render data from a http request to a component which is working fine, the issue is that it's null while the data is being fetched. While the data is null the console is throwing a TypeError until all the data is loaded and committed to the Vuex store.
All is working how I'd suspect, I'm just trying to figure how I can prevent the errors being thrown and to wait until all the appropriate data is fetched. I've seen others using v-if to check if the data is null which will work. It just seems tedious and that there surly is a better way to achieve the same outcome, without an application riddled with v-if statements checking every single state.
I came across this solution but it's still not working how I thought it would, I'm still receiving the same console errors. Am I using these key words correctly and are they in the correct location? since nothing has changed with every variation I've tried.
Vuex Action:
const actions = {
getThread ({ commit }, payload) {
Vue.http
.get(`http://localhost:9000/threads/${payload.id}`)
.then(async response => {
commit(FETCH_THREAD, await response.data)
})
}
}
This is within my vue file calling upon the action:
created () {
this.$store.dispatch('getThread', {id: '59280ab5acbafb17af9da902'})
}
I assume you are trying to display something from your store in your template. The problem is, Vue cannot render something that does not exist yet. The solution is to check whether the data exists or not.
Let's take this component example:
<template>
<div>
{{ someObject.name }}
</div>
</template>
<script>
export default {
data () {
return {
someObject: null
}
},
methods: {
fetchTheObject () {
this.someObject = {
id: 1,
name: 'My object'
}
}
},
created () {
setTimeout( () => {
this.fetchTheObject()
}, 3000)
}
}
</script>
As you can see, you will get an error in your console because someObject.name does not exist until fetchTheObject() has been called.
The solution is to put some v-if attribute to control that:
<template>
<div>
<span v-if="someObject === null">Fetching the object</span>
<span v-else>{{ someObject.name }}</span>
</div>
</template>
In general, you would want to display some spinner to show the user that something is loading...
Hope this helps
EDIT: And forget about the async await in your code, you don't need that here

CollectionFS image url from cfsFileUrl handler not working

I have followed collectionFS guide and several other stackoverflow questions [here][1], but I still face an error in displaying the image. The broken image icon is shown and console prints "Resource interpreted as Image but transferred with MIME type text/html:". Any idea what i can do to solve this??
My code are as follows:
HTML
<template name="fileList">
{{#each images}}
{{name}}
<img src="{{cfsFileUrl 'default1'}}">
<br />
{{else}}
No Files uploaded
{{/each}}
</template>
Client JS
Template.fileList.helpers({
'images': function(){
return ImagesFS.find({}, {sort: {uploadDate:-1}});
}
});
Server JS
if(Meteor.isServer){
ImagesFS.fileHandlers({
default1: function(options) { // Options contains blob and fileRecord — same is expected in return if should be saved on filesytem, can be modified
console.log('I am handling default1: ' + options.fileRecord.filename);
console.log(options.destination());
return { blob: options.blob, fileRecord: options.fileRecord }; // if no blob then save result in fileHandle (added createdAt)
}
});
}
I got this working by manually adding the cfs-public-folder package via:
meteor add cfs-public-folder
Now files show in the browser, and the URL to
http://localhost:3000/cfs/<collectionFS name>/<imageId_fileHandler.ext>
works.
cfs-public-folder
is not working anymore on 0.9.x
please use:
.url()
like
MyColletionCFS.findOne().url()

Resources