0

Below is the code I have for my firebase storage composable I then call and use in all my other vue.js views:

import { ref } from "vue";
import { projectStorage } from "../firebase/config";

//all the files at the root in one array
const mixed = ref([]);
const loading = ref(true);

//function to list all the contents of a folder
const  getClientFiles = async (folder) => {
  const listRef = projectStorage.ref(folder);

  listRef
    .list()
    .then((res) => {
      res.prefixes.forEach((folderRef) => {
        // All the prefixes under listRef.
        mixed.value.push({
          name: folderRef.name,
          type: "Folder",
          size: "--",
          lastUpdated: "--",
          url: "--",
        });
      });
      if (res.items.length > 0) {
        res.items.forEach((itemRef) => {
          let one = {
            name: itemRef.name,
            type: "Folder",
            size: "--",
            lastUpdated: "--",
            url: "--",
          };

          // All the items under listRef.
          itemRef.getDownloadURL().then((url) => {
            // console.log ("download url: " + url)
            one.url = url;
          });

          itemRef.getMetadata().then((metadata) => {
            // Metadata now contains the metadata for each itemRef
            (one.type = metadata.contentType),
              (one.size = metadata.size),
              (one.lastUpdated = metadata.timeCreated);
          });
          mixed.value.push(one);
        });
        console.log(mixed.value)
        loading.value = false
      }
    })
    .catch((error) => {
      // Uh-oh, an error occurred!
      console.log(error);
    }).finally(() => {
if (mixed.value.length > 0){
    loading.value = false
}
    })
}

export { getClientFiles, loading, Files, Items, mixed, meta, links };

The issue I am having is that the code lists all the elements in the mixed array as references at first. And can only be updated after I press a button that basically updates something in the DOM.

Is there a way to cause loading to still be true until all the folders and files are ready and pushed into the mixed array?

Christian
  • 4,902
  • 4
  • 24
  • 42
Kola Ayanwale
  • 105
  • 1
  • 8

1 Answers1

1

It sounds like you want to wait for the single list call and then all getDownloadURL calls to complete.

It's easiest to do that by using await rather than then, and using for...of rather than forEach. With those two changes, the code would look something like this:

const getClientFiles = async (folder) => {
  const listRef = projectStorage.ref(folder);

  const res = await listRef.list();
  for (const folderRef of res.prefixes) {
    mixed.value.push({
      name: folderRef.name,
      type: "Folder",
      size: "--",
      lastUpdated: "--",
      url: "--",
    });
  }

  if (res.items.length > 0) {
    for (const itemRef of res.items) {
      let one = {
        name: itemRef.name,
        type: "Folder",
        size: "--",
        lastUpdated: "--",
        url: "--",
      };

      one.url = await itemRef.getDownloadURL()
      const metadata = await itemRef.getMetadata()
      one.type = metadata.contentType);
      one.size = metadata.size;
      one.lastUpdated = metadata.timeCreated;

      mixed.value.push(one);
    });
  }
  loading.value = false
}

There may be some syntax and minor other errors in here, so please focus on the big changes which are the use of await and for...of loops.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807