@hawkeye64 I’ve read quite a lot of instances where Quasar CSS led people to other frameworks… Just so that you know
Posts made by pazarbasifatih
-
RE: PurgeCSS
-
RE: Sortable in tabs
@dobbel Sortable as in Sortable.js, I think.
An example would be like this:
https://sortablejs.github.io/vue.draggable.next/#/table-example -
RE: Q-Uploader with Composition API
@metalsadman Actually, I don’t assume myself knowing anything. I look at the documentation and try to find my way. My eyes simply couldn’t pick up anything about the fact that refs could be referred by xyz.value, on neither vue3 documentation nor the quasar’s. I’m a novice with some JS knowledge. Bare with me, please.
And thank you. Of course I didn’t know that. Now I’ll try that
-
RE: Q-Uploader with Composition API
Anyway, I tried the putting scope.reset() in the queuedFiles list template, (as it seems like only place to access the prescribed reset(). function is through scope in the documentation)
It resets the whole thing… So I needed use the event @finish event but it didn’t fit any place I’ve inserted so far. I probably don’t understand this component at all. Why is it so hard? I am doing guess work here.
This is the Codepen I’ve tried doing it. -
RE: Q-Uploader with Composition API
@dobbel said in Q-Uploader with Composition API:
this.$refs[myRefToQUploader].reset()
Thank you, but
this
doesnt make sense in composition api. -
RE: Q-Uploader with Composition API
@rstoenescu Great! I tried running
reset()
method in the MyUploader.js but I am probably doing something wrong because, it’s giving meReferenceError: reset is not defined at eval
error.So I tried creating my own
function reset()
inside the MyUploader.js but it has the infamous uploadSize.value in the original example, which is not inside const state, so I can’t use the helpers object for reaching it.function reset () { if (props.disable === false) { state.abort() state.uploadedSize.value = 0 uploadSize.value = 0 revokeImgURLs() state.files.value = [] state.queuedFiles.value = [] state.uploadedFiles.value = [] } }
I’m sure there must be a proper way of calling that function but I lack the knowledge.
Sorry to bother for this, but I’ve got kind of obsessed with it now. Wouldn’t putting uploadSize inside the
const state = {uploadSize: ref(0)}
in the uploader-core be a little bit more flexible? -
RE: Q-Uploader with Composition API
@metalsadman Great! Thank you for point that out.
Now let’s me see how I can fix the uploadSizeLabel issue.
Uploading (A feature to block parallel uploading would be great)
Uploaded
Remove File (See thatremoveFile()
does not recalculate the uploadSizeLabel because I can’t reach uploadSize from helpers. It should be configured via a PR in uploader-core.js)
And this problem leads to the following, when all files are removed.
And if you add a file, it keeps adding to the old uploadSize.
2.8 MB + 400 KB = 3.2 MB // true but this is not the behavior you’d expect to see.
When done with uploading, the label is a complete(!) mess
-
RE: Q-Uploader with Composition API
I have converted github/birchb 's wonderful q-uploader firebase implementation into the composition api using this files above. And it’s uploading, updating the progess and removing the file on demand. It has 2 minor issues with emitting the ‘uploaded’ event and calculating the blue uploadSize label on top of the component when the item is removed. But I’m sure they’re solvable problems. So the code is…
import { createUploaderComponent } from "quasar"; import { computed, ref } from "vue"; import firebase from "firebase/app"; // export a Vue component export default createUploaderComponent({ // defining the QUploader plugin here name: "MyUploader", // your component's name props: { pathPrefix: { type: String, default: "", }, }, emits: ["uploaded", "failed", "removed"], injectPlugin({ props, emit, helpers }) { // can call any other composables here // as this function will run in the component's setup() const storage = ref(firebase.storage().ref()); const activeTasks = ref([]); // [ REQUIRED! ] // We're working on uploading files const isUploading = computed(() => { // return <Boolean> }); // [ optional ] // Shows overlay on top of the // uploader signaling it's waiting // on something (blocks all controls) const isBusy = computed(() => { // return <Boolean> }); // [ REQUIRED! ] // Abort and clean up any process // that is in progress function abort() { // ... } // [ REQUIRED! ] // Start the uploading process function upload() { if (props.disable || !helpers.queuedFiles.value.length) { return; } helpers.queuedFiles.value.forEach(async (file) => { await __uploadSingleFile(file); }); } function __uploadSingleFile(file) { let pathPrefix = props.pathPrefix || ""; // const fileRef = storage.value.child(pathPrefix + file.name) const fileRef = storage.value.child(`${pathPrefix}/${file.name}`); helpers.updateFileStatus(file, "uploading", 0); const uploadTask = fileRef.put(file); activeTasks.value.push(uploadTask); // Listen for state changes, errors, and completion of the upload. uploadTask.on( firebase.storage.TaskEvent.STATE_CHANGED, // or 'state_changed' (snapshot) => { // Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded if (file.__status !== "failed") { const loaded = Math.min( snapshot.totalBytes, snapshot.bytesTransferred ); helpers.uploadedSize.value += loaded - file.__uploaded; helpers.updateFileStatus(file, "uploading", loaded); } }, (error) => { // A full list of error codes is available at // https://firebase.google.com/docs/storage/web/handle-errors helpers.queuedFiles.value.push(file); helpers.updateFileStatus(file, "failed"); emit("failed", { file, error }); helpers.uploadedSize.value -= file.__uploaded; activeTasks.value = activeTasks.value.filter((t) => t !== uploadTask); }, () => { // Upload completed successfully, now we can get the download URL uploadTask.snapshot.ref .getDownloadURL() .then((downloadURL) => { const fullPath = uploadTask.snapshot.ref.fullPath; const fileName = uploadTask.snapshot.ref.name; helpers.uploadedFiles.value.push(file); helpers.updateFileStatus(file, "uploaded"); let uploadTime = _.round(new Date().getTime() / 1000); console.log("TCL: __uploadSingleFile -> uploadTime", uploadTime); let [fileSize, fileType] = [file.size, file.type]; console.log( downloadURL, fileName, fileSize, fileType, fullPath, uploadTime ); emit("uploaded", { downloadURL, fileName, fileSize, fileType, fullPath, uploadTime, }); helpers.uploadedSize.value += file.size - file.__uploaded; // helpers.uploadedSize.value = 0; }) .catch((error) => { emit("failed", { file, error }); }); activeTasks.value = activeTasks.value.filter((t) => t !== uploadTask); } ); } function removeFile(file) { if (props.disable) { return; } if (file.__status === "uploaded") { helpers.uploadedFiles.value = helpers.uploadedFiles.value.filter( (f) => f.name !== file.name ); // As of Quasar v2 beta7 uploadSize cannot be taken out of helpers/state. So removeFile won't be able to change blue header the label on top. helpers.uploadSize.value -= file.__uploaded; } else if (file.__status === "uploading") { file.__abort(); } else { helper.uploadSize.value -= file.size; } helpers.files.value = helpers.files.value.filter((f) => { if (f.name !== file.name) { return true; } f._img !== void 0 && window.URL.revokeObjectURL(f._img.src); return false; }); helpers.queuedFiles.value = helpers.queuedFiles.value.filter( (f) => f.name !== file.name ); emit("removed", [file]); } return { isUploading, isBusy, abort, upload, }; }, });
It gives the following warningBut it’s a fully functional Firebase Uploader for Quasar v2 now.[Vue warn]: Component emitted event "uploaded" but it is neither declared in the emits option nor as an "onUploaded" prop.
I don’t know why.Edit: emits: [“uploaded”, “failed”, “removed”],
-
RE: Q-Uploader with Composition API
I made a discovery today. I will be working on it over the next days. It’s the uploader-core which exposes all the functions and references. So I can begin working with the createUploaderComponent Hurray.
Edit: Ok ok this thing goes deeper than I’ve expected. There’s this xhr-uploader-plugin which exposes how things are running. I’ve finally found how the heck the queuedFiles can be called in the createUploaderComponent:
helpers.queuedFiles.value
. So I’ll keep running my expedition from there. -
RE: A working QFirebaseUploader component
this is not properly working, sorry. the computed properties are blocking the process. The uploaded chunks are not reflected as percentages. Pfff.
-
RE: Q-Uploader with Composition API
So, ok. I came up with a solution with factory function but it spits out an error.
This one is a free project on firebase.import firebase from "firebase/app"; import "firebase/storage"; const firebaseConfig = { apiKey: "AIzaSyCp5sEmtSaDOjIdm5E88Wy41cCqFOoYd2o", authDomain: "someproject-43c3a.firebaseapp.com", projectId: "someproject-43c3a", storageBucket: "someproject-43c3a.appspot.com", messagingSenderId: "445668329191", appId: "1:445668329191:web:9bebd22c71e3ca8c05c442", }; // init firebase firebase.initializeApp(firebaseConfig); // init services const projectStorage = firebase.storage(); export { projectStorage};
And this is the useStorage composable
import { projectStorage } from "../boot/firebase"; import { ref } from "vue"; const useStorage = () => { const error = ref(null); const downloadURL = ref(null); const filePath = ref(null); const uploadFile = async (file) => { filePath.value = `covers/${file.name}`; const storageRef = projectStorage.ref(filePath.value); try { const res = await storageRef.put(file); downloadURL.value = await res.ref.getDownloadURL(); } catch (err) { console.log(err.message); error.value = err; } }; return { uploadFile, downloadURL, error }; }; export default useStorage;
And this is where it’s placed in the the Quploader as a factory function.
<template> <q-page class="flex flex-center"> <q-uploade multiple :factory="factory" @factory-failed="onFactoryFail" ></q-uploader> </q-page> </template> <script> import { ref } from "vue"; import useStorage from "src/composables/useStorage"; import { projectStorage } from "src/boot/firebase"; export default { name: "PageIndex", setup(props) { const { uploadFile, downloadURL, } = useStorage(); //Events async function factory(files) { // console.log("files[0].name:", files[0].name); await uploadFile(files[0]); console.log("downloadURL.value:", downloadURL.value); } function onFactoryFail(err, files) { console.log("factoryFail error:", err); console.log("factoryFail files:", files); } return { factory, onFactoryFail }; }, }; </script>
It’s giving me the downloadURL.value, so it’s successful in uploading. @factory-failed is giving me the following errors about url:
factoryFail error: TypeError: Cannot read property 'url' of undefined at getProp (xhr-uploader-plugin.js?e40a:131) at performUpload (xhr-uploader-plugin.js?e40a:136) at eval (xhr-uploader-plugin.js?e40a:116)
factoryFail files: [File]
(Eventhough the bucket has that file uploaded in it)Eventually this is the screen that the user ends up with:
A similar error has been recorded in this topic but didn’t receive a solution.
-
RE: Q-uploader with factory function
I’m having the same issue with @LIANG-FENG and @bruno-ronchetti
It uploads perfectly to Firebase. But I don’t have a url.
I tried moving from async await syntax to Promise syntax. It didn’t work.
I tried removing all the events from the quploader, except for the @factory-failed event. It didn’t work.
It gives error, but the thing works. -
RE: Q-Uploader with Composition API
Maybe I can work with those Events under the Quploader Api. They seem to be offering
@uploaded
and@uploading
… Also they can takefiles
-
RE: Q-Uploader with Composition API
@dobbel Yeay, more of them! Thanks for uncovering the mystery
Quasar never ceases to amaze me.
Do you have any idea about whatthis
refers to in the qv1{QUploaderBase} from "quasar"
-
RE: Q-Uploader with Composition API
So, I discovered 2 things.
First thing is that Q-uploader has secret v-on bindings,@added
@rejected
uploaded
and@finish
, which I believe should make their places in the documentation.
Second is the old way of Quploader for Firebase can be modified to receive vue refs.
But the following code has some issues withthis
.For example I get
Uncaught TypeError: Cannot read property 'files' of undefined
error with this code.
But where do thethis.files
,this.uploadSize
,this.uploadedSize
,this.removeFile(file)
come from?
Alsothis.$emit
looks problematic, where should I put thecontext
in this file? There is no setup configuration.import { createUploaderComponent } from "quasar"; import { computed, ref } from "vue"; // export a Vue component export default createUploaderComponent({ // defining the QUploader plugin here name: "QFirebaseUploader", // your component's name props: { // ...your custom props }, emits: [ // ...your custom events name list ], injectPlugin({ props, emit, helpers }) { // can call any other composables here // as this function will run in the component's setup() const uploading = ref(false); const uploadTasks = ref([]); // [ REQUIRED! ] // We're working on uploading files const isUploading = computed(() => { return uploading.value; }); // [ optional ] // Shows overlay on top of the // uploader signaling it's waiting // on something (blocks all controls) const isBusy = computed(() => { return uploading.value; }); // [ REQUIRED! ] // Abort and clean up any process // that is in progress function abort() { uploadTasks.value.forEach((uploadTask) => { uploadTask.cancel(); }); uploading.value = false; } // [ REQUIRED! ] // Start the uploading process function upload() { uploading.value = true; this.files.forEach((file) => { const datetime = new Date().toISOString().split(".")[0]; const newRef = this.path + datetime + "_" + file.name; const uploadTask = firebaseCs.ref(newRef).put(file); uploadTasks.value.push(uploadTask); uploadTask.on( "state_changed", (snapshot) => { this.uploadSize = snapshot.totalBytes; this.uploadedSize = snapshot.bytesTransferred; }, (error) => console.log(error), () => { uploadTask.snapshot.ref.getDownloadURL().then((downloadURL) => { this.$emit("upload", { url: downloadURL, name: file.name, uploadedDate: datetime, }); this.removeFile(file); }); this.uploadedSize - this.uploadSize === 0 && (uploading.value = false); } ); }); } return { isUploading, isBusy, abort, upload, }; }, });
-
RE: Q-Uploader with Composition API
@dobbel Edited that minor detail. Thank you for pointing it.
Of course… It’s in beta and I want to discuss how we can improve.So event.target.files doesn’t give me the list of files to begin with…
-
Q-Uploader with Composition API
Hey there,
Can we elaborate a little bit on making this Q-Uploader documentation help more to the third party storage users? Firebase in particular.
I read it over and over, only to look at the screen with empty eyes, wondering where to start first.
So we have urls,methods and etc on the API, that’s a good sign if you have an endpoint to upload…
What if I need pre and post upload actions? Like retrieving user data beforehand or recording to database after uploading?
Then I’m obliged to use the template below, which leaves me clueless
If I want to call the
function upload()
, does it take(file)
as argument. Willfile
be passed as prop?
Is it going to upload one by one or all at the same time.
How am I to abort the upload action of multiple files. How will I reference to that specific file and not others?
What if I need creating a prefix?
What if I need to record the event to a database?I’m lost. How do you guys achieve all this with the Firebase?
// MyUploader.js import { createUploaderComponent } from 'quasar' import { computed } from 'vue' // export a Vue component export default createUploaderComponent({ // defining the QUploader plugin here name: 'MyUploader', // your component's name props: { // ...your custom props }, emits: [ // ...your custom events name list ], injectPlugin ({ props, emit, helpers }) { // can call any other composables here // as this function will run in the component's setup() // [ REQUIRED! ] // We're working on uploading files const isUploading = computed(() => { // return <Boolean> }) // [ optional ] // Shows overlay on top of the // uploader signaling it's waiting // on something (blocks all controls) const isBusy = computed(() => { // return <Boolean> }) // [ REQUIRED! ] // Abort and clean up any process // that is in progress function abort () { // ... } // [ REQUIRED! ] // Start the uploading process function upload () { // ... } return { isUploading, isBusy, abort, upload } } })
I realize that there is a FBQUploader for vue2 version but I don’t know how to implement his code to vue version 3.
-
RE: Send Email from Quasar App Example Needed
Believe me if you’re asking this particular question you’re better off using a managed backend. Try Firebase. It’s easy to learn and goes a long long way.
But if you insist on taking the hard way, you might want to check the Nodemailer. You’re going to have a lot of fun (!) debugging stuff in your Authentication services and Database
And if you do so please… don’t ever give to end user the control of your mail module… like never… -
RE: Send Email from Quasar App Example Needed
@cynderkromi Yes you can create the messaging module with Quasar and store the messages in a backend solution. Then each time a user sends a message to another, the backend can trigger a mail notification. The easiest solution is Firebase. You can find courses telling exactly how you can set this up step by step. (search udemy first)
-
RE: Send Email from Quasar App Example Needed
Sorry, I was busy for a while.
@cynderkromi have you considered making a messages module so your users can message each other?
You can send email notifications to the users when they receive a message…
~You’ve got a message from the {{user}} which says {{first100CharMessage}} Click and learn more~
You can’t control the outbound traffic with you current knowledge and It might be an invitation for trouble sent to your home address. You’ll have to log a lot of things. With user messages you’ll at least restrict the message traffic to be in between the users.Quasar is a frontend framework. What you want to do involves mostly backend.