SlideShare ist ein Scribd-Unternehmen logo
1 von 92
Downloaden Sie, um offline zu lesen
Dept. of Smart Finance, Korea Polytechnics Seoul Kangseo Campus
ApplicationDevelopmentw/
QuasarFramework
Basic Course
QuasarCLIInstallation
• Prerequisite


Node >=12.22.1 and NPM >=6.14.12


• recommendation node version : v14.17.5


check your node and npm : node -v


npm -v


• npm install -g @quasar/cli
Do not use uneven versions of Node i.e. 13, 15, etc. These versions are not tested with Quasar and often cause issues due to their experimental nature. We highly recommend always using the LTS version of Node.
Ref : https://quasar.dev/quasar-cli/installation
HelloworldⅠ(1/2)
•  we create a project folder with Quasar CLI


• quasar create <folder_name>
Ref : https://quasar.dev/quasar-cli/installation
(base) waynehwang@wayneui-MacBookPro temp % quasar create hello


___


/ _  _ _ __ _ ___ __ _ _ __


| | | | | | |/ _` / __|/ _` | '__|


| |_| | |_| | (_| __  (_| | |


_____,_|__,_|___/__,_|_|




? Project name (internal usage for dev) hello


? Project product name (must start with letter if building mobile apps) hello


? Project description hello world


? Author wayne hwang <wonyong@wonyong.net>


? Pick your CSS preprocessor: SCSS


? Check the features needed for your project: ESLint (recommended), Vuex, Axios


? Pick an ESLint preset: Prettier


? Continue to install project dependencies after the project has been created? (


recommended) NPM


Quasar CLI · Generated "hello".


[*] Installing project dependencies …


[*] Quasar Project initialization finished!


To get started:


cd hello


quasar dev
Helloworld Ⅰ(2/2)
• Look into package.json, App.vue, routes.js, Index.vue, EssentialLink.vue, …


• Run your app with below command:


quasar dev
HelloWorldⅡ
• Repository address :


https://github.com/wonyongHwang/kopoPro
fi
le


• git clone https://github.com/wonyongHwang/kopoPro
fi
le


• npm install


• quasar dev
kopoProfile
HelloWorldⅡ
• In this practice, we don’t have a


drawer and a footer either. So, only


<q-header> is being a
ff
ected by


<q-layout>.


•
layout
<q-layout view="lHh lpr lFf">
reference : https://quasar.dev/layout/layout#understanding-the-view-prop
HelloWorldⅡ
• quasar can detect platform : $q.platfrom.is.~~




eg> if you will deploy app to mobile device(android,


ios) app can detect platform using $q.platform.is.


cordova
$q.platform
<div v-bind:class="{'main': $q.platform.is.desktop, 'mobile_main': $q.platform.is.ipad || $q.platform.is.mobile}"


class="full-height" style="background-color:rgba(0, 0, 0, 0.7);">
reference : https://quasar.dev/options/platform-detection#introduction
HelloWorldⅡ
style
<q-header class="q-py-sm" style="background-color:rgba(0, 0, 0, 0.7);">
reference : https://quasar.dev/style/spacing#table-of-permutations
HelloWorldⅡ
q-tab
reference : https://quasar.dev/vue-components/tabs
<q-tabs v-model="selected_tab" shrink>


<q-tab name="about_me" :style="[selected_tab == 'about_me' ? {backgroundColor: 'green'} : {}]" class="q-mr-sm q-py-xs custom_tab"


@click="scrollToElement('id_about_me')" style="width:120px;min-height:auto !important;color: white"


label="About Me"/>
HelloWorldⅡ
q-card
<q-card class="my-card" flat bordered>


<q-card-section>
reference : https://quasar.dev/vue-components/card#introduction
HelloWorldⅡ
• Get/set scroll position (Quasar Scrolling Utils)


https://quasar.dev/quasar-utils/scrolling-utils#get-set-scroll-position
<script></script>
import {scroll} from 'quasar'


const {getScrollTarget, setScrollPosition} = scroll


export default {


name: 'PageIndex',


data() {


return {


name: "",


email: "",


message: "",


selected_tab: 'about_me',


}


},


methods: {


scrollToElement(id) {


let el = document.getElementById(id)


const target = getScrollTarget(el)


const o
ff
set = el.o
ff
setTop - 65


const duration = 800


setScrollPosition(target, o
ff
set, duration)


}


},


mounted () {


}


}
homework
• customizing web page


• upload source to your github repo.


- README.md should be edited
ex>
homework
• deploy your web pages via netlify


https://app.netlify.com/
homework
• check url


• if you have a own domain, netlify allow you to access your web site


• ‘https(let’s encrypt)’ supports both custom domain and netlify domain
Make Your First Page
Basic Practice
Layout
• quasar create <folder name>


• quasar dev


•
fi
rst page is served by Index.vue


Layout
• Quasar provides basic layouts
reference : https://quasar.dev/layout/gallery
SignIn
• what you need to implement a sign-in page:


2 Input Text
fi
eld


1 Check Box


1 Button


and more …
SignIn
• copy relevant codes and paste to your “Index.vue”


https://quasar.dev/vue-components/input
SignUp
• add Signup.Vue to your project


• add page mapping on routes.js
pagelink
• vue syntax for page link :


<router-link to=“/address”> ~~ </router-link>
<router-link to="/signup" >


<center>New User? Click Here to Register.</center>


</router-link>
Homework
• Place and Organize Input Text
fi
elds (E-mail, Password, etc …)


: center alignment


• Password should be masked while typing


• Place Sign-In / Sign-Up buttons
complete your sign-in / sign-up pages!
f
irebase
• https://
fi
rebase.google.com/?hl=ko
create a project
// For Firebase JS SDK v7.20.0 and later, measurementId is optional


const
fi
rebaseCon
fi
g = {


apiKey: "AIzaSyA~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~",


authDomain: "kopologinchecker.
fi
rebaseapp.com",


projectId: "kopologinchecker",


storageBucket: "kopologinchecker.appspot.com",


messagingSenderId: "17~~~~~~~~~~~~",


appId: "1:17~~~~~~~~:web:d4~~~~~~~~",


measurementId: “G-H0~~~~~~~~~~~~"


};
• npm install --save
fi
rebase


• quasar new boot
fi
rebase


->
fi
rebase.js will be generated in src/boot


-> paste
fi
rebase con
fi
guration to
fi
rebase.js
f
irebase
setting config.
ref : https://quasar.dev/quasar-cli/boot-
fi
les
import firebase from 'firebase/app';


import 'firebase/auth';


import 'firebase/analytics'


const firebaseConfig = {


apiKey: "~",


authDomain: "kopologinchecker.firebaseapp.com",


projectId: "kopologinchecker",


storageBucket: "kopologinchecker.appspot.com",


messagingSenderId: “~",


appId: "~",


measurementId: "~"


};


if (!firebase.apps.length) {


firebase.initializeApp(firebaseConfig);


}


firebase.analytics();


export const auth = firebase.auth();
f
irebase
• enable email/password


• create a test user if needed
sign-in method
f
irebase
• https://
fi
rebase.google.com/docs/auth/web/start?hl=ko
sign-in method
fi
rebase.auth().signInWithEmailAndPassword(email, password
)

  .then((userCredential) =>
{

    // Signed i
n

    var user = userCredential.user
;

    // ..
.

  }
)

  .catch((error) =>
{

    var errorCode = error.code
;

    var errorMessage = error.message
;

  });
• let’s use quasar notify to show success/fail message


https://quasar.dev/quasar-plugins/notify#introduction
f
irebase
sign-in method
auth.signInWithEmailAndPassword(this.text, this.password).then(


(userCredential) => {


console.log(userCredential.user);


this.$router.push({ path: 'home' })


}


).catch(


(err) => {


console.log(err.code);


console.log(err.message);


this.$q.notify({


message: err.message,


color: 'purple'


})


}


)


message, color, postion, textColor, icon, …
import { useQuasar } from 'quasar'


const $q = useQuasar()


$q.notify({


message : "login success",


color : "blue"


})
vue 3
homework
• implement a sign-up function using
fi
rebase api


• validation logic should be implemented


ex> email/password should not be empty


password should be equal to ‘repeat password’


password must be at least 6 characters long


hint> https://levelup.gitconnected.com/
fi
rebase-auth-management-in-vue-js-with-vuex-9c4a5d9cedc


• move page after sign-up


hint> this.$router.push({ path: 'home' })
import { useRouter, useRoute } from 'vue-router'
export default
{

setup()
{

const router = useRouter()
const route = useRoute()
// Now you can access params like
:

console.log(route.params.id)
;

route.push({path: ‘home’}
)

}

};
vue v3
https://next.router.vuejs.org/guide/advanced/composition-api.html#accessing-the-router-and-current-route-inside-setup
• Parent -> child : props


• Child -> Parent : emit
management
f
irebaseauthw/vuex
• state management pattern and its library


• state : data


• mutations : change state (sync)


• actions : commit mutation (async)
what vuex is
Actions
State
View
Mutations
this.$store.commit


emit, props
Unidirectional
fl
ow
management
f
irebaseauthw/vuex
• state =
fi
re auth info


• ‘
fi
re auth info’ can acquire when we call


signInWithEmailAndPassword()


createUserWithEmailAndPassword()


and so on.
state
Actions
State
View
Mutations
this.$store.commit


import {auth} from "src/boot/firebase"


export default store(function (/* { ssrContext } */) {


const Store = createStore({


modules: {


// example


},


state: {


fireUser:null


},


…
State
management
f
irebaseauthw/vuex
• get the current sign-in user is by setting an observer on the Auth object


https://
fi
rebase.google.com/docs/auth/web/manage-users


• state should be null when user signed out


https://
fi
rebase.google.com/docs/auth/web/password-auth?hl=ko
action
actions: {


signOutAction({commit}) {


auth.signOut()


.then(() => {


commit("setFireUser", null);


})


},


authAction({ commit }) {


auth.onAuthStateChanged(user => {


if (user) {


commit("setFireUser", user);


}


});


},


},


mutations: {


setFireUser(state, firebaseUser){


state.fireUser = firebaseUser


}
Actions
Mutations
management
f
irebaseauthw/vuex
• prepare helper functions


https://joshua1988.github.io/web-development/vuejs/vuex-getters-mutations/
getters
getters: {


getFireUser(state) {


return state.fireUser;


},


isUserAuth(state) {


return !!state.fireUser;


}


},
management
f
irebaseauthw/vuex
source code
import { store } from 'quasar/wrappers'


import { createStore } from 'vuex'


import {auth} from "src/boot/firebase"


export default store(function (/* { ssrContext } */) {


const Store = createStore({


state: {


fireUser:null


},


actions: {


signOutAction({commit}) {


auth.signOut()


.then(() => {


commit("setFireUser", null);


})


.catch(error => {


commit("setFireError", error.message);


});


},


authAction({ commit }) {


auth.onAuthStateChanged(user => {


if (user) {


commit("setFireUser", user);


} else {


commit("setFireUser", null);


}


});


},


},


getters: {


getFireUser(state) {


return state.fireUser;


},


isUserAuth(state) {


return !!state.fireUser;


}


},


mutations: {


setFireUser(state, firebaseUser){


state.fireUser = firebaseUser


}


},


})


return Store


})
management
f
irebaseauthw/vuex
• commit state when my application obtain a
fi
rebase auth


• get a
fi
rebase auth to display user info


• check a
fi
rebase auth
usage example
auth.signInWithEmailAndPassword(this.text, this.password).then(


(userCredential) => {


this.$store.commit("setFireUser", userCredential.user);


}


)
<div class="text-h6" align="center">


Hi, {{ this.name }}({{ getFireUser.email }})


<br>


…


computed: {


...mapGetters(["getFireUser", "isUserAuth"])


},


mounted() {


this.authAction();


…


methods: {


...mapActions(["signOutAction","authAction"]),
import { useStore } from "vuex"
;

export default
{

setup()
{

const store = useStore()
;

 

store.commit("setFireUser", userCredential.user)
;

}

};
vue v3
https://kyounghwan01.github.io/blog/Vue/vue3/composition-api-vuex/#vuex-%E1%84%89%E1%85%A6%E1%84%90%E1%85%B5%E1%86%BC-%E1%84%86%E1%85%B5%E1%86%BE-store-module-1%E1%84%80%E1%85%A2%E1%84%85%E1%85%A9-%E1%84%89%E1%85%B5%E1%86%AF%E1%84%92%E1%85%A2%E1%86%BC
homework
• When a user logged in, move Vue Page and display user’s email using vuex


• tip>


<div v-if=“getFireUser">~~</div>


computed: {


...mapGetters(["getFireUser", "isUserAuth"])


},


<div class="text-h6" align="center">


Hi,({{ getFireUser.email }})


</div>


import { mapGetters } from "vuex";
vuelifecycle
• https://cornswrold.tistory.com/342


• beforeCreate, created, beforeMount, mounted,


beforeUpdate, updated, beforeDestroy, destroyed
Firestore
Firestore
Firestore
• Firestore data add: set() or add()


https://
fi
rebase.google.com/docs/
fi
restore/manage-data/add-data?hl=ko
API
db.collection("users").add({


id: this.text,


name: this.name


})


.then((docRef) => {


console.log("Document written with ID: ", docRef.id);


this.$q.notify({


message: "Register Success",


color: 'blue'


})


})


.catch((error) => {


console.error("Error adding document: ", error);


this.$q.notify({


message: error,


color: 'red'


})


});
Firestore
•
fi
rebase.js


import '
fi
rebase/
fi
restore'


export const db =
fi
rebase.
fi
restore();


• import


import { db } from "src/boot/
fi
rebase"
Preparations
Firestore
Data write
db.collection("users").add({


id: this.text,


name: this.name


})


.then((docRef) => {


console.log("Document written with ID: ", docRef.id);


})


.catch((error) => {


console.error("Error adding document: ", error);


});
Firestore
Data read
db.collection("users").where("id", "==", this.getFireUser.email )


.get()


.then((querySnapshot) => {


querySnapshot.forEach((doc) => {


// doc.data() is never undefined for query doc snapshots


console.log(doc.id, " => ", doc.data());


this.name = doc.data().name


});


})


.catch((error) => {


console.log("Error getting documents: ", error);


});
Homework
• When a user logged in, move page(/home) and display user’s name using vuex


- user name was saved at Firestore, so we have to read the data
fi
rst to show it.


• user name should be displayed on page(/home) even after refreshing page.
Homework
Hint
<template>


<div>


HOME


<div class="text-h6" align="center">


<div v-if="getFireUser">


Hi,({{ getFireUser.email }})


:) {{ name }}


</div>


</div>


</div>


</template>
<script>


import { defineComponent } from 'vue';


import { auth, db } from "src/boot/firebase"


import { useQuasar } from 'quasar'


import { mapGetters, mapActions } from "vuex"; //


export default defineComponent({


name: 'PageIndex',


computed: {


...mapGetters(["getFireUser", "isUserAuth"])


},


updated() {




if(this.getFireUser != null && this.name == ''){ // for refresh page //


db.collection("users").where("id", "==", this.getFireUser.email )


.get()


.then((querySnapshot) => {


querySnapshot.forEach((doc) => {


// doc.data() is never undefined for query doc snapshots


console.log(doc.id, " => ", doc.data());


this.name = doc.data().name


});


})


.catch((error) => {


console.log("Error getting documents: ", error);


});


}


},


mounted(){ //


this.authAction() // for refresh page //


if(this.getFireUser != null){


db.collection("users").where("id", "==", this.getFireUser.email )


.get()


.then((querySnapshot) => {


querySnapshot.forEach((doc) => {


// doc.data() is never undefined for query doc snapshots


console.log(doc.id, " => ", doc.data());


this.name = doc.data().name


});


})


.catch((error) => {


console.log("Error getting documents: ", error);


});


}


},


data(){


return{


name : ''


}


},




methods: {


...mapActions(["signOutAction","authAction"])






}


})


</script>
f
irebaseusermgmt.
• https://
fi
rebase.google.com/docs/auth/web/manage-users?hl=ko


• User Info management


- user info update


- user account delete
Some security-sensitive actions—such as deleting an account, setting a primary email address, and changing a password—require that the user has recently signed in. 
Implementationof“rememberme”usinglocalStorage
• UI


<q-checkbox v-model="remember" label="Remember Me" color="teal"/>


• Declaration


let remember = ref(‘false')


• mounted()


• When a user tries to log in: if (remember.value == true) {


localStorage.username = email.value;


localStorage.checkbox = remember.value;


} else {


localStorage.username = "";


localStorage.checkbox = "";


}


mounted(){


if(localStorage.checkbox && localStorage.checkbox !==""){


this.remember = true


this.email = localStorage.username


} else {


this.remember = false


}


}
Implementationof“rememberme”usinglocalStorage
• Test
Homework
• Elaborate your work(home/sign-in/sign-up)


• Conceptualizing your idea
OAuth
• https://
fi
rebase.google.com/docs/auth/web/google-signin?hl=ko


•
google
OAuth
• https://
fi
rebase.google.com/docs/auth/web/facebook-login?hl=ko


• https://developers.facebook.com/apps


• Only https allowed
Facebook
OAuth
GitHub
https://github.com/settings/apps
Local
Firebase
github
f
irebasehosting
f
irebasehosting
• Hosting settings
f
irebasehosting
• Login results
f
irebasehosting
• Select hosting …
f
irebasehosting
• Public directory : dist/spa
f
irebasehosting
•
fi
rebase serve


• quasar build


•
fi
rebase deploy
f
irebasehosting
• Deploy results…
Favicon
• https://favicon.io/favicon-generator/
Menu
• components hierarchy


⎯ MainLayout.vue


EssentialLink.vue
props and emit
icon title


label
link
+
<template>


<q-item clickable tag="a" target="_blank" :href="link">


<q-item-section v-if="icon" avatar>


<q-icon :name="icon" />


</q-item-section>


<q-item-section>


<q-item-label>{{ title }}</q-item-label>


<q-item-label caption> {{ caption }} </q-item-label>


</q-item-section>


</q-item>


</template>


<script>


import { defineComponent } from 'vue'


export default defineComponent({


name: 'EssentialLink',


props: {


title: {


type: String,


required: true


},


caption: {


type: String,


default: ''


},


link: {


type: String,


default: '#'


},


icon: {


type: String,


default: ''


}


}


})


</script>
props : hey, parent component! control me
Menu
• components hierarchy


⎯ MainLayout.vue


EssentialLink.vue
props and emit
<EssentialLink v-for="link in essentialLinks" :key="link.title" v-bind="link" />


…


import EssentialLink from 'components/EssentialLink.vue'


const linksList = [


{


title: 'Docs',


caption: 'quasar.dev',


icon: 'school',


link: 'https://quasar.dev'


},


…


export default defineComponent({


name: 'MainLayout',


components: {


EssentialLink


},




setup () {


return {


essentialLinks: linksList,


}


}


…
parent component(MainLayout) now can set child props
Menu
• <Practice>


- open internal links in a current window


- open external links in a new tab (or window)
props and emit
Menu
• <Practice> child component(EssentialLink) modi
fi
cation


props





template
props and emit
external: {


type: Boolean,


default: false


}
<template>


<!-- <router-link :to="link" style="text-decoration: none"> -->


<section v-if="external">


<q-item clickable tag="a" target="_target" :href="link">


…


</q-item>


</section>


<section v-else>


<router-link :to="link" style="text-decoration: none; color: inherit;”>


…


</router-link>


</section>


</template>
Menu
• <Practice> parent component(MainLayout) modi
fi
cation


props and emit
const linksList = [


{


title: 'Home',


caption: 'Home',


icon: 'home',


link: '/home'


},


{


title: 'QR Scanner',


caption: 'QR Check for Admin',


icon: 'qr_code_scanner',


link: 'https://kopologinchecker.web.app/#/qrscanner',


external: true


},


…
Menu
• <Practice>


- close menu when a external link is clicked
props and emit
emit : hey, parent component! handle this
Menu
• <Practice> child component(EssentialLink)
modi
fi
cation


template





methods
props and emit
<q-item clickable tag="a" target="_target" :href="link" @click="sendEvent()">
methods: {


sendEvent() {


this.$emit('closeDrawer');


console.log("emit emit")


}


},
• <Practice> parent component(MainLayout)
modi
fi
cation


template





methods
<EssentialLink v-on:closeDrawer="closeme()"


v-for="link in essentialLinks" :key="link.title" v-bind="link" />
methods: {


closeme() {


console.log('event received');


this.leftDrawerOpen = false;


}


},
q-table
• https://quasar.dev/vue-components/table
Homework
• save user login timestamps to
fi
restore


• display user login info (w/ timestamp)
build your own table
q-table
• save user data to Firestore


var cdate = Date.now()


// firestore insert => then we can get doc id to generate qr code


db.collection("qrgen").add({


date: cdate,


id: this.getFireUser.email,


status: this.sliderValue //this.group


})


.then((docRef) => {


// console.log("Document written with ID: ", docRef.id);




})


.catch((error) => {


console.error("Error adding document: ", error);


});
q-table
• basic layout
<section v-if="!onloading">


<q-table :title="date" :rows="rows" :columns="columns" row-key="no" v-model:pagination="pagination" :filter="filter">


</q-table>


</section>
‘onloading’ set to be false when data is completely loaded data() {


return {


pagination: {


sortBy: 'time',


descending: false,


rowsPerPage: 15, // current rows per page being displayed




},


date: '2019/02/01',


filter : '',


columns : [


{


name: 'no',


required: true,


label: 'SID',


align: 'left',


field: row => row.no,


format: val => `${val}`,


sortable: true


},


{ name: 'name', align: 'left', label: 'Name', field: 'name', sortable: true },


{ name: 'time', align: 'left', label: 'Check-In Time', field: 'time', sortable: true },


{ name: 'temperature', label: 'Temperature', field: 'temperature', sortable: true }


],


rows : [ ],


cnt : 1,


onloading : true


}


},
q-table
data load
dataLoad: function () {


this.cnt = 1


var now = new Date();


var startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate());


var timestamp = startOfDay / 1;


db.collection("checkin").where("time", ">=", timestamp) // 오늘 체크인만 확인


.onSnapshot((snapshot) => {


snapshot.docChanges().forEach((change) => {


if (change.type === "added") {


var tempRow = {name: '', time:'', temperature:''}


tempRow.name = change.doc.data().name


const getTime = (timeStamp, offset) => {


let d = new Date((timeStamp + offset));


var hour = d.getHours()


var min = d.getMinutes()


var sec = d.getSeconds()


if (hour < 10) { hour = "0" + hour; }


if (min < 10) { min = "0" + min; }


if (sec < 10) { sec = "0" + sec; }


let ret = (d.getMonth()+1)+ "/"+(d.getDate())+ " "+hour+ ":"+min+":"+sec


return ret


}


tempRow.time = getTime(change.doc.data().time,0)


tempRow.no = this.cnt


this.cnt++


tempRow.temperature = change.doc.data().temperature


this.rows.push(tempRow)


}


});


});


this.onloading = false


} // end of dataLoad
ref : https://
fi
rebase.google.com/docs/
fi
restore/query-data/listen?hl=ko
q-table
• additional function - search
<section v-if="!onloading">


<q-table :title="date" :rows="rows" :columns="columns" row-key="no" :pagination.sync="pagination" :filter="filter">


<template v-slot:top-right>


<q-input borderless dense debounce="300" v-model="filter" placeholder="Search">


<template v-slot:append>


<q-icon name="search"></q-icon>


</template>


</q-input>


</template>


</q-table>


</section>
q-table
• additional function - date picker
<template v-slot:top-left>


<div class="q-pa-md" style="width: 150px; margin-top: 20px">


<q-input borderless dense debounce="300" v-model="date" mask="date" :rules="['date']">


<template v-slot:append>


<q-icon name="event" class="cursor-pointer">


<q-popup-proxy ref="qDateProxy" transition-show="scale" transition-hide="scale">


<q-date v-model="date">


<div class="row items-center justify-end">


<q-btn v-close-popup label="Close" color="primary" flat @click="datePicked()"></q-btn>


</div>


</q-date>


</q-popup-proxy>


</q-icon>


</template>


</q-input>


</div>


</template>


should be coded between <q-table> and </q-table>
q-table
• additional function


- date picker
datePicked(){


this.cnt = 1


this.rows = []


var yyyyMMdd = String(this.date);


var sYear = yyyyMMdd.substring(0,4);


var sMonth = yyyyMMdd.substring(5,7);


var sDate = yyyyMMdd.substring(8,10);


var startOfDay = new Date(Number(sYear), Number(sMonth)-1, Number(sDate));


var timestamp = startOfDay / 1;


var timestampp1d = timestamp + 86400000


db.collection("users").where("date", ">=", timestamp).where("date", "<", timestampp1d)


.get()


.then((querySnapshot) => {


querySnapshot.forEach((doc) => {


var tempRow = {name: '', time:'', temperature:''}


tempRow.name = doc.data().email


const getTime = (timeStamp, offset) => {


let d = new Date((timeStamp + offset));


console.log(d)


var hour = d.getHours()


var min = d.getMinutes()


var sec = d.getSeconds()


if (hour < 10) { hour = "0" + hour; }


if (min < 10) { min = "0" + min; }


if (sec < 10) { sec = "0" + sec; }


let ret = (d.getMonth()+1)+ "/"+(d.getDate())+" "+hour+ ":"+min+":"+sec


return ret


}


tempRow.time = getTime(doc.data().date,0)


tempRow.no = this.cnt


this.cnt++


tempRow.name = doc.data().name


this.rows.push(tempRow)


});


})


.catch((error) => {


console.log("Error getting documents: ", error);


});


}
q-table
• additional function - csv export
<div align="right">


<q-btn


color="primary"


icon-right="archive"


label="Export to csv"


no-caps


@click="exportTable"


>


</q-btn>


</div>
exportTable () {


var columns = this.columns


var rows = this.rows


// naive encoding to csv format


const content = [columns.map(col => this.wrapCsvValue(col.label))].concat(


rows.map(row => columns.map(col => this.wrapCsvValue(


typeof col.field === 'function'


? col.field(row)


: row[ col.field === void 0 ? col.name : col.field ],


col.format


)).join(','))


).join('rn')


const status = exportFile(


'table-export.csv',


content,


'text/csv'


)


if (status !== true) {


$q.notify({


message: 'Browser denied file download...',


color: 'negative',


icon: 'warning'


})


}


},
q-table
• additional function - csv export
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}"`


},


import { exportFile } from 'quasar'
FirebaseSecurityRules
• https://khreniak.medium.com/cloud-
fi
restore-security-rules-basics-fac6b6bea18e
makeyourprivacypolicy
• https://www.privacy.go.kr/a3sc/per/inf/perInfStep01.do
checklicenses
• https://www.npmjs.com/package/license-checker
OSS(Open Source Software)
npm install -g license-checker


license-checker --csv --out ./licenses.csv
androidstudio
• install


• license package download after installation


https://devvkkid.tistory.com/204


• build


• run (w/ AVD manager)
cordova
• npm install -g cordova


• quasar dev -m android --ide


android studio error might be occurred :


“Installed Build Tools revision 31.0.0 is corrupted. Remove and install again using the SDK Manager.”


if you get above error, then you should modify version settings in your build.grade as below image











then type below command on your terminal (https://stackover
fl
ow.com/questions/68387270/android-studio-error-installed-build-tools-revision-31-0-0-is-corrupted)


cd ~/Library/Android/sdk/build-tools/31.0.0 && mv d8 dx && cd lib && mv d8.jar dx.jar


then close android studio and re-run “quasar dev -m android —ide"
cordova
• result
cordova
• quasar build -m cordova -T android


• brew install gradle
if you get a net error on simulator, then check you port in quasar.conf.js
cordova
• https://bottlecok.tistory.com/177
aab build
cordova
• quasar dev -m cordova -T ios


• quasar build -m cordova -T ios


• https://www.youtube.com/watch?v=P_Ox5s4anCI
ios
Vue3 tutorial
extra
BasicStructure
• setup is called between “before created” and “created”


• you can set a style whatever you want
step 1
<template>


<div class="test">


Hello World, {{ name }}


</div>


</template>


<script>


import { defineComponent } from 'vue';


export default defineComponent({


name: 'PageIndex',


setup() {


const name = "KOPO"


return {


name


}


}


})


</script>


<style lang="scss">


.test {


color: red;


background-color: yellow;


text-align: center;


font-size: 30px;




}


</style>
BasicStructure
• add function “printName”
add a function
<template>


<div class="test">


Hello World, {{ name }}


<p></p>


{{ printName() }}


</div>


</template>


<script>


import { defineComponent } from 'vue';


export default defineComponent({


name: 'PageIndex',


setup() {


const name = "KOPO"


const printName = () => {


return name + "!!"


}


return {


name,


printName


}


}


})


</script>
BasicStructure
• add a parameter : param


• call the function with parameter
add a parameter
<template>


<div class="test">


Hello World, {{ name }}


<p></p>


{{ printName(name) }}


</div>


</template>


<script>


import { defineComponent } from 'vue';


export default defineComponent({


name: 'PageIndex',


setup() {


const name = "KOPO"


const printName = (param) => {


return 'hello '+ param + "!!"


}


return {


name,


printName


}


}


})


</script>
BasicStructure
• we want to change name string when a button is clicked.


but, the result is …


• tip> button width dynamically can be set.


use $ref !
add a button
<template>


<div class="test" ref="topitem">


Hello World, {{ name }}


<p></p>


{{ printName(name) }}


</div>


<q-btn


@click="changeName"


class="button is-primary"


color="primary"

label="BUTTON"


:style="{width: itemWidth+'px'}" />


</template>


<script>


import { defineComponent, ref } from 'vue';


export default defineComponent({


name: 'PageIndex',


mounted() {


this.itemWidth = this.$refs.topitem.clientWidth


console.log(this.itemWidth)


},


setup() {


let name = "KOPO"


let itemWidth = ref(0)


const printName = (param) => {


return 'hello '+ param + "!!"


}


const changeName = () => {


name = "Button Clicked"


console.log("name chaged? ", name)


}


return {


name,


itemWidth,


printName,


changeName


}


}


})


</script>
<style lang="scss">


.test {


color: red;


background-color: yellow;


text-align: center;


font-size: 30px;


width: 300px;


}


</style>
BasicStructure
• “KOPO” —> ref(“KOPO”)


• name —> name.value
use ref to make the variable to be reactive
setup() {


let name = ref("KOPO")


let itemWidth = ref(0)


const printName = (param) => {


return 'hello '+ param + "!!"


}


const changeName = () => {


name.value = "Button Clicked"


console.log("name chaged? ", name)


}


if you use object or array data, use reactive(“~”) instead ref(“~”)

Weitere ähnliche Inhalte

Was ist angesagt?

Terraform Modules and Continuous Deployment
Terraform Modules and Continuous DeploymentTerraform Modules and Continuous Deployment
Terraform Modules and Continuous DeploymentZane Williamson
 
JWT-spring-boot-avancer.pdf
JWT-spring-boot-avancer.pdfJWT-spring-boot-avancer.pdf
JWT-spring-boot-avancer.pdfJaouad Assabbour
 
Net Framework vs .Net Core A Complete Comparison.pdf
Net Framework vs  .Net Core  A Complete Comparison.pdfNet Framework vs  .Net Core  A Complete Comparison.pdf
Net Framework vs .Net Core A Complete Comparison.pdfWPWeb Infotech
 
Observability and Management on OCI - Logging and Monitoring
Observability and Management on OCI - Logging and MonitoringObservability and Management on OCI - Logging and Monitoring
Observability and Management on OCI - Logging and MonitoringKnoldus Inc.
 
Programación reactiva con Vert.x
Programación reactiva con Vert.xProgramación reactiva con Vert.x
Programación reactiva con Vert.xFran García
 
ReactJS Tutorial For Beginners | ReactJS Redux Training For Beginners | React...
ReactJS Tutorial For Beginners | ReactJS Redux Training For Beginners | React...ReactJS Tutorial For Beginners | ReactJS Redux Training For Beginners | React...
ReactJS Tutorial For Beginners | ReactJS Redux Training For Beginners | React...Edureka!
 
Docker vs VM | | Containerization or Virtualization - The Differences | DevOp...
Docker vs VM | | Containerization or Virtualization - The Differences | DevOp...Docker vs VM | | Containerization or Virtualization - The Differences | DevOp...
Docker vs VM | | Containerization or Virtualization - The Differences | DevOp...Edureka!
 
What is Node.js | Node.js Tutorial for Beginners | Node.js Modules | Node.js ...
What is Node.js | Node.js Tutorial for Beginners | Node.js Modules | Node.js ...What is Node.js | Node.js Tutorial for Beginners | Node.js Modules | Node.js ...
What is Node.js | Node.js Tutorial for Beginners | Node.js Modules | Node.js ...Edureka!
 
Dot net platform and dotnet core fundamentals
Dot net platform and dotnet core fundamentalsDot net platform and dotnet core fundamentals
Dot net platform and dotnet core fundamentalsLalit Kale
 
Spring: Overview do framework mais popular para desenvolvimento em Java
Spring: Overview do framework mais popular para desenvolvimento em JavaSpring: Overview do framework mais popular para desenvolvimento em Java
Spring: Overview do framework mais popular para desenvolvimento em JavaMariana de Azevedo Santos
 
Docker Introduction
Docker IntroductionDocker Introduction
Docker IntroductionPeng Xiao
 
Docker: From Zero to Hero
Docker: From Zero to HeroDocker: From Zero to Hero
Docker: From Zero to Herofazalraja
 
Node.js Express
Node.js  ExpressNode.js  Express
Node.js ExpressEyal Vardi
 

Was ist angesagt? (20)

Terraform Modules and Continuous Deployment
Terraform Modules and Continuous DeploymentTerraform Modules and Continuous Deployment
Terraform Modules and Continuous Deployment
 
JWT-spring-boot-avancer.pdf
JWT-spring-boot-avancer.pdfJWT-spring-boot-avancer.pdf
JWT-spring-boot-avancer.pdf
 
Spring Boot
Spring BootSpring Boot
Spring Boot
 
Net Framework vs .Net Core A Complete Comparison.pdf
Net Framework vs  .Net Core  A Complete Comparison.pdfNet Framework vs  .Net Core  A Complete Comparison.pdf
Net Framework vs .Net Core A Complete Comparison.pdf
 
Observability and Management on OCI - Logging and Monitoring
Observability and Management on OCI - Logging and MonitoringObservability and Management on OCI - Logging and Monitoring
Observability and Management on OCI - Logging and Monitoring
 
Maven ppt
Maven pptMaven ppt
Maven ppt
 
Programación reactiva con Vert.x
Programación reactiva con Vert.xProgramación reactiva con Vert.x
Programación reactiva con Vert.x
 
ReactJS Tutorial For Beginners | ReactJS Redux Training For Beginners | React...
ReactJS Tutorial For Beginners | ReactJS Redux Training For Beginners | React...ReactJS Tutorial For Beginners | ReactJS Redux Training For Beginners | React...
ReactJS Tutorial For Beginners | ReactJS Redux Training For Beginners | React...
 
Docker vs VM | | Containerization or Virtualization - The Differences | DevOp...
Docker vs VM | | Containerization or Virtualization - The Differences | DevOp...Docker vs VM | | Containerization or Virtualization - The Differences | DevOp...
Docker vs VM | | Containerization or Virtualization - The Differences | DevOp...
 
Deep dive into SoapUI
Deep dive into SoapUIDeep dive into SoapUI
Deep dive into SoapUI
 
What is Node.js | Node.js Tutorial for Beginners | Node.js Modules | Node.js ...
What is Node.js | Node.js Tutorial for Beginners | Node.js Modules | Node.js ...What is Node.js | Node.js Tutorial for Beginners | Node.js Modules | Node.js ...
What is Node.js | Node.js Tutorial for Beginners | Node.js Modules | Node.js ...
 
Dot net platform and dotnet core fundamentals
Dot net platform and dotnet core fundamentalsDot net platform and dotnet core fundamentals
Dot net platform and dotnet core fundamentals
 
laravel.pptx
laravel.pptxlaravel.pptx
laravel.pptx
 
Spring: Overview do framework mais popular para desenvolvimento em Java
Spring: Overview do framework mais popular para desenvolvimento em JavaSpring: Overview do framework mais popular para desenvolvimento em Java
Spring: Overview do framework mais popular para desenvolvimento em Java
 
Introduction to Node.js
Introduction to Node.jsIntroduction to Node.js
Introduction to Node.js
 
.Net Core
.Net Core.Net Core
.Net Core
 
Docker Introduction
Docker IntroductionDocker Introduction
Docker Introduction
 
Laravel Presentation
Laravel PresentationLaravel Presentation
Laravel Presentation
 
Docker: From Zero to Hero
Docker: From Zero to HeroDocker: From Zero to Hero
Docker: From Zero to Hero
 
Node.js Express
Node.js  ExpressNode.js  Express
Node.js Express
 

Ähnlich wie App development with quasar (pdf)

EWD 3 Training Course Part 5b: First Steps in Building a QEWD Application
EWD 3 Training Course Part 5b: First Steps in Building a QEWD ApplicationEWD 3 Training Course Part 5b: First Steps in Building a QEWD Application
EWD 3 Training Course Part 5b: First Steps in Building a QEWD ApplicationRob Tweed
 
EWD 3 Training Course Part 5a: First Steps in Building a QEWD Application
EWD 3 Training Course Part 5a: First Steps in Building a QEWD ApplicationEWD 3 Training Course Part 5a: First Steps in Building a QEWD Application
EWD 3 Training Course Part 5a: First Steps in Building a QEWD ApplicationRob Tweed
 
Easy Cloud Native Transformation using HashiCorp Nomad
Easy Cloud Native Transformation using HashiCorp NomadEasy Cloud Native Transformation using HashiCorp Nomad
Easy Cloud Native Transformation using HashiCorp NomadBram Vogelaar
 
Kraken
KrakenKraken
KrakenPayPal
 
JSNation.com - Azure Static Web Apps (SWA) with Azure DevOps
JSNation.com - Azure Static Web Apps (SWA) with Azure DevOpsJSNation.com - Azure Static Web Apps (SWA) with Azure DevOps
JSNation.com - Azure Static Web Apps (SWA) with Azure DevOpsJuarez Junior
 
Provisioning, deploying and debugging node.js applications on azure
Provisioning, deploying and debugging node.js applications on azureProvisioning, deploying and debugging node.js applications on azure
Provisioning, deploying and debugging node.js applications on azurePatriek van Dorp
 
Intro To Node.js
Intro To Node.jsIntro To Node.js
Intro To Node.jsChris Cowan
 
Kraken Front-Trends
Kraken Front-TrendsKraken Front-Trends
Kraken Front-TrendsPayPal
 
Control your deployments with Capistrano
Control your deployments with CapistranoControl your deployments with Capistrano
Control your deployments with CapistranoRamazan K
 
Pyramid Deployment and Maintenance
Pyramid Deployment and MaintenancePyramid Deployment and Maintenance
Pyramid Deployment and MaintenanceJazkarta, Inc.
 
Building websites with Node.ACS
Building websites with Node.ACSBuilding websites with Node.ACS
Building websites with Node.ACSralcocer
 
Building websites with Node.ACS
Building websites with Node.ACSBuilding websites with Node.ACS
Building websites with Node.ACSRicardo Alcocer
 
Laravel Beginners Tutorial 1
Laravel Beginners Tutorial 1Laravel Beginners Tutorial 1
Laravel Beginners Tutorial 1Vikas Chauhan
 
以Vue開發電子商務網站
架構與眉角
以Vue開發電子商務網站
架構與眉角以Vue開發電子商務網站
架構與眉角
以Vue開發電子商務網站
架構與眉角Mei-yu Chen
 
OCI Oracle Functions Deployment
OCI Oracle Functions Deployment OCI Oracle Functions Deployment
OCI Oracle Functions Deployment Toni Epple
 
Server(less) Swift at SwiftCloudWorkshop 3
Server(less) Swift at SwiftCloudWorkshop 3Server(less) Swift at SwiftCloudWorkshop 3
Server(less) Swift at SwiftCloudWorkshop 3kognate
 

Ähnlich wie App development with quasar (pdf) (20)

EWD 3 Training Course Part 5b: First Steps in Building a QEWD Application
EWD 3 Training Course Part 5b: First Steps in Building a QEWD ApplicationEWD 3 Training Course Part 5b: First Steps in Building a QEWD Application
EWD 3 Training Course Part 5b: First Steps in Building a QEWD Application
 
EWD 3 Training Course Part 5a: First Steps in Building a QEWD Application
EWD 3 Training Course Part 5a: First Steps in Building a QEWD ApplicationEWD 3 Training Course Part 5a: First Steps in Building a QEWD Application
EWD 3 Training Course Part 5a: First Steps in Building a QEWD Application
 
Easy Cloud Native Transformation using HashiCorp Nomad
Easy Cloud Native Transformation using HashiCorp NomadEasy Cloud Native Transformation using HashiCorp Nomad
Easy Cloud Native Transformation using HashiCorp Nomad
 
Write php deploy everywhere tek11
Write php deploy everywhere   tek11Write php deploy everywhere   tek11
Write php deploy everywhere tek11
 
Kraken
KrakenKraken
Kraken
 
JSNation.com - Azure Static Web Apps (SWA) with Azure DevOps
JSNation.com - Azure Static Web Apps (SWA) with Azure DevOpsJSNation.com - Azure Static Web Apps (SWA) with Azure DevOps
JSNation.com - Azure Static Web Apps (SWA) with Azure DevOps
 
Provisioning, deploying and debugging node.js applications on azure
Provisioning, deploying and debugging node.js applications on azureProvisioning, deploying and debugging node.js applications on azure
Provisioning, deploying and debugging node.js applications on azure
 
Intro To Node.js
Intro To Node.jsIntro To Node.js
Intro To Node.js
 
Kraken Front-Trends
Kraken Front-TrendsKraken Front-Trends
Kraken Front-Trends
 
Control your deployments with Capistrano
Control your deployments with CapistranoControl your deployments with Capistrano
Control your deployments with Capistrano
 
Pyramid Deployment and Maintenance
Pyramid Deployment and MaintenancePyramid Deployment and Maintenance
Pyramid Deployment and Maintenance
 
Building websites with Node.ACS
Building websites with Node.ACSBuilding websites with Node.ACS
Building websites with Node.ACS
 
Building websites with Node.ACS
Building websites with Node.ACSBuilding websites with Node.ACS
Building websites with Node.ACS
 
Nodejs web,db,hosting
Nodejs web,db,hostingNodejs web,db,hosting
Nodejs web,db,hosting
 
Laravel Beginners Tutorial 1
Laravel Beginners Tutorial 1Laravel Beginners Tutorial 1
Laravel Beginners Tutorial 1
 
以Vue開發電子商務網站
架構與眉角
以Vue開發電子商務網站
架構與眉角以Vue開發電子商務網站
架構與眉角
以Vue開發電子商務網站
架構與眉角
 
OCI Oracle Functions Deployment
OCI Oracle Functions Deployment OCI Oracle Functions Deployment
OCI Oracle Functions Deployment
 
Dancing with websocket
Dancing with websocketDancing with websocket
Dancing with websocket
 
Love at first Vue
Love at first VueLove at first Vue
Love at first Vue
 
Server(less) Swift at SwiftCloudWorkshop 3
Server(less) Swift at SwiftCloudWorkshop 3Server(less) Swift at SwiftCloudWorkshop 3
Server(less) Swift at SwiftCloudWorkshop 3
 

Mehr von wonyong hwang

Hyperledger Explorer.pptx
Hyperledger Explorer.pptxHyperledger Explorer.pptx
Hyperledger Explorer.pptxwonyong hwang
 
하이퍼레저 페이지 단위 블록 조회
하이퍼레저 페이지 단위 블록 조회하이퍼레저 페이지 단위 블록 조회
하이퍼레저 페이지 단위 블록 조회wonyong hwang
 
토큰 증권 개요.pptx
토큰 증권 개요.pptx토큰 증권 개요.pptx
토큰 증권 개요.pptxwonyong hwang
 
Vue.js 기초 실습.pptx
Vue.js 기초 실습.pptxVue.js 기초 실습.pptx
Vue.js 기초 실습.pptxwonyong hwang
 
Deploying Hyperledger Fabric on Kubernetes.pptx
Deploying Hyperledger Fabric on Kubernetes.pptxDeploying Hyperledger Fabric on Kubernetes.pptx
Deploying Hyperledger Fabric on Kubernetes.pptxwonyong hwang
 
k8s practice 2023.pptx
k8s practice 2023.pptxk8s practice 2023.pptx
k8s practice 2023.pptxwonyong hwang
 
HyperLedger Fabric V2.5.pdf
HyperLedger Fabric V2.5.pdfHyperLedger Fabric V2.5.pdf
HyperLedger Fabric V2.5.pdfwonyong hwang
 
Ngrok을 이용한 Nginx Https 적용하기.pptx
Ngrok을 이용한 Nginx Https 적용하기.pptxNgrok을 이용한 Nginx Https 적용하기.pptx
Ngrok을 이용한 Nginx Https 적용하기.pptxwonyong hwang
 
Nginx Https 적용하기.pptx
Nginx Https 적용하기.pptxNginx Https 적용하기.pptx
Nginx Https 적용하기.pptxwonyong hwang
 
Kafka JDBC Connect Guide(Postgres Sink).pptx
Kafka JDBC Connect Guide(Postgres Sink).pptxKafka JDBC Connect Guide(Postgres Sink).pptx
Kafka JDBC Connect Guide(Postgres Sink).pptxwonyong hwang
 
Nginx Reverse Proxy with Kafka.pptx
Nginx Reverse Proxy with Kafka.pptxNginx Reverse Proxy with Kafka.pptx
Nginx Reverse Proxy with Kafka.pptxwonyong hwang
 
Kafka monitoring using Prometheus and Grafana
Kafka monitoring using Prometheus and GrafanaKafka monitoring using Prometheus and Grafana
Kafka monitoring using Prometheus and Grafanawonyong hwang
 
주가 정보 다루기.pdf
주가 정보 다루기.pdf주가 정보 다루기.pdf
주가 정보 다루기.pdfwonyong hwang
 
Hyperledger Fabric practice (v2.0)
Hyperledger Fabric practice (v2.0) Hyperledger Fabric practice (v2.0)
Hyperledger Fabric practice (v2.0) wonyong hwang
 
Hyperledger fabric practice(pdf)
Hyperledger fabric practice(pdf)Hyperledger fabric practice(pdf)
Hyperledger fabric practice(pdf)wonyong hwang
 
Hyperledger composer
Hyperledger composerHyperledger composer
Hyperledger composerwonyong hwang
 

Mehr von wonyong hwang (20)

Hyperledger Explorer.pptx
Hyperledger Explorer.pptxHyperledger Explorer.pptx
Hyperledger Explorer.pptx
 
하이퍼레저 페이지 단위 블록 조회
하이퍼레저 페이지 단위 블록 조회하이퍼레저 페이지 단위 블록 조회
하이퍼레저 페이지 단위 블록 조회
 
토큰 증권 개요.pptx
토큰 증권 개요.pptx토큰 증권 개요.pptx
토큰 증권 개요.pptx
 
Vue.js 기초 실습.pptx
Vue.js 기초 실습.pptxVue.js 기초 실습.pptx
Vue.js 기초 실습.pptx
 
Deploying Hyperledger Fabric on Kubernetes.pptx
Deploying Hyperledger Fabric on Kubernetes.pptxDeploying Hyperledger Fabric on Kubernetes.pptx
Deploying Hyperledger Fabric on Kubernetes.pptx
 
k8s practice 2023.pptx
k8s practice 2023.pptxk8s practice 2023.pptx
k8s practice 2023.pptx
 
HyperLedger Fabric V2.5.pdf
HyperLedger Fabric V2.5.pdfHyperLedger Fabric V2.5.pdf
HyperLedger Fabric V2.5.pdf
 
Ngrok을 이용한 Nginx Https 적용하기.pptx
Ngrok을 이용한 Nginx Https 적용하기.pptxNgrok을 이용한 Nginx Https 적용하기.pptx
Ngrok을 이용한 Nginx Https 적용하기.pptx
 
Nginx Https 적용하기.pptx
Nginx Https 적용하기.pptxNginx Https 적용하기.pptx
Nginx Https 적용하기.pptx
 
Kafka JDBC Connect Guide(Postgres Sink).pptx
Kafka JDBC Connect Guide(Postgres Sink).pptxKafka JDBC Connect Guide(Postgres Sink).pptx
Kafka JDBC Connect Guide(Postgres Sink).pptx
 
Nginx Reverse Proxy with Kafka.pptx
Nginx Reverse Proxy with Kafka.pptxNginx Reverse Proxy with Kafka.pptx
Nginx Reverse Proxy with Kafka.pptx
 
Kafka Rest.pptx
Kafka Rest.pptxKafka Rest.pptx
Kafka Rest.pptx
 
Kafka monitoring using Prometheus and Grafana
Kafka monitoring using Prometheus and GrafanaKafka monitoring using Prometheus and Grafana
Kafka monitoring using Prometheus and Grafana
 
주가 정보 다루기.pdf
주가 정보 다루기.pdf주가 정보 다루기.pdf
주가 정보 다루기.pdf
 
KAFKA 3.1.0.pdf
KAFKA 3.1.0.pdfKAFKA 3.1.0.pdf
KAFKA 3.1.0.pdf
 
kubernetes practice
kubernetes practicekubernetes practice
kubernetes practice
 
Hyperledger Fabric practice (v2.0)
Hyperledger Fabric practice (v2.0) Hyperledger Fabric practice (v2.0)
Hyperledger Fabric practice (v2.0)
 
Docker practice
Docker practiceDocker practice
Docker practice
 
Hyperledger fabric practice(pdf)
Hyperledger fabric practice(pdf)Hyperledger fabric practice(pdf)
Hyperledger fabric practice(pdf)
 
Hyperledger composer
Hyperledger composerHyperledger composer
Hyperledger composer
 

Kürzlich hochgeladen

Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilV3cube
 

Kürzlich hochgeladen (20)

Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 

App development with quasar (pdf)

  • 1. Dept. of Smart Finance, Korea Polytechnics Seoul Kangseo Campus ApplicationDevelopmentw/ QuasarFramework Basic Course
  • 2. QuasarCLIInstallation • Prerequisite 
 Node >=12.22.1 and NPM >=6.14.12 • recommendation node version : v14.17.5 
 check your node and npm : node -v 
 npm -v • npm install -g @quasar/cli Do not use uneven versions of Node i.e. 13, 15, etc. These versions are not tested with Quasar and often cause issues due to their experimental nature. We highly recommend always using the LTS version of Node. Ref : https://quasar.dev/quasar-cli/installation
  • 3. HelloworldⅠ(1/2) •  we create a project folder with Quasar CLI • quasar create <folder_name> Ref : https://quasar.dev/quasar-cli/installation (base) waynehwang@wayneui-MacBookPro temp % quasar create hello ___ / _ _ _ __ _ ___ __ _ _ __ | | | | | | |/ _` / __|/ _` | '__| | |_| | |_| | (_| __ (_| | | _____,_|__,_|___/__,_|_| ? Project name (internal usage for dev) hello ? Project product name (must start with letter if building mobile apps) hello ? Project description hello world ? Author wayne hwang <wonyong@wonyong.net> ? Pick your CSS preprocessor: SCSS ? Check the features needed for your project: ESLint (recommended), Vuex, Axios ? Pick an ESLint preset: Prettier ? Continue to install project dependencies after the project has been created? ( recommended) NPM Quasar CLI · Generated "hello". [*] Installing project dependencies … [*] Quasar Project initialization finished! To get started: cd hello quasar dev
  • 4. Helloworld Ⅰ(2/2) • Look into package.json, App.vue, routes.js, Index.vue, EssentialLink.vue, … • Run your app with below command: 
 quasar dev
  • 5. HelloWorldⅡ • Repository address : 
 https://github.com/wonyongHwang/kopoPro fi le • git clone https://github.com/wonyongHwang/kopoPro fi le • npm install • quasar dev kopoProfile
  • 6. HelloWorldⅡ • In this practice, we don’t have a 
 drawer and a footer either. So, only 
 <q-header> is being a ff ected by 
 <q-layout>. • layout <q-layout view="lHh lpr lFf"> reference : https://quasar.dev/layout/layout#understanding-the-view-prop
  • 7. HelloWorldⅡ • quasar can detect platform : $q.platfrom.is.~~ 
 
 eg> if you will deploy app to mobile device(android, 
 ios) app can detect platform using $q.platform.is. 
 cordova $q.platform <div v-bind:class="{'main': $q.platform.is.desktop, 'mobile_main': $q.platform.is.ipad || $q.platform.is.mobile}" class="full-height" style="background-color:rgba(0, 0, 0, 0.7);"> reference : https://quasar.dev/options/platform-detection#introduction
  • 8. HelloWorldⅡ style <q-header class="q-py-sm" style="background-color:rgba(0, 0, 0, 0.7);"> reference : https://quasar.dev/style/spacing#table-of-permutations
  • 9. HelloWorldⅡ q-tab reference : https://quasar.dev/vue-components/tabs <q-tabs v-model="selected_tab" shrink> <q-tab name="about_me" :style="[selected_tab == 'about_me' ? {backgroundColor: 'green'} : {}]" class="q-mr-sm q-py-xs custom_tab" @click="scrollToElement('id_about_me')" style="width:120px;min-height:auto !important;color: white" label="About Me"/>
  • 10. HelloWorldⅡ q-card <q-card class="my-card" flat bordered> <q-card-section> reference : https://quasar.dev/vue-components/card#introduction
  • 11. HelloWorldⅡ • Get/set scroll position (Quasar Scrolling Utils) 
 https://quasar.dev/quasar-utils/scrolling-utils#get-set-scroll-position <script></script> import {scroll} from 'quasar' const {getScrollTarget, setScrollPosition} = scroll export default { name: 'PageIndex', data() { return { name: "", email: "", message: "", selected_tab: 'about_me', } }, methods: { scrollToElement(id) { let el = document.getElementById(id) const target = getScrollTarget(el) const o ff set = el.o ff setTop - 65 const duration = 800 setScrollPosition(target, o ff set, duration) } }, mounted () { } }
  • 12. homework • customizing web page • upload source to your github repo. 
 - README.md should be edited ex>
  • 13. homework • deploy your web pages via netlify 
 https://app.netlify.com/
  • 14. homework • check url • if you have a own domain, netlify allow you to access your web site • ‘https(let’s encrypt)’ supports both custom domain and netlify domain
  • 15. Make Your First Page Basic Practice
  • 16. Layout • quasar create <folder name> • quasar dev • fi rst page is served by Index.vue 

  • 17. Layout • Quasar provides basic layouts reference : https://quasar.dev/layout/gallery
  • 18. SignIn • what you need to implement a sign-in page: 
 2 Input Text fi eld 
 1 Check Box 
 1 Button 
 and more …
  • 19. SignIn • copy relevant codes and paste to your “Index.vue” 
 https://quasar.dev/vue-components/input
  • 20. SignUp • add Signup.Vue to your project • add page mapping on routes.js
  • 21. pagelink • vue syntax for page link : 
 <router-link to=“/address”> ~~ </router-link> <router-link to="/signup" > <center>New User? Click Here to Register.</center> </router-link>
  • 22. Homework • Place and Organize Input Text fi elds (E-mail, Password, etc …) 
 : center alignment • Password should be masked while typing • Place Sign-In / Sign-Up buttons complete your sign-in / sign-up pages!
  • 23. f irebase • https:// fi rebase.google.com/?hl=ko create a project // For Firebase JS SDK v7.20.0 and later, measurementId is optional const fi rebaseCon fi g = { apiKey: "AIzaSyA~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", authDomain: "kopologinchecker. fi rebaseapp.com", projectId: "kopologinchecker", storageBucket: "kopologinchecker.appspot.com", messagingSenderId: "17~~~~~~~~~~~~", appId: "1:17~~~~~~~~:web:d4~~~~~~~~", measurementId: “G-H0~~~~~~~~~~~~" };
  • 24. • npm install --save fi rebase • quasar new boot fi rebase 
 -> fi rebase.js will be generated in src/boot 
 -> paste fi rebase con fi guration to fi rebase.js f irebase setting config. ref : https://quasar.dev/quasar-cli/boot- fi les import firebase from 'firebase/app'; import 'firebase/auth'; import 'firebase/analytics' const firebaseConfig = { apiKey: "~", authDomain: "kopologinchecker.firebaseapp.com", projectId: "kopologinchecker", storageBucket: "kopologinchecker.appspot.com", messagingSenderId: “~", appId: "~", measurementId: "~" }; if (!firebase.apps.length) { firebase.initializeApp(firebaseConfig); } firebase.analytics(); export const auth = firebase.auth();
  • 25. f irebase • enable email/password • create a test user if needed sign-in method
  • 26. f irebase • https:// fi rebase.google.com/docs/auth/web/start?hl=ko sign-in method fi rebase.auth().signInWithEmailAndPassword(email, password )   .then((userCredential) => {     // Signed i n     var user = userCredential.user ;     // .. .   } )   .catch((error) => {     var errorCode = error.code ;     var errorMessage = error.message ;   });
  • 27. • let’s use quasar notify to show success/fail message 
 https://quasar.dev/quasar-plugins/notify#introduction f irebase sign-in method auth.signInWithEmailAndPassword(this.text, this.password).then( (userCredential) => { console.log(userCredential.user); this.$router.push({ path: 'home' }) } ).catch( (err) => { console.log(err.code); console.log(err.message); this.$q.notify({ message: err.message, color: 'purple' }) } ) message, color, postion, textColor, icon, … import { useQuasar } from 'quasar' const $q = useQuasar() $q.notify({ message : "login success", color : "blue" }) vue 3
  • 28. homework • implement a sign-up function using fi rebase api • validation logic should be implemented 
 ex> email/password should not be empty 
 password should be equal to ‘repeat password’ 
 password must be at least 6 characters long 
 hint> https://levelup.gitconnected.com/ fi rebase-auth-management-in-vue-js-with-vuex-9c4a5d9cedc • move page after sign-up 
 hint> this.$router.push({ path: 'home' }) import { useRouter, useRoute } from 'vue-router' export default { setup() { const router = useRouter() const route = useRoute() // Now you can access params like : console.log(route.params.id) ; route.push({path: ‘home’} ) } }; vue v3 https://next.router.vuejs.org/guide/advanced/composition-api.html#accessing-the-router-and-current-route-inside-setup
  • 29. • Parent -> child : props • Child -> Parent : emit
  • 30. management f irebaseauthw/vuex • state management pattern and its library • state : data • mutations : change state (sync) • actions : commit mutation (async) what vuex is Actions State View Mutations this.$store.commit emit, props Unidirectional fl ow
  • 31. management f irebaseauthw/vuex • state = fi re auth info • ‘ fi re auth info’ can acquire when we call 
 signInWithEmailAndPassword() 
 createUserWithEmailAndPassword() 
 and so on. state Actions State View Mutations this.$store.commit import {auth} from "src/boot/firebase" export default store(function (/* { ssrContext } */) { const Store = createStore({ modules: { // example }, state: { fireUser:null }, … State
  • 32. management f irebaseauthw/vuex • get the current sign-in user is by setting an observer on the Auth object 
 https:// fi rebase.google.com/docs/auth/web/manage-users • state should be null when user signed out 
 https:// fi rebase.google.com/docs/auth/web/password-auth?hl=ko action actions: { signOutAction({commit}) { auth.signOut() .then(() => { commit("setFireUser", null); }) }, authAction({ commit }) { auth.onAuthStateChanged(user => { if (user) { commit("setFireUser", user); } }); }, }, mutations: { setFireUser(state, firebaseUser){ state.fireUser = firebaseUser } Actions Mutations
  • 33. management f irebaseauthw/vuex • prepare helper functions 
 https://joshua1988.github.io/web-development/vuejs/vuex-getters-mutations/ getters getters: { getFireUser(state) { return state.fireUser; }, isUserAuth(state) { return !!state.fireUser; } },
  • 34. management f irebaseauthw/vuex source code import { store } from 'quasar/wrappers' import { createStore } from 'vuex' import {auth} from "src/boot/firebase" export default store(function (/* { ssrContext } */) { const Store = createStore({ state: { fireUser:null }, actions: { signOutAction({commit}) { auth.signOut() .then(() => { commit("setFireUser", null); }) .catch(error => { commit("setFireError", error.message); }); }, authAction({ commit }) { auth.onAuthStateChanged(user => { if (user) { commit("setFireUser", user); } else { commit("setFireUser", null); } }); }, }, getters: { getFireUser(state) { return state.fireUser; }, isUserAuth(state) { return !!state.fireUser; } }, mutations: { setFireUser(state, firebaseUser){ state.fireUser = firebaseUser } }, }) return Store })
  • 35. management f irebaseauthw/vuex • commit state when my application obtain a fi rebase auth • get a fi rebase auth to display user info • check a fi rebase auth usage example auth.signInWithEmailAndPassword(this.text, this.password).then( (userCredential) => { this.$store.commit("setFireUser", userCredential.user); } ) <div class="text-h6" align="center"> Hi, {{ this.name }}({{ getFireUser.email }}) <br> … computed: { ...mapGetters(["getFireUser", "isUserAuth"]) }, mounted() { this.authAction(); … methods: { ...mapActions(["signOutAction","authAction"]), import { useStore } from "vuex" ; export default { setup() { const store = useStore() ; store.commit("setFireUser", userCredential.user) ; } }; vue v3 https://kyounghwan01.github.io/blog/Vue/vue3/composition-api-vuex/#vuex-%E1%84%89%E1%85%A6%E1%84%90%E1%85%B5%E1%86%BC-%E1%84%86%E1%85%B5%E1%86%BE-store-module-1%E1%84%80%E1%85%A2%E1%84%85%E1%85%A9-%E1%84%89%E1%85%B5%E1%86%AF%E1%84%92%E1%85%A2%E1%86%BC
  • 36. homework • When a user logged in, move Vue Page and display user’s email using vuex • tip> 
 <div v-if=“getFireUser">~~</div> 
 computed: { ...mapGetters(["getFireUser", "isUserAuth"]) }, <div class="text-h6" align="center"> Hi,({{ getFireUser.email }}) </div> import { mapGetters } from "vuex";
  • 37. vuelifecycle • https://cornswrold.tistory.com/342 • beforeCreate, created, beforeMount, mounted, 
 beforeUpdate, updated, beforeDestroy, destroyed
  • 40. Firestore • Firestore data add: set() or add() 
 https:// fi rebase.google.com/docs/ fi restore/manage-data/add-data?hl=ko API db.collection("users").add({ id: this.text, name: this.name }) .then((docRef) => { console.log("Document written with ID: ", docRef.id); this.$q.notify({ message: "Register Success", color: 'blue' }) }) .catch((error) => { console.error("Error adding document: ", error); this.$q.notify({ message: error, color: 'red' }) });
  • 41. Firestore • fi rebase.js 
 import ' fi rebase/ fi restore' 
 export const db = fi rebase. fi restore(); • import 
 import { db } from "src/boot/ fi rebase" Preparations
  • 42. Firestore Data write db.collection("users").add({ id: this.text, name: this.name }) .then((docRef) => { console.log("Document written with ID: ", docRef.id); }) .catch((error) => { console.error("Error adding document: ", error); });
  • 43. Firestore Data read db.collection("users").where("id", "==", this.getFireUser.email ) .get() .then((querySnapshot) => { querySnapshot.forEach((doc) => { // doc.data() is never undefined for query doc snapshots console.log(doc.id, " => ", doc.data()); this.name = doc.data().name }); }) .catch((error) => { console.log("Error getting documents: ", error); });
  • 44. Homework • When a user logged in, move page(/home) and display user’s name using vuex 
 - user name was saved at Firestore, so we have to read the data fi rst to show it. • user name should be displayed on page(/home) even after refreshing page.
  • 45. Homework Hint <template> <div> HOME <div class="text-h6" align="center"> <div v-if="getFireUser"> Hi,({{ getFireUser.email }}) :) {{ name }} </div> </div> </div> </template> <script> import { defineComponent } from 'vue'; import { auth, db } from "src/boot/firebase" import { useQuasar } from 'quasar' import { mapGetters, mapActions } from "vuex"; // export default defineComponent({ name: 'PageIndex', computed: { ...mapGetters(["getFireUser", "isUserAuth"]) }, updated() { if(this.getFireUser != null && this.name == ''){ // for refresh page // db.collection("users").where("id", "==", this.getFireUser.email ) .get() .then((querySnapshot) => { querySnapshot.forEach((doc) => { // doc.data() is never undefined for query doc snapshots console.log(doc.id, " => ", doc.data()); this.name = doc.data().name }); }) .catch((error) => { console.log("Error getting documents: ", error); }); } }, mounted(){ // this.authAction() // for refresh page // if(this.getFireUser != null){ db.collection("users").where("id", "==", this.getFireUser.email ) .get() .then((querySnapshot) => { querySnapshot.forEach((doc) => { // doc.data() is never undefined for query doc snapshots console.log(doc.id, " => ", doc.data()); this.name = doc.data().name }); }) .catch((error) => { console.log("Error getting documents: ", error); }); } }, data(){ return{ name : '' } }, methods: { ...mapActions(["signOutAction","authAction"]) } }) </script>
  • 46. f irebaseusermgmt. • https:// fi rebase.google.com/docs/auth/web/manage-users?hl=ko • User Info management 
 - user info update 
 - user account delete Some security-sensitive actions—such as deleting an account, setting a primary email address, and changing a password—require that the user has recently signed in. 
  • 47. Implementationof“rememberme”usinglocalStorage • UI 
 <q-checkbox v-model="remember" label="Remember Me" color="teal"/> • Declaration 
 let remember = ref(‘false') • mounted() • When a user tries to log in: if (remember.value == true) { localStorage.username = email.value; localStorage.checkbox = remember.value; } else { localStorage.username = ""; localStorage.checkbox = ""; } mounted(){ if(localStorage.checkbox && localStorage.checkbox !==""){ this.remember = true this.email = localStorage.username } else { this.remember = false } }
  • 49. Homework • Elaborate your work(home/sign-in/sign-up) • Conceptualizing your idea
  • 61. Menu • components hierarchy 
 ⎯ MainLayout.vue 
 EssentialLink.vue props and emit icon title label link + <template> <q-item clickable tag="a" target="_blank" :href="link"> <q-item-section v-if="icon" avatar> <q-icon :name="icon" /> </q-item-section> <q-item-section> <q-item-label>{{ title }}</q-item-label> <q-item-label caption> {{ caption }} </q-item-label> </q-item-section> </q-item> </template> <script> import { defineComponent } from 'vue' export default defineComponent({ name: 'EssentialLink', props: { title: { type: String, required: true }, caption: { type: String, default: '' }, link: { type: String, default: '#' }, icon: { type: String, default: '' } } }) </script> props : hey, parent component! control me
  • 62. Menu • components hierarchy 
 ⎯ MainLayout.vue 
 EssentialLink.vue props and emit <EssentialLink v-for="link in essentialLinks" :key="link.title" v-bind="link" /> … import EssentialLink from 'components/EssentialLink.vue' const linksList = [ { title: 'Docs', caption: 'quasar.dev', icon: 'school', link: 'https://quasar.dev' }, … export default defineComponent({ name: 'MainLayout', components: { EssentialLink }, 
 
 setup () { return { essentialLinks: linksList, } } … parent component(MainLayout) now can set child props
  • 63. Menu • <Practice> 
 - open internal links in a current window 
 - open external links in a new tab (or window) props and emit
  • 64. Menu • <Practice> child component(EssentialLink) modi fi cation 
 props 
 

 template props and emit external: { type: Boolean, default: false } <template> <!-- <router-link :to="link" style="text-decoration: none"> --> <section v-if="external"> <q-item clickable tag="a" target="_target" :href="link"> … </q-item> </section> <section v-else> <router-link :to="link" style="text-decoration: none; color: inherit;”> … </router-link> </section> </template>
  • 65. Menu • <Practice> parent component(MainLayout) modi fi cation 
 props and emit const linksList = [ { title: 'Home', caption: 'Home', icon: 'home', link: '/home' }, { title: 'QR Scanner', caption: 'QR Check for Admin', icon: 'qr_code_scanner', link: 'https://kopologinchecker.web.app/#/qrscanner', 
 external: true }, …
  • 66. Menu • <Practice> 
 - close menu when a external link is clicked props and emit emit : hey, parent component! handle this
  • 67. Menu • <Practice> child component(EssentialLink) modi fi cation 
 template 
 

 methods props and emit <q-item clickable tag="a" target="_target" :href="link" @click="sendEvent()"> methods: { sendEvent() { this.$emit('closeDrawer'); console.log("emit emit") } }, • <Practice> parent component(MainLayout) modi fi cation 
 template 
 

 methods <EssentialLink v-on:closeDrawer="closeme()" 
 v-for="link in essentialLinks" :key="link.title" v-bind="link" /> methods: { closeme() { console.log('event received'); this.leftDrawerOpen = false; } },
  • 69. Homework • save user login timestamps to fi restore • display user login info (w/ timestamp) build your own table
  • 70. q-table • save user data to Firestore 
 var cdate = Date.now() // firestore insert => then we can get doc id to generate qr code db.collection("qrgen").add({ date: cdate, id: this.getFireUser.email, status: this.sliderValue //this.group }) .then((docRef) => { // console.log("Document written with ID: ", docRef.id); }) .catch((error) => { console.error("Error adding document: ", error); });
  • 71. q-table • basic layout <section v-if="!onloading"> <q-table :title="date" :rows="rows" :columns="columns" row-key="no" v-model:pagination="pagination" :filter="filter"> </q-table> </section> ‘onloading’ set to be false when data is completely loaded data() { return { pagination: { sortBy: 'time', descending: false, rowsPerPage: 15, // current rows per page being displayed }, date: '2019/02/01', filter : '', columns : [ { name: 'no', required: true, label: 'SID', align: 'left', field: row => row.no, format: val => `${val}`, sortable: true }, { name: 'name', align: 'left', label: 'Name', field: 'name', sortable: true }, { name: 'time', align: 'left', label: 'Check-In Time', field: 'time', sortable: true }, { name: 'temperature', label: 'Temperature', field: 'temperature', sortable: true } ], rows : [ ], cnt : 1, onloading : true } },
  • 72. q-table data load dataLoad: function () { this.cnt = 1 var now = new Date(); var startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate()); var timestamp = startOfDay / 1; db.collection("checkin").where("time", ">=", timestamp) // 오늘 체크인만 확인 .onSnapshot((snapshot) => { snapshot.docChanges().forEach((change) => { if (change.type === "added") { var tempRow = {name: '', time:'', temperature:''} tempRow.name = change.doc.data().name const getTime = (timeStamp, offset) => { let d = new Date((timeStamp + offset)); var hour = d.getHours() var min = d.getMinutes() var sec = d.getSeconds() if (hour < 10) { hour = "0" + hour; } if (min < 10) { min = "0" + min; } if (sec < 10) { sec = "0" + sec; } let ret = (d.getMonth()+1)+ "/"+(d.getDate())+ " "+hour+ ":"+min+":"+sec return ret } tempRow.time = getTime(change.doc.data().time,0) tempRow.no = this.cnt this.cnt++ tempRow.temperature = change.doc.data().temperature this.rows.push(tempRow) } }); }); this.onloading = false } // end of dataLoad ref : https:// fi rebase.google.com/docs/ fi restore/query-data/listen?hl=ko
  • 73. q-table • additional function - search <section v-if="!onloading"> <q-table :title="date" :rows="rows" :columns="columns" row-key="no" :pagination.sync="pagination" :filter="filter"> <template v-slot:top-right> <q-input borderless dense debounce="300" v-model="filter" placeholder="Search"> <template v-slot:append> <q-icon name="search"></q-icon> </template> </q-input> </template> </q-table> </section>
  • 74. q-table • additional function - date picker <template v-slot:top-left> <div class="q-pa-md" style="width: 150px; margin-top: 20px"> <q-input borderless dense debounce="300" v-model="date" mask="date" :rules="['date']"> <template v-slot:append> <q-icon name="event" class="cursor-pointer"> <q-popup-proxy ref="qDateProxy" transition-show="scale" transition-hide="scale"> <q-date v-model="date"> <div class="row items-center justify-end"> <q-btn v-close-popup label="Close" color="primary" flat @click="datePicked()"></q-btn> </div> </q-date> </q-popup-proxy> </q-icon> </template> </q-input> </div> </template> should be coded between <q-table> and </q-table>
  • 75. q-table • additional function 
 - date picker datePicked(){ this.cnt = 1 this.rows = [] var yyyyMMdd = String(this.date); var sYear = yyyyMMdd.substring(0,4); var sMonth = yyyyMMdd.substring(5,7); var sDate = yyyyMMdd.substring(8,10); var startOfDay = new Date(Number(sYear), Number(sMonth)-1, Number(sDate)); var timestamp = startOfDay / 1; var timestampp1d = timestamp + 86400000 db.collection("users").where("date", ">=", timestamp).where("date", "<", timestampp1d) .get() .then((querySnapshot) => { querySnapshot.forEach((doc) => { var tempRow = {name: '', time:'', temperature:''} tempRow.name = doc.data().email const getTime = (timeStamp, offset) => { let d = new Date((timeStamp + offset)); console.log(d) var hour = d.getHours() var min = d.getMinutes() var sec = d.getSeconds() if (hour < 10) { hour = "0" + hour; } if (min < 10) { min = "0" + min; } if (sec < 10) { sec = "0" + sec; } let ret = (d.getMonth()+1)+ "/"+(d.getDate())+" "+hour+ ":"+min+":"+sec return ret } tempRow.time = getTime(doc.data().date,0) tempRow.no = this.cnt this.cnt++ tempRow.name = doc.data().name this.rows.push(tempRow) }); }) .catch((error) => { console.log("Error getting documents: ", error); }); }
  • 76. q-table • additional function - csv export <div align="right"> <q-btn color="primary" icon-right="archive" label="Export to csv" no-caps @click="exportTable" > 
 </q-btn> </div> exportTable () { var columns = this.columns var rows = this.rows // naive encoding to csv format const content = [columns.map(col => this.wrapCsvValue(col.label))].concat( rows.map(row => columns.map(col => this.wrapCsvValue( typeof col.field === 'function' ? col.field(row) : row[ col.field === void 0 ? col.name : col.field ], col.format )).join(',')) ).join('rn') const status = exportFile( 'table-export.csv', content, 'text/csv' ) if (status !== true) { $q.notify({ message: 'Browser denied file download...', color: 'negative', icon: 'warning' }) } },
  • 77. q-table • additional function - csv export 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}"` }, import { exportFile } from 'quasar'
  • 80. checklicenses • https://www.npmjs.com/package/license-checker OSS(Open Source Software) npm install -g license-checker license-checker --csv --out ./licenses.csv
  • 81. androidstudio • install • license package download after installation 
 https://devvkkid.tistory.com/204 • build • run (w/ AVD manager)
  • 82. cordova • npm install -g cordova • quasar dev -m android --ide 
 android studio error might be occurred : 
 “Installed Build Tools revision 31.0.0 is corrupted. Remove and install again using the SDK Manager.” 
 if you get above error, then you should modify version settings in your build.grade as below image 
 







 then type below command on your terminal (https://stackover fl ow.com/questions/68387270/android-studio-error-installed-build-tools-revision-31-0-0-is-corrupted) 
 cd ~/Library/Android/sdk/build-tools/31.0.0 && mv d8 dx && cd lib && mv d8.jar dx.jar 
 then close android studio and re-run “quasar dev -m android —ide"
  • 84. cordova • quasar build -m cordova -T android • brew install gradle if you get a net error on simulator, then check you port in quasar.conf.js
  • 86. cordova • quasar dev -m cordova -T ios • quasar build -m cordova -T ios • https://www.youtube.com/watch?v=P_Ox5s4anCI ios
  • 88. BasicStructure • setup is called between “before created” and “created” • you can set a style whatever you want step 1 <template> <div class="test"> Hello World, {{ name }} </div> </template> <script> import { defineComponent } from 'vue'; export default defineComponent({ name: 'PageIndex', setup() { const name = "KOPO" return { name } } }) </script> <style lang="scss"> .test { color: red; background-color: yellow; text-align: center; font-size: 30px; } </style>
  • 89. BasicStructure • add function “printName” add a function <template> <div class="test"> Hello World, {{ name }} <p></p> {{ printName() }} </div> </template> <script> import { defineComponent } from 'vue'; export default defineComponent({ name: 'PageIndex', setup() { const name = "KOPO" const printName = () => { return name + "!!" } return { name, printName } } }) </script>
  • 90. BasicStructure • add a parameter : param • call the function with parameter add a parameter <template> <div class="test"> Hello World, {{ name }} <p></p> {{ printName(name) }} </div> </template> <script> import { defineComponent } from 'vue'; export default defineComponent({ name: 'PageIndex', setup() { const name = "KOPO" const printName = (param) => { return 'hello '+ param + "!!" } return { name, printName } } }) </script>
  • 91. BasicStructure • we want to change name string when a button is clicked. 
 but, the result is … • tip> button width dynamically can be set. 
 use $ref ! add a button <template> <div class="test" ref="topitem"> Hello World, {{ name }} <p></p> {{ printName(name) }} </div> <q-btn @click="changeName" class="button is-primary" color="primary" label="BUTTON" :style="{width: itemWidth+'px'}" /> </template> <script> import { defineComponent, ref } from 'vue'; export default defineComponent({ name: 'PageIndex', mounted() { this.itemWidth = this.$refs.topitem.clientWidth console.log(this.itemWidth) }, setup() { let name = "KOPO" let itemWidth = ref(0) const printName = (param) => { return 'hello '+ param + "!!" } const changeName = () => { name = "Button Clicked" console.log("name chaged? ", name) } return { name, itemWidth, printName, changeName } } }) </script> <style lang="scss"> .test { color: red; background-color: yellow; text-align: center; font-size: 30px; width: 300px; } </style>
  • 92. BasicStructure • “KOPO” —> ref(“KOPO”) • name —> name.value use ref to make the variable to be reactive setup() { let name = ref("KOPO") let itemWidth = ref(0) const printName = (param) => { return 'hello '+ param + "!!" } const changeName = () => { name.value = "Button Clicked" console.log("name chaged? ", name) } if you use object or array data, use reactive(“~”) instead ref(“~”)