質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.48%

firebaseから値を取得し、vueのdataに保存したい

受付中

回答 0

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 458

score 6

したいこと

Message.jsのpostDataにあらかじめcolor,textの値をセットしておき、ユーザーがtagを入力し、送信ボタンを押すタイミングで値の更新をしたい。

分からないこと

firestore(Message.js)に

tag: {
color: ['purple', 'indigo', 'blue', 'green', 'red', 'orange'],
text: ['HTML', 'CSS', 'JavaScript', 'Vue.js', 'React.js', 'TypeScript']
}


とすることで値をセットしていますが、そこから取得し、TextBox.vueにセットすることが出来ません。

試したこと

created()を使用し、tagオブジェクトのcolor,text配列を格納しようとしましたが、まずそもそもfirestoreから値が取得できず止まっております。

アドバイスいただけましたら幸いです。
宜しくお願い致します。

TextBox.vue

<template>
    <!-- eslint-disable -->
    <div class="textbox-container">
        <client-only>
            <div class="d-flex justify-space-between">
                <div>
                    <p>今日のアウトプット内容</p>
                    <input v-model.trim="time" class="textbox-input" type="number" max="24" min="0" step="0.5" placeholder="3" />
                    時間
                    <!-- <v-combobox v-model.trim="select" multiple label="Tags" append-icon chips deletable-chips /> -->
                    <v-container fluid class="pl-0">
                        <v-combobox
                            v-model="select"
                            multiple
                            outlined
                            :filter="filter"
                            :hide-no-data="!search"
                            :items="items"
                            :search-input.sync="search"
                            hide-selected
                            label="タグを入力してください。"
                            multiple
                            small-chips
                            solo
                        >
                            <template #no-data>
                                <v-list-item>
                                    <span class="subheading">制作</span>
                                    <v-chip :color="`${colors[nonce - 1]} lighten-3`" label small>
                                        {{ search }}
                                    </v-chip>
                                </v-list-item>
                            </template>
                            <template #selection="{ attrs, item, parent, selected }">
                                <v-chip
                                    v-if="item === Object(item)"
                                    v-bind="attrs"
                                    :color="`${item.color} lighten-3`"
                                    :input-value="selected"
                                    label
                                    small
                                >
                                    <span class="pr-2">
                                        {{ item.text }}
                                    </span>
                                    <v-icon small @click="parent.selectItem(item)">mdi-close</v-icon>
                                </v-chip>
                            </template>
                            <template #item="{ index, item }">
                                <v-text-field
                                    v-if="editing === item"
                                    v-model="editing.text"
                                    autofocus
                                    flat
                                    background-color="transparent"
                                    hide-details
                                    solo
                                    @keyup.enter="edit(index, item)"
                                ></v-text-field>
                                <v-chip v-else :color="`${item.color} lighten-3`" dark label small>
                                    {{ item.text }}
                                </v-chip>
                                <v-spacer></v-spacer>
                                <v-list-item-action @click.stop>
                                    <v-btn icon @click.stop.prevent="edit(index, item)">
                                        <v-icon>{{ editing !== item ? 'mdi-pencil' : 'mdi-check' }}</v-icon>
                                    </v-btn>
                                </v-list-item-action>
                            </template>
                        </v-combobox>
                    </v-container>
                </div>
            </div>
            <v-textarea
                v-model.trim="body"
                class="textbox-area"
                label="JSの非同期処理(async,await)について学びました。"
                flat
                auto-grow
                outlined
                rows="1"
                row-height="100"
                max-width="100px"
            />
            <div class="button">
                <Button :on-click="add">
                    <v-icon color="success"> mdi-send </v-icon>
                </Button>
            </div>
        </client-only>
    </div>
</template>

<script>
    import firebase from '../plugins/firebase';
    import { dbMessages } from '../plugins/firebase';
    import MessageModel from '../models/Message';
    import Button from './Button';

    export default {
        components: {
            Button
        },
        props: {
            onClick: {
                type: Function,
                required: true
            }
        },
        data() {
            return {
                time: '',
                body: '',
                canPost: true,
                // tag: {},
                select: [],
                activator: null,
                attach: null,
                colors: ['purple', 'indigo', 'blue', 'green', 'red', 'orange'],
                editing: null,
                index: -1,
                items: [
                    { header: 'タグを選択するか作成して下さい。' },
                    {
                        color: [],
                        text: []
                    }
                    // {
                    //     color: 'purple',
                    //     text: 'HTML'
                    // },
                    // {
                    //     color: 'indigo',
                    //     text: 'CSS'
                    // },
                    // {
                    //     color: 'blue',
                    //     text: 'JavaScript'
                    // },
                    // {
                    //     color: 'green',
                    //     text: 'Vue.js'
                    // },
                    // {
                    //     color: 'red',
                    //     text: 'React.js'
                    // },
                    // {
                    //     color: 'orange',
                    //     text: 'TypeScript'
                    // }
                ],
                nonce: 1,
                menu: false,
                // model: [
                //     {
                //         text: 'Foo',
                //         color: 'blue'
                //     }
                // ],
                x: 0,
                search: null,
                y: 0
            };
        },
        watch: {
            model(val, prev) {
                if (val.length === prev.length) return;

                this.model = val.map(v => {
                    if (typeof v === 'string') {
                        v = {
                            text: v,
                            color: this.colors[this.nonce - 1]
                        };
                        this.items.push(v);
                        this.nonce++;
                    }

                    return v;
                });
            }
        },
        async created() {
            await MessageModel.save({
                tag: {
                    color: ['purple', 'indigo', 'blue', 'green', 'red', 'orange'],
                    text: ['HTML', 'CSS', 'JavaScript', 'Vue.js', 'React.js', 'TypeScript']
                }
            });
            const uid = firebase.auth().currentUser.uid;
            const tag = await dbMessages.where('uid', '==', uid).get();
            console.log(this.items[1]);
            console.log(tag);
        },
        methods: {
            // updateTags() {
            //     this.$nextTick(() => {
            //         this.select.push(...this.search.split(","));
            //         this.$nextTick(() => {
            //             this.search = "";
            //         });
            //     });
            // },
            // async clear() {
            //     this.canPost = false
            //     try {
            //         const message = await MessageModel.clear()
            //         this.onDelete(message)
            //     } catch (error) {
            //         console.error(error.message)
            //     }
            //     this.canPost = true
            // },
            async add() {
                this.canPost = false;

                console.log(this.select);

                try {
                    const message = await MessageModel.save({
                        time: Number(this.time),
                        body: this.body,
                        tag: this.select
                    });
                    this.onClick(message);
                    this.time = 0;
                    this.body = '';
                    this.select = '';
                } catch (error) {
                    alert(error.message);
                }
                this.canPost = true;
            },
            edit(index, item) {
                if (!this.editing) {
                    this.editing = item;
                    this.index = index;
                } else {
                    this.editing = null;
                    this.index = -1;
                }
            },
            filter(item, queryText, itemText) {
                if (item.header) return false;

                const hasValue = val => (val != null ? val : '');

                const text = hasValue(itemText);
                const query = hasValue(queryText);

                return text.toString().toLowerCase().indexOf(query.toString().toLowerCase()) > -1;
            }
        }
    };
</script>

<style scoped>
    .textbox-input {
        margin: 0;
        padding: 0;
        border: 1px solid rgb(161, 161, 161);
    }
    p {
        font-weight: 900;
        font-size: 25px;
    }
    .textbox-area {
        max-width: 80%;
        resize: none;
        background: white;
        border-radius: 5px;
        padding: 0;
        margin: 0;
    }
    .button {
        margin-right: 50px;
        text-align: right;
        padding: 10px;
    }
</style>

Message.js

import firebase from 'firebase';
import { dbMessages } from '../plugins/firebase';

class Message {
    constructor({ id, time, body, date, tag }) {
        this.id = id;
        this.time = time;
        this.body = body;
        this.date = date;
        this.tag = tag;
    }

    static async save({ time, body }) {
        if (!time) {
            throw new Error('入力欄が空欄です。');
        }

        if (!body || !body.trim()) {
            throw new Error('入力欄が空欄です。');
        }

        const uid = firebase.auth().currentUser.uid;

        const postData = {
            time,
            body,
            date: firebase.firestore.FieldValue.serverTimestamp(),
            uid,
            tag: {
                color: ['purple', 'indigo', 'blue', 'green', 'red', 'orange'],
                text: ['HTML', 'CSS', 'JavaScript', 'Vue.js', 'React.js', 'TypeScript']
            }
        };

        const docRef = await dbMessages.add(postData);
        const snapShot = await docRef.get();
        const data = snapShot.data();
        const model = this.create(docRef.id, data);

        return model;
    }

    static async clear() {
        const clearId = [];
        const uid = firebase.auth().currentUser.uid;
        const collection = await dbMessages.where('uid', '==', uid).orderBy('date').get();
        try {
            collection.forEach(doc => {
                clearId.unshift(doc.id);
            });
            return clearId;
        } catch (error) {
            console.error(error);
        }
    }

    static async fetchMessages() {
        const uid = firebase.auth().currentUser.uid;
        const collection = await dbMessages.where('uid', '==', uid).orderBy('date').get();
        if (collection.empty) {
            return [];
        }

        return collection.docs.map(doc => {
            return this.create(doc.id, doc.data());
        });
    }

    static create(id, data) {
        return new Message({
            id,
            time: data.time,
            body: data.body,
            date: data.date.toDate().toLocaleString(),
            tag: data.tag
        });
    }

    static async dbtime() {
        try {
            const uid = firebase.auth().currentUser.uid;
            const querySnapshot = await dbMessages.where('uid', '==', uid).get();
            let totaltime = 0;
            querySnapshot.forEach(postDoc => {
                totaltime += postDoc.data().time;
            });
            return totaltime;
        } catch (error) {
            console.error(error.message);
        }
    }
}

export default Message;
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

まだ回答がついていません

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.48%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る