What are the steps to store a firebase storage downloadURL in a firestore collection?

I'm facing an issue with saving my firebase storage image into a firestore collection variable. Initially, it was working correctly but suddenly stopped functioning, and now the image variable is returning null.

Note: I am using the asia-south1 server.

Below is the template code for ManageProducts:

<div>
      <h1>Add Items</h1>
      <div>
        <form>
          <input type="text" placeholder="name" required v-model="item.name" />
          <textarea
            required
            placeholder="description"
            v-model="item.description"
          ></textarea>
          <input
            type="text"
            required
            placeholder="price"
            v-model="item.price"
          />
          <div class="form-group">
            <input
              type="text"
              placeholder="Available/Unavailable"
              v-model.lazy="item.status"
              class="form-control"
            />
          </div>
          <div class="form-group">
            <input
              type="text"
              placeholder="Sewing Partner"
              v-model.lazy="item.sewingPartner"
              class="form-control"
            />
          </div>
          <input type="file" required @change="uploadImage" accept="image/*" />
          <button @click.prevent="AddNewItem">Add Item</button> |
          <button class="delete">
            Cancel
          </button>
        </form>
      </div>

And here's the script for Manage Products, where all input values are successfully added except for the firebase storage image URL:

  <script>
    import { dbItemAdd } from "../../main";
    import firebase from "firebase";
    import "firebase/firestore";
    import "firebase/storage";
    export default {
      name: "AddItems",
      components: { AdminPreviewItems },
      data() {
        return {
          items: [],
          item: {
            name: null,
            description: null,
            image: null,
            price: null,
            status: null,
            sewingPartner: null,
          },
        };
      },
      methods: {
        uploadImage(e) {
          let file = e.target.files[0];
          var storageRef = firebase.storage().ref("products/" + file.name);
          let uploadTask = storageRef.put(file);
          uploadTask.on(
            "state_changed",
            (snapshot) => {
              console.log(snapshot);
            },
            (error) => {
              // Handle unsuccessful uploads
              console.log(error.message);
            },
            () => {
              // Handle successful uploads on complete
              // For instance, get the download URL: https://firebasestorage.googleapis.com/...
              uploadTask.snapshot.ref.getDownloadURL().then((downloadURL) => {
                this.item.image = downloadURL;
                console.log("File available at", downloadURL);
              });
            }
          );
        },
    
        AddNewItem() {
          dbItemAdd
            .add({
              name: this.item.name,
              description: this.item.description,
              image: this.item.image,
              price: this.item.price,
              status: this.item.status,
              sewingPartner: this.item.sewingPartner,
            })
            .then(() => {
              location.reload();
              console.log("Adding data to Firestore");
            })
            .catch((error) => {
              console.error("Error adding document: ", error);
            });
        },
      },
    };
    </script>

Answer №1

At what point do you call the AddNewItem function? If the image has not been uploaded or the downloadURL has not been fetched, clicking the submit button will result in it being null.

uploadTask.snapshot.ref.getDownloadURL().then((downloadURL) => {
  this.item.image = downloadURL;
  console.log("File available at", downloadURL);
  //function must be called after this
});

If this.item.image is null (default value), you can disable the submit button.

<button :disabled="!item.image" @click.prevent="AddNewItem">Add Item</button>

I don't see the state_changed observer being used. Do you need to display the upload progress? If so, you can keep the current code as is. Otherwise, you could refactor it into an async function like this:

async uploadImage(e) {
  let file = e.target.files[0];
  if (!file) alert("No file selected")
  var storageRef = firebase.storage().ref("products/" + file.name);
  let uploadTask = await storageRef.put(file);
  const url = await storageRef.getDownloadURL()
  this.item.image = url
}

You are actually uploading the image upon file change rather than on submit button click, so you could add the Firestore document right after getting the downloadURL within the @change event itself.

Answer №2

After uploading a file to storage, the next step is to use getDownloadURL() to generate an access token

This URL and access token should then be stored directly into firestore

// Create reference to image
var mountainImagesRef = storageRef.child('images/mountains.jpg');
// Put image file to Storage
ref.put(file).then((snapshot) => {
// Once complete, retrieve the downloadURL
return mountainImagesRef.getDownloadURL()})
.then((downloadURL) =>
// Include download URL in Firestore
firestore().doc("path/to/document/here").add({
              name: this.item.name,
              description: this.item.description,
              image: downloadURL,
              price: this.item.price,
              status: this.item.status,
              sewingPartner: this.item.sewingPartner,})
).catch(console.error);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for managing and identifying canceled requests in an Angular HTTP interceptor

Having trouble handling cancelled requests in my http interceptor. Despite trying various methods from SO, I can't seem to catch it. Here is an example of how my interceptor looks: public intercept(req: HttpRequest<any>, next: HttpHandler) { ...

Using the toggle method or IF statements in JavaScript to implement show and hide functionality upon clicking

