[Vue3] Fixed usage of value vs modelValue

This commit is contained in:
Ferdinand Thiessen 2021-02-02 01:28:23 +01:00
parent cb68f9ff7e
commit d3d8c1e5f2
7 changed files with 73 additions and 104 deletions

View File

@ -233,8 +233,7 @@ export default boot<UserSessionState>(({ router, store, app }) => {
}; };
// get all plugins // get all plugins
//const pluginsContext = require.context('src/plugins', true, /.+\/plugin.ts$/); const pluginsContext = require.context('src/plugins', true, /.+\/plugin.ts$/);
const pluginsContext = require['context']('src/plugins', true, /.+\/plugin.ts$/);
pluginsContext.keys().forEach((fileName: string) => { pluginsContext.keys().forEach((fileName: string) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
plugins.push(pluginsContext(fileName).default); plugins.push(pluginsContext(fileName).default);

View File

@ -1,17 +1,16 @@
<template> <template>
<q-input <q-input
v-model="dateTime"
filled filled
:readonly="readonly" :readonly="readonly"
:label="label" :label="label"
:value="getDateTime()"
:placeholder="placeholder" :placeholder="placeholder"
:rules="customRules" :rules="customRules"
@input="dateTimeChanged"
> >
<template #append> <template #append>
<q-icon v-if="type == 'date' || type == 'datetime'" name="event" class="cursor-pointer"> <q-icon v-if="type == 'date' || type == 'datetime'" name="event" class="cursor-pointer">
<q-popup-proxy ref="qDateProxy" transition-show="scale" transition-hide="scale"> <q-popup-proxy ref="qDateProxy" transition-show="scale" transition-hide="scale">
<q-date :value="getDate()" mask="YYYY-MM-DD" @input="dateChanged"> <q-date :model-value="getDate()" mask="YYYY-MM-DD" @input="dateChanged">
<div class="row items-center justify-end"> <div class="row items-center justify-end">
<q-btn v-close-popup label="Schließen" color="primary" flat /> <q-btn v-close-popup label="Schließen" color="primary" flat />
</div> </div>
@ -24,7 +23,7 @@
class="cursor-pointer" class="cursor-pointer"
> >
<q-popup-proxy ref="qTimeProxy" transition-show="scale" transition-hide="scale"> <q-popup-proxy ref="qTimeProxy" transition-show="scale" transition-hide="scale">
<q-time :value="getTime()" mask="HH:mm" @input="timeChanged"> <q-time :model-value="getTime()" mask="HH:mm" @update:modelValue="timeChanged">
<div class="row items-center justify-end"> <div class="row items-center justify-end">
<q-btn v-close-popup label="Schließen" color="primary" flat /> <q-btn v-close-popup label="Schließen" color="primary" flat />
</div> </div>
@ -37,12 +36,12 @@
<script lang="ts"> <script lang="ts">
import { computed, defineComponent, ref, PropType } from 'vue'; import { computed, defineComponent, ref, PropType } from 'vue';
import { date } from 'quasar'; import { date as q_date } from 'quasar';
export default defineComponent({ export default defineComponent({
name: 'IsoDateInput', name: 'IsoDateInput',
props: { props: {
value: { type: String, required: true }, modelValue: { type: Date, default: new Date() },
type: { type: {
type: String, type: String,
default: 'date', default: 'date',
@ -57,33 +56,6 @@ export default defineComponent({
}, },
emits: { input: (date: string) => date.length > 5 }, emits: { input: (date: string) => date.length > 5 },
setup(props, { emit }) { setup(props, { emit }) {
function getDateTime() {
if (typeof props.value == 'object') {
switch (props.type) {
case 'date':
return getDate();
case 'time':
return getTime();
case 'datetime':
return `${getDate()} ${getTime()}`;
}
}
return props.value;
}
function getDate() {
if (typeof props.value == 'object') {
return date.formatDate(props.value, 'YYYY-MM-DD');
}
return '';
}
function getTime() {
if (typeof props.value == 'object') {
return date.formatDate(props.value, 'HH:mm');
}
return '';
}
const _date = ref(''); const _date = ref('');
const _time = ref(''); const _time = ref('');
const placeholder = computed(() => { const placeholder = computed(() => {
@ -98,15 +70,50 @@ export default defineComponent({
throw 'Invalid type given'; throw 'Invalid type given';
}); });
const dateTime = computed({
get() {
if (typeof props.modelValue == 'object') {
switch (props.type) {
case 'date':
return getDate();
case 'time':
return getTime();
case 'datetime':
return `${getDate()} ${getTime()}`;
}
}
return props.modelValue;
},
set(dateTimeString: string) {
switch (props.type) {
case 'date':
dateChanged(dateTimeString);
break;
case 'time':
timeChanged(dateTimeString);
break;
case 'datetime':
const _dateTime = dateTimeString.split(' ');
_date.value = _dateTime[0];
_time.value = _dateTime[1];
console.log(dateTimeString, _dateTime);
if (/^\d{4}-\d\d-\d\d \d\d:\d\d$/.test(dateTimeString)) {
console.log('dateTimeChanged');
emit('input', new Date(`${_date.value} ${_time.value}`).toISOString());
} else {
emit('input', dateTimeString);
}
}
},
});
function dateChanged(dateString: string) { function dateChanged(dateString: string) {
_date.value = dateString; _date.value = dateString;
console.log(dateString); console.log(dateString);
if (/^\d{4}-\d\d-\d\d$/.test(dateString)) { if (/^\d{4}-\d\d-\d\d$/.test(dateString)) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
emit('input', new Date(`${_date.value} ${_time.value}`).toISOString()); emit('input', new Date(`${_date.value} ${_time.value}`).toISOString());
} else { } else {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
emit('input', dateString); emit('input', dateString);
} }
} }
@ -114,39 +121,26 @@ export default defineComponent({
function timeChanged(timeString: string) { function timeChanged(timeString: string) {
_time.value = timeString; _time.value = timeString;
if (_date.value == '') { if (_date.value == '') {
_date.value = date.formatDate(new Date(), 'YYYY-MM-DD'); _date.value = q_date.formatDate(new Date(), 'YYYY-MM-DD');
} }
if (/^\d\d:\d\d$/.test(timeString)) { if (/^\d\d:\d\d$/.test(timeString)) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
emit('input', new Date(`${_date.value} ${_time.value}`).toISOString()); emit('input', new Date(`${_date.value} ${_time.value}`).toISOString());
} else { } else {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
emit('input', timeString); emit('input', timeString);
} }
} }
function dateTimeChanged(dateTimeString: string) { function getDate() {
switch (props.type) { if (typeof props.modelValue == 'object') {
case 'date': return q_date.formatDate(props.modelValue, 'YYYY-MM-DD');
dateChanged(dateTimeString);
break;
case 'time':
timeChanged(dateTimeString);
break;
case 'datetime':
const _dateTime = dateTimeString.split(' ');
_date.value = _dateTime[0];
_time.value = _dateTime[1];
console.log(dateTimeString, _dateTime);
if (/^\d{4}-\d\d-\d\d \d\d:\d\d$/.test(dateTimeString)) {
console.log('dateTimeChanged');
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
emit('input', new Date(`${_date.value} ${_time.value}`).toISOString());
} else {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
emit('input', dateTimeString);
}
} }
return '';
}
function getTime() {
if (typeof props.modelValue == 'object') {
return q_date.formatDate(props.modelValue, 'HH:mm');
}
return '';
} }
function isDate(val: string) { function isDate(val: string) {
@ -161,33 +155,19 @@ export default defineComponent({
return !val || /^\d{4}-\d\d-\d\d \d\d:\d\d$/.test(val) || 'Datum und Zeit ist nicht gültig.'; return !val || /^\d{4}-\d\d-\d\d \d\d:\d\d$/.test(val) || 'Datum und Zeit ist nicht gültig.';
} }
// const customRules = computed(() => {
// const _rules = props.rules;
// switch (props.type) {
// case 'date':
// _rules.push(isDate);
// case 'time':
// _rules.push(isTime);
// case 'datetime':
// _rules.push(isDateTime);
// }
// });
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const customRules = [ const customRules = [
props.type == 'date' ? isDate : props.type == 'time' ? isTime : isDateTime, props.type == 'date' ? isDate : props.type == 'time' ? isTime : isDateTime,
...props.rules, ...props.rules,
]; ];
return { return {
dateTime,
getDate, getDate,
getTime, getTime,
getDateTime,
dateChanged, dateChanged,
customRules, customRules,
timeChanged, timeChanged,
placeholder, placeholder,
dateTimeChanged,
}; };
}, },
}); });

View File

@ -3,7 +3,7 @@
<q-card-section class="fit row justify-start content-center items-center"> <q-card-section class="fit row justify-start content-center items-center">
<div class="col-xs-12 col-sm-6 text-center text-h6">Benutzereinstellungen</div> <div class="col-xs-12 col-sm-6 text-center text-h6">Benutzereinstellungen</div>
<div class="col-xs-12 col-sm-6 q-pa-sm"> <div class="col-xs-12 col-sm-6 q-pa-sm">
<UserSelector :user="user" @update:user="userUpdated" /> <UserSelector v-model="user" />
</div> </div>
</q-card-section> </q-card-section>
<MainUserSettings :user="user" @update:user="updateUser" /> <MainUserSettings :user="user" @update:user="updateUser" />
@ -24,12 +24,6 @@ export default defineComponent({
const store = useStore<UserSessionState>(); const store = useStore<UserSessionState>();
const user = ref(<FG.User>store.state.users.currentUser); const user = ref(<FG.User>store.state.users.currentUser);
// can be dropped with VUE3
const userUpdated = (value: FG.User) => {
user.value = value;
console.log(value);
};
function updateUser(value: FG.User) { function updateUser(value: FG.User) {
store.dispatch('users/updateUser', value).catch((error) => { store.dispatch('users/updateUser', value).catch((error) => {
console.warn(error); console.warn(error);
@ -38,7 +32,6 @@ export default defineComponent({
return { return {
user, user,
userUpdated,
updateUser, updateUser,
}; };
}, },

View File

@ -1,18 +1,17 @@
<template> <template>
<q-select <q-select
v-model="selected"
filled filled
:label="label" :label="label"
:value="modelValue"
:options="users" :options="users"
option-label="display_name" option-label="display_name"
option-value="userid" option-value="userid"
map-options map-options
@input="updated"
/> />
</template> </template>
<script lang="ts"> <script lang="ts">
import { computed, defineComponent, Prop, onBeforeMount } from 'vue'; import { computed, defineComponent, PropType, onBeforeMount } from 'vue';
import { useStore } from 'vuex'; import { useStore } from 'vuex';
import { UserSessionState } from '../store'; import { UserSessionState } from '../store';
@ -20,10 +19,10 @@ export default defineComponent({
name: 'UserSelector', name: 'UserSelector',
props: { props: {
label: { type: String, default: 'Benutzer' }, label: { type: String, default: 'Benutzer' },
modelValue: { required: true, type: Object } as Prop<FG.User>, modelValue: { required: true, type: Object as PropType<FG.User> },
}, },
emits: { 'update:modelValue': (user: FG.User) => !!user }, emits: { 'update:modelValue': (user: FG.User) => !!user },
setup(_, { emit }) { setup(props, { emit }) {
const store = useStore<UserSessionState>(); const store = useStore<UserSessionState>();
onBeforeMount(() => { onBeforeMount(() => {
@ -33,12 +32,13 @@ export default defineComponent({
}); });
const users = computed(() => store.state.users.users); const users = computed(() => store.state.users.users);
const updated = (value: FG.User) => { const selected = computed({
emit('update:modelValue', value); get: () => props.modelValue,
}; set: (value: FG.User) => emit('update:modelValue', value),
});
return { return {
updated, selected,
users, users,
}; };
}, },

View File

@ -112,7 +112,7 @@ import { Notify } from 'quasar';
import { UserSessionState } from '../../store'; import { UserSessionState } from '../../store';
import { hasPermission } from 'src/utils/permission'; import { hasPermission } from 'src/utils/permission';
import IsoDateInput from 'src/components/utils/IsoDateInput.vue'; import IsoDateInput from 'src/components/utils/IsoDateInput.vue';
import { defineComponent, computed, ref, onBeforeMount, Prop } from 'vue'; import { defineComponent, computed, ref, onBeforeMount, PropType } from 'vue';
export default defineComponent({ export default defineComponent({
name: 'MainUserSettings', name: 'MainUserSettings',
@ -120,8 +120,8 @@ export default defineComponent({
props: { props: {
user: { user: {
required: true, required: true,
type: Object, type: Object as PropType<FG.User>,
} as Prop<FG.User>, },
newUser: { type: Boolean, required: true }, newUser: { type: Boolean, required: true },
}, },
emits: { emits: {
@ -138,7 +138,7 @@ export default defineComponent({
}); });
const isCurrentUser = computed( const isCurrentUser = computed(
() => user_model.value?.userid === store.state.users.currentUser?.userid () => user_model.value.userid === store.state.users.currentUser?.userid
); );
const canSetRoles = computed(() => hasPermission('users_set_roles')); const canSetRoles = computed(() => hasPermission('users_set_roles'));
@ -162,7 +162,7 @@ export default defineComponent({
const new_password2 = ref(''); const new_password2 = ref('');
function save() { function save() {
let changed = <FG.User>user_model.value; let changed = user_model.value;
if (typeof changed.birthday === 'string') changed.birthday = new Date(changed.birthday); if (typeof changed.birthday === 'string') changed.birthday = new Date(changed.birthday);
changed = Object.assign(changed, { changed = Object.assign(changed, {
password: password.value, password: password.value,
@ -173,8 +173,6 @@ export default defineComponent({
}); });
} }
// TODO: investigate this issue
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
emit('update:user', changed); emit('update:user', changed);
if (avatar.value && (avatar.value.length > 0 || avatar.value instanceof File)) if (avatar.value && (avatar.value.length > 0 || avatar.value instanceof File))

View File

@ -10,14 +10,14 @@
label="Rolle" label="Rolle"
input-debounce="0" input-debounce="0"
class="col-xs-12 col-sm-6 q-pa-sm" class="col-xs-12 col-sm-6 q-pa-sm"
:value="role" :model-value="role"
:options="roles" :options="roles"
option-label="name" option-label="name"
option-value="name" option-value="name"
map-options map-options
clearable clearable
@new-value="createRole" @new-value="createRole"
@input="updateRole" @update:modelValue="updateRole"
@clear="removeRole" @clear="removeRole"
/> />
</q-card-section> </q-card-section>
@ -26,7 +26,7 @@
<q-scroll-area style="height: 20em; width: 100%"> <q-scroll-area style="height: 20em; width: 100%">
<q-input v-if="role.id != -1" v-model="newRoleName" filled label="neuer Name" /> <q-input v-if="role.id != -1" v-model="newRoleName" filled label="neuer Name" />
<q-option-group <q-option-group
:value="role.permissions" :model-value="role.permissions"
:options="permissions" :options="permissions"
color="primary" color="primary"
type="checkbox" type="checkbox"

View File

@ -9,7 +9,6 @@ export interface LoginResponse {
permissions: FG.Permission[]; permissions: FG.Permission[];
} }
//eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
export interface CurrentUserResponse extends FG.User { export interface CurrentUserResponse extends FG.User {
permissions: FG.Permission[]; permissions: FG.Permission[];
} }