This worked perfect, have used in one of my projects now.
Thanks a lot.
This worked perfect, have used in one of my projects now.
Thanks a lot.
@Hawkeye64 thanks for the advice, lets see if @Pratik-Patel has this working and is an easy fix we can use. i will give it a try.
Thanks
@Pratik-Patel i have tried using your qgrid extension but there are a few quirks i found,
the filter_type: ‘select’ and pagination does not seem to work with data being requested from the server, i am pasting the demo i have built, its pretty straight forward with the ajax request i am doing.
can you please review
@Hawkeye64 if you can also advise, thanks!
<template>
<div>
<q-grid
:title="`${pageTitle}s`"
:pagination.sync="pagination"
:data="data"
:columns="columns"
:columns_filter="true"
:draggable="true"
:fullscreen="true"
:csv_download="true"
:global_search="true"
:no-data-label="$utils.noResultsLabel"
:no-results-label="$utils.filterNoResultsLabel"
row-key="id"
:loading="loading"
:filter="filter"
@request="onRequest"
binary-state-sort
>
<template v-slot:body="props">
<q-tr :props="props">
<q-td key="id">
{{ props.row.id }}
</q-td>
<q-td key="roll_no">
{{ props.row.roll_no }}
</q-td>
<q-td key="color">
{{ props.row.color }}
</q-td>
<q-td key="gsm">
{{ props.row.gsm }}
</q-td>
<q-td key="length">
{{ props.row.length }}
</q-td>
<q-td key="roll_size">
{{ props.row.roll_size }}
</q-td>
<q-td key="gross_weight">
{{ props.row.gross_weight }}
</q-td>
<q-td key="net_weight">
{{ props.row.net_weight }}
</q-td>
<q-td key="createdAt">
{{ $utils.formatDate(props.row.createdAt) }}
</q-td>
<q-td key="updatedAt">
{{ $utils.formatDate(props.row.updatedAt) }}
</q-td>
</q-tr>
</template>
</q-grid>
</div>
</template>
<script>
const strPage = "Roll";
import { mapActions, mapState, mapGetters } from "vuex";
export default {
async mounted() {
this.refresh();
},
computed: {
...mapState("enquiry", ["arrColor"]),
arrColorMapped() {
let arr = this.arrColor.map(str => {
return { id: str, name: str };
});
return arr;
},
pageUri() {
return this.pageTitle.toLowerCase().replace(" ", "_");
}
},
methods: {
async onRequest(props) {
const { page, rowsPerPage, sortBy, descending } = props.pagination;
const strFilter = props.filter;
this.loading = true;
let objParams = Object.assign({}, props.pagination);
objParams.search = strFilter;
let objResponse;
try {
//pass status as params
if (this.status) {
objParams.status = this.status;
}
objResponse = await this.$myAxios.execute(
"GET",
`/${this.pageUri}`,
objParams
);
} catch (e) {
this.$utils.showErrorNotice(e.message);
} finally {
this.loading = false;
}
if (objResponse) {
this.pagination.rowsNumber = objResponse.obj.count;
this.pagination.page = page;
this.pagination.rowsPerPage = rowsPerPage;
this.pagination.sortBy = sortBy;
this.pagination.descending = descending;
this.data = objResponse.obj.rows;
}
},
async refresh() {
this.onRequest({
pagination: this.pagination,
filter: undefined
});
}
},
data() {
return {
pageTitle: strPage,
breadcrumbs: [
{ id: 1, label: "Home", icon: "home", to: "/admin/dashboard" },
{ id: 2, label: strPage, icon: "folder" }
],
columns: [
{
name: "id",
required: true,
label: "Id",
align: "left",
field: "id",
sort: (a, b) => parseInt(a, 10) - parseInt(b, 10),
sortable: true
},
{
name: "roll_no",
required: true,
label: "Roll #",
align: "left",
field: "roll_no",
sort: (a, b) => parseInt(a, 10) - parseInt(b, 10),
sortable: true
},
{
name: "color",
label: "Color",
align: "left",
field: "color",
sortable: true,
filter_type: "select",
sort: (a, b) => parseInt(a, 10) - parseInt(b, 10)
},
{
name: "gsm",
label: "GSM",
align: "left",
field: "gsm",
sortable: true,
sort: (a, b) => parseInt(a, 10) - parseInt(b, 10)
},
{
name: "length",
label: "Length",
align: "left",
field: "length",
sortable: true,
filter_type: "select",
sort: (a, b) => parseInt(a, 10) - parseInt(b, 10)
},
{
name: "roll_size",
label: "Roll Size",
align: "left",
field: "roll_size",
sortable: true,
sort: (a, b) => parseInt(a, 10) - parseInt(b, 10)
},
{
name: "gross_weight",
label: "Gross Weight",
align: "left",
field: "gross_weight",
sortable: true,
sort: (a, b) => parseInt(a, 10) - parseInt(b, 10)
},
{
name: "net_weight",
label: "Net Weight",
align: "left",
field: "net_weight",
sortable: true,
sort: (a, b) => parseInt(a, 10) - parseInt(b, 10)
},
{
name: "createdAt",
label: "Date Created",
align: "left",
field: "createdAt",
sortable: true,
sort: (a, b) => parseInt(a, 10) - parseInt(b, 10)
},
{
name: "updatedAt",
label: "Date Updated",
align: "left",
field: "updatedAt",
sortable: true,
sort: (a, b) => parseInt(a, 10) - parseInt(b, 10)
}
],
objModel: {},
editMode: false,
dialog: false,
printDialog: false,
loading: false,
filter: "",
data: [],
pagination: {
sortBy: "id",
descending: true,
page: 1,
rowsPerPage: 10,
rowsNumber: 10
},
rollsToPrint: []
};
}
};
</script>
<style lang="scss" scoped></style>
Here is how i did it maybe it helps someone in future
component
<template>
<div class="q-gutter-sm">
<q-field
ref="radioGroup"
:value="radioGroup"
hide-bottom-space
borderless
:rules="rules"
>
<q-radio
v-model="radioGroup"
v-on:input="emit"
v-for="radioOption in radioOptions"
:key="radioOption.id"
:val="radioOption.id"
:label="radioOption.name"
/>
</q-field>
</div>
</template>
<script>
export default {
name: "base-radio",
created() {
this.radioGroup = this.value;
},
data() {
return { radioGroup: "" };
},
props: {
radioOptions: {
type: Array,
required: true
},
value: { required: true },
isRequired: { type: Boolean, default: false },
tooltip: {
type: String
}
},
computed: {
rules() {
return this.isRequired ? this.$utils.requiredRule : [];
}
},
methods: {
emit(value) {
console.log("emitting", value);
this.$emit("input", value);
}
}
};
</script>
<style lang="scss" scoped></style>
call to component
<base-radio
isRequired
v-model="objModel.title"
:radioOptions="arrTitle"
></base-radio>
Please ignore above i found out i have to use QField for this as input and select are already wrapping them.
Hello
I have a q-radio component that is working fine but i am having a very hard time trying to validate that atleast one of the option must be selected for form validation.
if someone can help on this i will be highly grateful. Thanks in advance below is my code.
//my component
<template>
<div class="q-gutter-sm">
<q-radio
:value="value"
:rules="arrRules"
v-on:input="emit"
v-for="objOption in arrRadioOptions"
:key="objOption.id"
:val="objOption.id"
:label="objOption.name"
/>
</div>
</template>
<script>
export default {
name: "base-radio",
data() {
return {};
},
props: {
arrRadioOptions: {
type: Array,
required: true
},
value: { required: true },
is_required: { type: Boolean, default: false },
tooltip: {
type: String
}
},
computed: {
arrRules() {
return this.is_required ? this.$utils.requiredRule : [];
}
},
methods: {
emit(value) {
this.$emit("input", value);
}
}
};
</script>
<style lang="scss" scoped></style>
my call for component in parent
<base-radio
is_required
v-model="objModel.title"
:arrRadioOptions="arrTitle"
></base-radio>
I actually fixed this back then, sorry i did not posted here let me post now so it may help someone need this.
<template>
<div>
<q-file
:value="files"
@input="updateFiles"
:label="label"
outlined
multiple
:clearable="!isUploading"
>
<template v-slot:file="{ index, file }">
<q-chip
class="full-width q-my-xs"
:removable="isUploading && uploadProgress[index].percent < 1"
square
@remove="cancelFile(index)"
>
<q-linear-progress
class="absolute-full full-height"
:value="uploadProgress[index].percent"
:color="uploadProgress[index].color"
track-color="grey-2"
/>
<q-avatar>
<q-icon :name="uploadProgress[index].icon" />
</q-avatar>
<div class="ellipsis relative-position">
{{ file.name }}
</div>
<q-tooltip>
{{ file.name }}
</q-tooltip>
</q-chip>
</template>
<template v-slot:after v-if="canUpload">
<q-btn
color="primary"
dense
icon="cloud_upload"
round
@click="upload"
:disable="!canUpload"
:loading="isUploading"
/>
</template>
</q-file>
</div>
<!--
<div class="col-4 q-pa-sm">
<q-uploader
url="http://localhost:30035/uploads"
label="Upload files"
color="purple"
square
flat
bordered
/>
</div>
</div>
-->
</template>
<script>
import api from "@/api";
import axios from "axios";
export default {
name: "Uploader",
props: {
type: {
type: String,
default: ""
}
},
data() {
return {
files: null,
uploadProgress: [],
uploading: null
};
},
computed: {
label() {
return "Upload your " + this.type;
},
isUploading() {
return this.uploading !== null;
},
canUpload() {
return this.files !== null;
}
},
methods: {
cancelFile(index) {
this.uploadProgress[index] = {
...this.uploadProgress[index],
error: true,
color: "orange-2"
};
},
async updateFiles(files) {
this.files = files;
if (this.files.length) {
let objFile = this.files[0];
if (this.type == "Video") {
if (objFile.type.indexOf("video/") !== 0) {
this.$q.notify({
color: "red-5",
textColor: "white",
icon: "warning",
message: "Please select a valid VIDEO to upload."
});
return false;
event.preventDefault();
}
} else {
if (objFile.type.indexOf("image/") !== 0) {
this.$q.notify({
color: "red-5",
textColor: "white",
icon: "warning",
message: "Please select a valid IMAGE to upload."
});
return false;
event.preventDefault();
}
}
this.uploadProgress = (files || []).map(file => ({
error: false,
color: "green-2",
percent: 0,
icon:
file.type.indexOf("video/") === 0
? "movie"
: file.type.indexOf("image/") === 0
? "photo"
: file.type.indexOf("audio/") === 0
? "audiotrack"
: "insert_drive_file"
}));
}
},
upload() {
clearTimeout(this.uploading);
const config = {
headers: {
"Content-Type": "multipart/form-data"
},
onUploadProgress: progressEvent => {
console.log(progressEvent.loaded);
this.uploadProgress[0].error = false;
this.uploadProgress[0].color = "green-2";
var percent = progressEvent.loaded / progressEvent.total;
this.uploadProgress[0].percent = percent;
console.log(
"Progress:",
progressEvent.loaded,
"/",
progressEvent.total,
percent + "%"
);
}
};
var file = this.files[0];
//var fileName = file.name;
var strType = this.type;
var formData = new FormData();
formData.append("file", file);
// You should have a server side REST API
var _this = this;
axios
.post(api.getAPIBaseUrl() + "/uploads", formData, config)
.then(function(objResponse) {
objResponse.data.strType = strType;
console.log("SUCCESS!!", objResponse.data);
_this.$emit("uploaded", objResponse.data);
})
.catch(function(err) {
console.log("FAILURE!!", err);
_this.$emit("uploaded", err);
});
}
/*
__updateUploadProgress() {
let done = true;
this.uploadProgress = this.uploadProgress.map(progress => {
if (progress.percent === 1 || progress.error === true) {
return progress;
}
const percent = Math.min(1, progress.percent + Math.random() / 10);
const error = percent < 1 && Math.random() > 0.95;
if (error === false && percent < 1 && done === true) {
done = false;
}
return {
...progress,
error,
color: error === true ? "red-2" : "green-2",
percent
};
});
this.uploading =
done !== true ? setTimeout(this.__updateUploadProgress, 300) : null;
}
*/
},
beforeDestroy() {
clearTimeout(this.uploading);
}
};
</script>
in express
app.post('/uploads', function (req, res) {
if (!req.files || Object.keys(req.files).length === 0) {
return res.status(400).send('No files were uploaded.');
}
// The name of the input field (i.e. "objFile") is used to retrieve the uploaded file
let objFile = req.files[Object.keys(req.files)[0]]; //returns 'someVal'
objFile.name = objFile.md5 + "." + mime.getExtension(objFile.mimetype);
console.log("objFile is ", objFile);
// Use the mv() method to place the file somewhere on your server
objFile.mv(__dirname + '/uploads/' + objFile.name, function (err) {
if (err) {
res.status(500).json({ blnOK: false, msg: err.message });
}
var objResponse = {};
objResponse.blnOK = true;
objResponse.objFile = objFile;
res.json(objResponse);
});
});
please note i am using “express-fileupload” for file uploading
Hello
I am new to quasar and will appreciate if someone can help on this.
I am using the q-file-picker component like this
<template>
<div class="q-pa-md column items-start q-gutter-y-md">
<q-file
:value="files"
@input="updateFiles"
label="Pick files"
outlined
multiple
:clearable="!isUploading"
style="max-width: 400px"
>
<template v-slot:file="{ index, file }">
<q-chip
class="full-width q-my-xs"
:removable="isUploading && uploadProgress[index].percent < 1"
square
@remove="cancelFile(index)"
>
<q-linear-progress
class="absolute-full full-height"
:value="uploadProgress[index].percent"
:color="uploadProgress[index].color"
track-color="grey-2"
/>
<q-avatar>
<q-icon :name="uploadProgress[index].icon" />
</q-avatar>
<div class="ellipsis relative-position">
{{ file.name }}
</div>
<q-tooltip>
{{ file.name }}
</q-tooltip>
</q-chip>
</template>
<template v-slot:after v-if="canUpload">
<q-btn
color="primary"
dense
icon="cloud_upload"
round
@click="upload"
:disable="!canUpload"
:loading="isUploading"
/>
</template>
</q-file>
</div>
<!--
<div class="col-4 q-pa-sm">
<q-uploader
url="http://localhost:30035/uploads"
label="Upload files"
color="purple"
square
flat
bordered
/>
</div>
</div>
-->
</template>
<script>
import api from "../../api";
export default {
data() {
return {
files: null,
uploadProgress: [],
uploading: null
};
},
computed: {
isUploading() {
return this.uploading !== null;
},
canUpload() {
return this.files !== null;
}
},
methods: {
cancelFile(index) {
this.uploadProgress[index] = {
...this.uploadProgress[index],
error: true,
color: "orange-2"
};
},
async updateFiles(files) {
this.files = files;
this.uploadProgress = (files || []).map(file => ({
error: false,
color: "green-2",
percent: 0,
icon:
file.type.indexOf("video/") === 0
? "movie"
: file.type.indexOf("image/") === 0
? "photo"
: file.type.indexOf("audio/") === 0
? "audiotrack"
: "insert_drive_file"
}));
},
async upload() {
clearTimeout(this.uploading);
const allDone = this.uploadProgress.every(
progress => progress.percent === 1
);
var file = this.files[0];
var fileName = file.name;
const objResponse = await api.uploadFile(file);
console.log("objResponse in app is ", objResponse);
this.uploadProgress = this.uploadProgress.map(progress => ({
...progress,
error: false,
color: "green-2",
percent: allDone === true ? 0 : progress.percent
}));
let done;
this.uploading =
done !== true ? setTimeout(this.__updateUploadProgress, 300) : null;
},
__updateUploadProgress() {
let done = true;
this.uploadProgress = this.uploadProgress.map(progress => {
if (progress.percent === 1 || progress.error === true) {
return progress;
}
const percent = Math.min(1, progress.percent + Math.random() / 10);
const error = percent < 1 && Math.random() > 0.95;
if (error === false && percent < 1 && done === true) {
done = false;
}
return {
...progress,
error,
color: error === true ? "red-2" : "green-2",
percent
};
});
this.uploading =
done !== true ? setTimeout(this.__updateUploadProgress, 300) : null;
}
},
beforeDestroy() {
clearTimeout(this.uploading);
}
};
</script>
and in my express code i am doing like this
app.post('/uploads', function (req, res) {
if (!req.files || Object.keys(req.files).length === 0) {
return res.status(400).send('No files were uploaded.');
}
// The name of the input field (i.e. "sampleFile") is used to retrieve the uploaded file
let sampleFile = req.files[Object.keys(req.files)[0]]; //returns 'someVal'
console.log("sampleFile is ", sampleFile);
// Use the mv() method to place the file somewhere on your server
sampleFile.mv(__dirname + '/uploads/' + sampleFile.name, function (err) {
if (err)
return res.status(500).send(err);
res.send('File uploaded!');
});
});
I am not able to connect the both, the express code works ok with q-uploader but i would like to use q-file-picker as above for my project…
can someone please help.
Thanks
GS
i have now figured out you need to import like this Quasar.utils.exportFile
import { exportFile } from Quasar.utils.exportFile;
might help someone who have this issue…
Hello i am trying to import an exportFile component like this in a standalone quasar configuration on my existing project but it does not work…
<script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/quasar@1.12.2/dist/quasar.umd.min.js"></script>
<script>
import { exportFile } from 'quasar';
function wrapCsvValue (val, formatFn) {
let formatted = formatFn !== void 0
? formatFn(val)
: val
formatted = formatted === void 0 || formatted === null
? ''
: String(formatted)
formatted = formatted.split('"').join('""')
/**
* Excel accepts \n and \r in strings, but some other CSV parsers do not
* Uncomment the next two lines to escape new lines
*/
// .split('\n').join('\\n')
// .split('\r').join('\\r')
return `"${formatted}"`
}
new Vue({
el: '#q-app',
data: function () {
return {
loading: false,
filter: "",
arrData: [],
Can somebody please advise the right way to do it as i could not find it in the docs…
Thanks
gs
Use a VMWare VM with macOS and install xcode on it. Experience will be a bit laggy but it does the job.
Nevermind, i have figured out and developed my own component in case someone needs below is the code…
Install: npm i shaka-player
<template>
<video
ref="shakaVideo"
:width="width"
:height="height"
poster="//shaka-player-demo.appspot.com/assets/poster.jpg"
controls
></video>
</template>
<script>
import * as shaka from "shaka-player";
export default {
name: "ShakaPlayer",
props: {
manifestUri: {
type: String
},
width: {
type: String,
default: "200px"
},
height: {
type: String,
default: "100%"
}
},
data() {
return {};
},
mounted() {
// Install built-in polyfills to patch browser incompatibilities.
shaka.polyfill.installAll();
// Check to see if the browser supports the basic APIs Shaka needs.
if (shaka.Player.isBrowserSupported()) {
// Everything looks good!
// Create a Player instance.
var video = this.$refs.shakaVideo;
var player = new shaka.Player(video);
// Attach player to the window to make it easy to access in the JS console.
window.player = player;
// Listen for error events.
player.addEventListener("error", onErrorEvent);
// Try to load a manifest.
// This is an asynchronous process.
player
.load(this.manifestUri)
.then(function() {
// This runs if the asynchronous load is successful.
console.log("The video has now been loaded!");
})
.catch(onError); // onError is executed if the asynchronous load fails.
} else {
// This browser does not have the minimum set of APIs we need.
alert("Browser not supported!");
}
function onErrorEvent(event) {
// Extract the shaka.util.Error object from the event.
onError(event.detail);
}
function onError(error) {
// Log the error.
console.log("Error code: ", error.code, ", object: ", error);
}
}
};
</script>
Hello all
Has anyone tried integrating shaka-player in quasar…
If yes, can you please share a sample version of code?
Thanks
i have found the answer for my question i think i needed this command
quasar dev -m cordova -T android
Thanks for your help…
Hello thanks for your response…
What if I have cordova plugins like onesignal that require building of the mobile app everytime to debug?
Thanks
Hello
I have a quasar app with some cordova plugins like onesignal, camera etc.
Currently, I have to rebuild the app everytime I make changes to debug.
Is there a live reload solution available in quasar?
Thank you in advance…