I’ve been struggling with this issue for days now. It seems like I may have overcomplicated a simple piece of code. I'm trying to show some divs when a button is clicked, but I’m having trouble getting it to work properly. Initially, I used VAR.st ...

Error: You cannot implement an import statement beyond a module while utilizing reactjs CDN Links

I am developing a Reactjs app using react CDN Links instead of 'npx create-react-app'. I have set up an index.html, index.js, and App.js files. My goal is to import the App.js component into the Index.js file using import App from '../compon ...

What is the best way to switch between light and dark themes with the ability to locally store the current theme?

Being new to the realm of react, I have been delving into the implementation of new features using Material-UI. One particular feature I am working on involves toggling between light and dark themes, with the current theme being stored locally within the b ...

Why does my JSON variable contain "type" and "data" values instead of something else?

After using JSON.stringify() on my object to save it to a file, I noticed that one of the parameters does not have the expected string value assigned. Instead, it has a "type" and "data". Code: fs.writeFileSync('myjson.json', JSON.stringify(myjs ...

Combining Mouseover and Click Events in Vue JS

Having four pictures, I want to display a specific component when hovering over them. However, I also need to bind the click event so that clicking on the picture will reveal the component. The challenge is that I am unable to simultaneously bind two event ...

Excessive Function Calls Detected in AngularJS Application

I'm facing a major performance issue. I need to display details in a list, but the function is being called excessively. Feel free to check out the demo here Here's the HTML code snippet : <div ng-controller="MyCtrl as ctrl"> <p>K ...

Transmitting form information to a nested page within a div container

This is my fourth attempt to seek an answer to this question, as I've faced downvotes in previous attempts. So here we go again. I am trying to send data from a hidden input within a form using ajax. The value of the hidden input is generated by a php ...

An Angular directive utilizing dual aliases

Is there a simple method to give a directive two distinct names? For example: app.directive(['directiveNameOne', 'directiveNameTwo'], function() {...}); I have created a directive that handles both radio buttons and checkboxes in th ...

webdriverIO encountered an unhandled promise rejection, resulting in a NoSuchSessionError with the message "invalid session id

I am currently learning how to conduct UI testing using Jasmine and WebdriverIO in conjunction with NodeJS. Below is a snippet of my test code: const projectsPage = require('../../lib/pages/projects.page'); const by = require('selenium-we ...

Customizing the starting number of rows per page in TablePagination from material-ui

As a newcomer to using materials, I am looking to customize the table pagination to show 'n' number of rows, for example 10, and remove the "Rows per page" dropdown. <TablePagination rowsPerPageOptions={[]} component="div" ...

exploring the contrast of css versus javascript selectors

Could you please explain the contrast between div#name and #name? Is there a significant difference when using class or id to position an element? Thank you for your help. ...

Ways to assign a CSS class specifically for images

.calendarList { background-image: url('/resource3/hpsc/common/images/calendar.png'); background-position: 135px 50%; background-repeat: no-repeat; cursor:pointer; } <input type="text" id="toDatepicker" class="cal ...

"Expand" Button following X buttons

Check out this JSFiddle for the code: $(document).ready(function(){ $( ".keywordsdiv" ).each(function(){ $(this).children(".keywords").eq(3).after('<a href="" id="playtrailershowmorebuttons">....Show More</a>');//add a uniq ...

Customizing BootstrapVue styles by overriding default Bootstrap styles: encountering an error due to undefined variable

I recently set up a new Vue application and integrated Bootstrap-Vue for styling, but I'm encountering difficulties when trying to customize Bootstrap's default style. Error message: [sass] Undefined variable. 11 │ $b-custom-control-indicator- ...

AngularJS is restricting the use of square brackets within the URL parameter, specifically the character '[.'

My goal is to connect to an external API Everything works smoothly when my parameters are set up like this $http.post('http://api.myprivatebox.com/users.json', { email : email, password : password}).then(function (results) { console.log( ...

Assign an array value to the input based on the selection made in Javascript

After finding a lot of useful information in previous questions, I am struggling to get the last piece that I need. My PHP code helps me loop through form fields and assign unique names to each field using a variable. One of these fields is for "expense ty ...

Preventing page re-rendering with redux when a condition is not met

I am currently working on a page that features a question paper with multiple options and a button to navigate to the next question. import Grid from "@material-ui/core/Grid"; import Typography from "@material-ui/core/Typography"; import React, { useEffec ...

I duplicated a functional jQuery form and moved it to a different location, but I am only able to get the

I recently duplicated a jQuery form from one page to another, but encountered unexpected issues with the copied version. The original form functions as follows: An onclick function connected to an image triggers a confirmation modal window with an "OK" bu ...

Is there a way to reach a different function within the value of the react Context.Provider?

Right now, I am learning how to utilize the react context API. Within my react Provider class, I have some state data and functions stored in the value={}. But I am curious, how can I call a function inside this value from another function within the same ...