Skip to content

Instantly share code, notes, and snippets.

@Akryum
Last active February 7, 2019 17:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Akryum/b827886bbbf6524903f92c114d8cacfb to your computer and use it in GitHub Desktop.
Save Akryum/b827886bbbf6524903f92c114d8cacfb to your computer and use it in GitHub Desktop.
Vue.js composition utils
export function mapEvents (list) {
const result = {}
for (const method of list) {
result[method] = function (...args) {
this.$emit(method, ...args)
}
}
return result
}
export function ComposeUtils () {
// @vue/component
return {
inheritAttrs: false,
methods: {
getComputedProps () {
const result = {}
for (const key in this.$options.computed) {
const prop = this.$options.computed[key]
if (typeof prop !== 'function' || !prop.vuex) {
result[key] = this[key]
}
}
return result
},
getLocalState () {
return {
...this.$attrs,
...this.$props,
...this.getComputedProps(),
}
},
getVuexGetters () {
const result = {}
for (const key in this.$options.computed) {
const prop = this.$options.computed[key]
if (typeof prop === 'function' && prop.vuex) {
result[key] = this[key]
}
}
return result
},
getMethods () {
const result = {}
for (const key in this.$options.methods) {
result[key] = this[key]
}
return result
},
getListeners () {
return {
...this.getMethods(),
...this.$listeners,
}
},
},
}
}
function getSyncId (field) {
return `SyncData_${field}`
}
export function SyncFrom (field, immediate = true) {
const id = getSyncId(field)
// @vue/component
return {
inject: {
[id]: {
default: { value: null },
},
},
watch: {
[field]: {
handler (value) {
this[id].value = value
},
immediate,
deep: true,
},
},
}
}
export function SyncTo (field, defaultFactory = null) {
const id = getSyncId(field)
// @vue/component
return {
provide () {
return {
[id]: this[id],
}
},
data () {
return {
[id]: {
value: defaultFactory ? defaultFactory() : null,
},
}
},
computed: {
[field] () {
return this[id].value
},
},
}
}
<template>
<DynamicScrollerItem
:item="item"
:active="active"
:size-dependencies="[
idState.answering,
data.answer,
isLiveAnswering,
]"
>
<QaItemView
v-bind="getLocalState()"
:state="getVuexGetters()"
v-on="getListeners()"
/>
</DynamicScrollerItem>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
import { ComposeUtils, SyncTo } from './compose'
import QaItemView from './QaItemView.vue'
export default {
components: {
QaItemView,
},
mixins: [
ComposeUtils(),
SyncTo('idState', () => ({})),
],
props: {
item: {
type: Object,
required: true,
},
active: {
type: Boolean,
default: true,
},
},
computed: {
...mapGetters([
'user',
'liveAnswer',
]),
isLiveAnswering () {
return this.liveAnswer && this.liveAnswer.questionId === this.item.id
},
},
methods: {
...mapActions([
'sendAnswer',
'sendUpvote',
'sendDownvote',
]),
},
}
</script>
<template>
<div class="question-item">
<div class="question">
<p>{{ item.question }}</p>
<button :class="{ voted: item.hasVoted }" @click="toggleVote">+1</button>
</div>
<div v-if="isLiveAnswering" class="live-answer">Is answering live!</div>
<div v-else-if="state.user.isHost">
<form @submit.prevent="postAnswer">
<input v-model="idState.answer" :disabled="idState.sendingAnswer"/>
</form>
</div>
</div>
</template>
<script>
import { IdState } from 'vue-virtual-scroller'
import { mapEvents, SyncFrom } from '@/common/js/compose'
export default {
mixins: [
IdState(),
SyncFrom('idState'),
],
props: {
item: {
type: Object,
required: true,
},
active: {
type: Boolean,
default: true,
},
state: {
type: Object,
required: true,
},
isLiveAnswering: {
type: Boolean,
default: false,
},
},
idState () {
return {
answer: '',
answering: false,
sendingAnswer: false,
}
},
methods: {
...mapEvents([
'sendAnswer',
'sendUpvote',
'sendDownvote',
]),
postAnswer () {
if (this.idState.answer.length > 0) {
this.sendAnswer({
answerText: this.idState.answer,
questionId: this.item.id,
})
this.idState.sendingAnswer = true
}
},
toggleVote () {
if (this.item.hasVoted) {
this.sendDownvote({ question: this.item })
} else {
this.sendUpvote({ question: this.item })
}
},
},
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment