概要
記事編集ページの作成
.
編集画面に遷移した際に
編集前の情報がformに入っている状態を作る。
.
Vue.jsもNuxt.jsも触った事がなかったので
めちゃくちゃ苦労した。笑
.
実装中の殴り書きメモはこちら。笑
鬼はまってなにしてるかわからなくなりました。
完成形
_id/edit.vue
<template>
<v-layout justify-center :class="$style.layout">
<v-flex :class="$style.container">
<h2 :class="$style.title">記事編集</h2>
<v-form ref="titleForm" @submit.prevent>
<v-text-field
v-model="title"
type="text"
name="title"
label="タイトル"
data-vv-name="title"
solo
required
outlined
color="#212121"
/>
</v-form>
<v-form ref="contentForm" @submit.prevent>
<v-textarea
v-model="content"
class="textarea"
type="text"
rows="5"
name="content"
label="本文"
hint=""
filled
counter
outlined
color="#212121"
/>
</v-form>
<v-btn
color="cyan"
elevation="4"
ripple
block
depressed
:loading="loading"
class="white--text font-weight-bold"
:class="[$style.button, $style.register]"
@click="submit"
>更新する</v-btn
>
</v-flex>
</v-layout>
</template>
<script lang="ts">
import { Vue, Component } from 'nuxt-property-decorator'
import { Context } from '@nuxt/types'
@Component({
async fetch(context: Context) {
const { store, error, route } = context
const id = route.params.id
try {
await store.dispatch('article/fetchArticle', id)
} catch (err) {
error({
statusCode: err.response.status,
message: err.response.data.message,
})
}
},
})
export default class ArticleEditPage extends Vue {
title = this.article.title
content = this.article.content
loading = false
async submit(): Promise<void> {
this.loading = true
const params = {
title: this.title,
content: this.content,
id: this.$route.params.id,
}
await this.$store
.dispatch('article/updateArticle', params)
.then(() => {
this.$router.push(`/articles/${this.$route.params.id}/detail`)
})
.finally(() => {
this.loading = false
})
}
get article() {
return this.$store.getters['article/article']
}
}
</script>
.
article.js(ストア)
.
export const state = () => ({
articles: {},
article: {},
})
export const getters = {
articles: (state) => state.articles,
article: (state) => state.article,
}
export const mutations = {
setArticles(state, articles) {
state.articles = articles
},
setArticle(state, article) {
state.article = article
},
}
export const actions = {
async getArticles({ commit }) {
await this.$axios.get('/v1/articles').then((response) => {
const articles = response.data
commit('setArticles', articles)
})
},
async articleNew({ commit }, params) {
await this.$axios.post('/v1/articles', params).then(() => {})
},
async updateArticle({ commit }, params) {
await this.$axios.patch(`/v1/articles/${params.id}`, params).then(() => {})
},
async deleteArticle({ commit }, id) {
await this.$axios.delete(`/v1/articles/${id}`)
},
async fetchArticle({ commit }, id) {
await this.$axios.get(`/v1/articles/${id}`, id).then((response) => {
const article = response.data
commit('setArticle', article)
})
},
}
実装手順
主な手順はこちら。
- フォーム、ボタンの作成
https://vuetifyjs.com/ja/components/textarea/
https://vuetifyjs.com/ja/components/text-fields/
こちらを参考にしました。 - ルーティングの設定
http://localhost:8080/article/:id/edit
のようなルーティングにして
どの記事かわかるようにして編集したい。
- id を取得できる vue ファイルを作る
ファイル名をarticle/_id/edit
に変更 - vue ファイルに 渡された id を取得する方法を調べ、実際に取得する
this.$route.params.id
で取得できることを確認。
- 送られた id の記事を vue ファイルにアクセスした時点で API を叩き、データを取得する
ファイルにアクセスした時点で API を叩き、
データを取得する時はfetch を使う。
.
import { Context } from '@nuxt/types'
@Component({
async fetch(context: Context) {
const { store, error } = context
try {
await store.dispatch('article/updateArticle')
} catch (err) {
error({
statusCode: err.response.status,
message: err.response.data.message,
})
}
},
})
.
こんな感じ。
.
article.js(ストア)
export const state = () => ({
articles: {},
+ article: {},
})
export const getters = {
articles: (state) => state.articles,
+ article: (state) => state.article,
}
export const mutations = {
setArticles(state, articles) {
state.articles = articles
},
+ updateArticle(state, article) {
+ state.article = article
+ },
}
export const actions = {
async getArticles({ commit }) {
await this.$axios.get('/v1/articles').then((response) => {
const articles = response.data
commit('setArticles', articles)
})
},
async articleNew({ commit }, params) {
await this.$axios.post('/v1/articles', params).then(() => {})
},
+ async updateArticle({ commit }, params) {
+ await this.$axios.patch('/v1/articles/:id"', params).then((response) => {
+ const article = response.data
+ commit('updateArticle', article)
})
},
}
fetchのdispatch先のactionを追加.
.
APIの繋ぎ込み先は
articles_controllerのupdateメソッドに。
.
成功した時のデータを変数articleにいれて
stateに入れておく。
.
export default class Articles extends Vue {
get articles() {
return this.$store.getters['article/articles']
}
}
.
ここで予め用意しておいたstateの
情報をgetterを介して受け取り
変数articleに格納しておく。
.
export default class ArticleEditPage extends Vue {
title = this.article.title
content = this.article.content
loading = false
.
格納したarticleはここに使用して、
遷移時にフォームに反映されるように設定。
.
export const state = () => ({
articles: {},
article: {},
})
export const getters = {
articles: (state) => state.articles,
article: (state) => state.article,
}
export const mutations = {
setArticles(state, articles) {
state.articles = articles
},
updateArticle(state, article) {
state.article = article
},
}
export const actions = {
async getArticles({ commit }) {
await this.$axios.get('/v1/articles').then((response) => {
const articles = response.data
commit('setArticles', articles)
})
},
async articleNew({ commit }, params) {
await this.$axios.post('/v1/articles', params).then(() => {})
},
async updateArticle({ commit }, params) {
await this.$axios.patch('/v1/articles/:id', params).then((response) => {
const article = response.data
commit('updateArticle', article)
})
},
}
.
今のままだとどの記事の情報を取りに行くのか
指示ができていない。
(ここで結構ハマった)
.
https://ja.nuxtjs.org/api/context/
こちらのサイトでcontextについて調べ、
routeの情報を持っていることを確認。
.
@Component({
async fetch(context: Context) {
const { store, error } = context
try {
+ await store.dispatch('article/fetchArticle', context)
- await store.dispatch('article/fetchArticle')
こんな感じに修正。
.
しかし、
contextの中には今回必要でない情報がたくさん入っている。
.
参照https://ja.nuxtjs.org/api/context/
.
詳細情報を取得するために必要な情報はid
情報のみなのでid
情報のみを渡せるように修正。
.
route.params.id
とする事でvueファイルのid情報を取得できる。
.
@Component({
async fetch(context: Context) {
- const { store, error } = context
+ const { store, error, route } = context
+ const id = route.params.id
try {
- await store.dispatch('article/fetchArticle', context)
+ await store.dispatch('article/fetchArticle', id)
} catch (err) {
error({
statusCode: err.response.status,
message: err.response.data.message,
})
}
},
.
actionも修正
.
+ async fetchArticle({ commit }, id) {
+ await this.$axios.get(`/v1/articles/${id}`, id).then((response) => {
const article = response.data
commit('setArticle', article)
})
},
これで意図した動きをする
実装ができた。
最後にもう一度完成形載せておきます。
完成形
_id/edit.vue
<template>
<v-layout justify-center :class="$style.layout">
<v-flex :class="$style.container">
<h2 :class="$style.title">記事編集</h2>
<v-form ref="titleForm" @submit.prevent>
<v-text-field
v-model="title"
type="text"
name="title"
label="タイトル"
data-vv-name="title"
solo
required
outlined
color="#212121"
/>
</v-form>
<v-form ref="contentForm" @submit.prevent>
<v-textarea
v-model="content"
class="textarea"
type="text"
rows="5"
name="content"
label="本文"
hint=""
filled
counter
outlined
color="#212121"
/>
</v-form>
<v-btn
color="cyan"
elevation="4"
ripple
block
depressed
:loading="loading"
class="white--text font-weight-bold"
:class="[$style.button, $style.register]"
@click="submit"
>更新する</v-btn
>
</v-flex>
</v-layout>
</template>
<script lang="ts">
import { Vue, Component } from 'nuxt-property-decorator'
import { Context } from '@nuxt/types'
@Component({
async fetch(context: Context) {
const { store, error, route } = context
const id = route.params.id
try {
await store.dispatch('article/fetchArticle', id)
} catch (err) {
error({
statusCode: err.response.status,
message: err.response.data.message,
})
}
},
})
export default class ArticleEditPage extends Vue {
title = this.article.title
content = this.article.content
loading = false
async submit(): Promise<void> {
this.loading = true
const params = {
title: this.title,
content: this.content,
id: this.$route.params.id,
}
await this.$store
.dispatch('article/updateArticle', params)
.then(() => {
this.$router.push(`/articles/${this.$route.params.id}/detail`)
})
.finally(() => {
this.loading = false
})
}
get article() {
return this.$store.getters['article/article']
}
}
</script>
.
article.js(ストア)
.
export const state = () => ({
articles: {},
article: {},
})
export const getters = {
articles: (state) => state.articles,
article: (state) => state.article,
}
export const mutations = {
setArticles(state, articles) {
state.articles = articles
},
setArticle(state, article) {
state.article = article
},
}
export const actions = {
async getArticles({ commit }) {
await this.$axios.get('/v1/articles').then((response) => {
const articles = response.data
commit('setArticles', articles)
})
},
async articleNew({ commit }, params) {
await this.$axios.post('/v1/articles', params).then(() => {})
},
async updateArticle({ commit }, params) {
await this.$axios.patch(`/v1/articles/${params.id}`, params).then(() => {})
},
async deleteArticle({ commit }, id) {
await this.$axios.delete(`/v1/articles/${id}`)
},
async fetchArticle({ commit }, id) {
await this.$axios.get(`/v1/articles/${id}`, id).then((response) => {
const article = response.data
commit('setArticle', article)
})
},
}
コメント