- 投稿日:2020-03-31T23:22:04+09:00
CognitoでSign in with Appleを実装して当たった壁
はじめに
2019年11月、Amazon CognitoがSign in with Apple1をサポートしました。
公式記事はこちら触れる機会があったので、この記事では以下の事柄についてまとめてみました。
- Cognitoを利用して、Appleでサインインできるようになるまで
- Sign in with Appleの特徴
- 実際にぶち当たった壁
想定読者
- ★★★これからAppleのアカウント連携を利用して何かしたい人★★★
- OAuthとか認証認可なにそれ美味しいの状態の人
- 筆者も依然勉強中のため、詳しすぎる人はちょっと御免です(アドバイスは歓迎します!)
- Vueにさくっと触れてみたい人(サンプルアプリあります!)
お断り
Sign in…と言いつつ、この後日本語で「ログイン」や「ログアウト」という言葉が多数出てきます。
- Sign in=ログイン
- Sign out=ログアウト
と読み替えてください。
Cognitoを利用して、Appleでログインできるようになるまで
いきなりですが、簡単にものづくりしましたので、説明します。
なお、この内容は、AWSの公式ブログ(英語)や、Classmethodさんの記事とかなり重複したため、一部省略があります。ご了承ください。
#逆にこれらのドキュメントで設定できたので、信頼できるということです!ものづくり概要
3つの画面で構成されるウェブアプリです。
実際には色んなAPIが飛んでいるのですが気にしない。
- トップ画面
- Appleの認証情報を入れる画面(Appleが用意したページ)
- ログイン後の画面(ログインユーザの情報を取得して表示)
設定その1:Apple Developerでのアプリ登録および設定
⚠ Apple Developerに登録していない場合は、こちらから登録してください。
なお、個人の場合は年額諭吉さん1枚以上かかります…頑張りましょう…Apple Developerのページに進めたら、フッターから証明書、ID、プロファイル(英語)をクリックしてください。
App IDの登録
左のバーをIdentifiers、右上のプルダウンをApp IDsにセットします。
新規に登録する場合は、+マークをクリックして必要事項を入力します。
既存のアプリを編集する場合は、一覧から選択して必要事項を入力します。
Capabilitiesの一覧から、Sign In Appleを有効にすればOKです。
※ちなみに、Descriptionに記載する名称は、エンドユーザに表示されるアプリ名になります。
※ちなみに、Descriptionには英数字しか使えないという制約があります。
Service IDの登録
こちらもAppIDと同様の手順で+マークから作成します。
Sign in with Apple関連の設定では、以下を記載します。
- Primary App ID: 前節で設定したApp IDを選択
- Domains: Cognitoのドメインを設定(後述)
- Return URLs: Cognitoのドメイン +
/oauth2/idpresponse
Keyの登録と取得
認証用のキーを作成します。これも、左のバーにあるKeysから簡単に登録できます。
Editから登録したいApp IDを選択するようにしましょう。作成すると、Key IDと鍵(.p8ファイル)がダウンロードできるので、ダウンロードしてください。
このページを離れると、ダウンロードはできませんので再生成が必要です。
設定その2:Cognitoへの登録
次に、Apple Developerで登録した設定値をCognitoに書き写します。
⚠ ユーザプールがすでに作成されている前提です。
わからない方でもこちらの記事やAWSの公式ガイドがかなりきっちりと書かれているので、トライしてみてください。⚠ Apple側に設定するCognitoのドメインは、アプリクライアントの作成時に設定しています。
Amazon Cognitoドメインの方が作成が楽だったので、今回はこちらで作成しました。
さて、ユーザプールが作成できたら、左のバーからフェデレーション>IDプロバイダーを選択します。
すると、Appleがあるので、ここまで設定した値を流し込んでいけばOKです。
項目名 値 AppleサービスID Service ID登録時に設定したIdentifier チームID Apple DeveloperのTeam ID(App IDの画面で表示されています) キーID Key登録後に表示されたKey ID プライベートキー .p8ファイルをそのままアップロードでOK 承認スコープ 任意(ここで設定した項目値をログインユーザからもらうことになります) ちなみに、今回はEメール、名前をアプリに表示させるので、共に取得する設定にしました。
有効化させればほぼ完成!あとは、Cognitoユーザプールの属性と、Sign in with AppleでもらうEメール、名前を
属性マッピングの設定でマッピングすると完成です。Webアプリの実装
お待たせしました。
Apple、Cognito双方の準備が出揃ったので、あとは概要にあるようなアプリを作って結びつけましょう。
・・・とはいうものの、ここはガッツリ省略します。
サンプルアプリをVueで実装してみたので、是非自分で環境を作ってお楽しみください。
https://github.com/taniyuu/sign-in-with-apple-sampleちなみに、今回はaws-amplifyを使って、ログイン/ログアウトを実装しました。
以下は擬似コードですが、コアなところは数行で書けます。// User PoolのIDや、Cognitoドメインを設定したりする import Auth from '@aws-amplify/auth' Auth.configure(config) // ログイン Auth.federatedSignIn({provider: 'SignInWithApple'}) // ログアウト Auth.signOut()Sign in with Appleの特徴
この章は、開発者というよりかは、1ユーザとして、このサービスの面白いところを上げていくコーナーです。
※Apple公式の受け売りみたいになってしまいました。Apple IDでアプリを管理できる
よく考えると、このようなサービスは山ほどあって、例えるなら
- AndroidユーザにとってのGoogleアカウントでログインして利用
- WindowsユーザにとってのOffice365アカウントでのログイン(企業向けではよくあると思います)
のiPhone、Macユーザ版に過ぎないです。(もちろん、WindowsでもApple ID自体は使えますが)ただ、Apple IDをWebモバイルアプリに
献上提供することで、ユーザ側でも管理できるようになりました。
https://appleid.apple.com/account/manage で「Apple IDを使用しているAppとWebサイト」
というところから、このようにSign in with AppleでログインしたWebモバイルアプリが一覧で見れるようになりました。Touch IDやFace IDが使える!
何よりもこれが操作性を向上させている感じがしました。ユーザ名とパスワード入力いらず。
基本的にはApple Payなどと同様な感覚で、認証させたいんでしょうね。
実際にぶち当たった壁
このようなエンドユーザにとっては願ったり叶ったり感のある機能ですが、開発者にとっては結構大変なようです。
Cognito×Appleのみで起こる事象もありました。事実を記載することに注意しつつ、この章では、これから作ろうと思う人への注意点を書きたいと思います。
名前はアプリごとに好みに設定できる
初期設定時に、元々の名前から変更するようなフォームがあります。
面白いと言えば面白いですが、エンタープライズ向けに管理するような類には向いてないかもです。【Cognito特有?】姓名が逆転しており、姓名別に取得できない
先ほどのフォームでログインした後の画面です。
ここまで出来上がりの画面を見せなかったのはここで物申したかったからです。
画面は「Welcome to Your Vue.js App」の下に、ユーザ名とアドレスを表示する仕様です。
ご覧の通り、ユーザ名の姓名が逆転しています(想定は「taniyuuです」)。
私の実装では姓名まとまった単位でしか取得できませんでした。一部のネイティブアプリを実際に利用してみたときには、姓名分かれているアプリもあったので、この点は調査したり独自実装が必要かもしれません。2
メールアドレスが隠蔽できるので、アプリ or インフラ対応が必要
先の画像でお気づきかもしれませんが、メールアドレスの部分をあえてマスクしませんでした。
隠蔽できるというと聞こえが悪いかもしれませんが、Appleのプライベートアドレスというものを設定して登録に利用できます。
※ランダムに指定されるのでエンドユーザの好きな文字列にはできません。この場合なにが起こるかというと、例えば登録者にメール配信する場合に、直接このEメールアドレスに送信しても、エラーになります。
アプリのドメインが正式ですよーというのを、Apple側に認識させなければなりません。3この課題に対応する手順には触れません(今回の記事の領域を大きく超える)が、以下の記事がトライしていたので参考になるかと思います。
https://notes.tret.jp/sign-in-with-apple-private-email-relay-service/【Cognito特有】 Touch IDなどでアプリ名がnullになる
今回私の実装はWebアプリですが、iOSアプリでも利用できます。
ただその場合に顕在化した問題があるようです。aws-amplifyのissueとして挙げられています。
上記ページから抜粋したものですが、Touch ID、Face IDの場合にアプリ名がnullになってしまうようです。
【Cognito特有】【解決済】初回ログインでTouch IDなどを利用した場合、Eメールや名前が連携されない
実は前掲のissueで、別の問題も議論されていました。
Cognitoの承認スコープでEメール、名前を設定したにも関わらず、Touch ID、Face IDでログインしようとした場合に、設定が出てこず、結果としてユーザプールにも連携されていないというバグがありました。
前の画像と比較すると一目瞭然かと思いますが、3月上旬に修正され、想定通りの挙動になりました。
まとめ
本記事では、CognitoからSign in with Appleを利用する手順から、実際に当たった壁について記載しました。
最後に言うのも何ですが、Appleのアプリでアカウント連携を実装しているものは、
2020/4末2020/6末4までにAppleのログインも実装せよという話があり、界隈ではザワザワしていた、というのを後になって知りました。5私はApple関連のサービスを使った実装をしてみたのは今回が初めてでしたが、実装の手軽さとTouch IDが使えるスマートさはピカイチでした。一方で、Googleなど他のID連携サービスと比べて独自路線を行っているのも事実であることから、Cognitoにおいても細かい問題が発生しているようです。
最初の想定読者に「★★★これからAppleのアカウント連携を利用して何かしたい人★★★」と書いたのはまさにここに帰着していて、「AppleのアプリはDeadlineに向けて頑張れ!」ですが、その他のWebアプリをはじめとする「ちょっと時間ある人」にとってのInput資料、Tipsになってもらえれば幸いです。
「Sign
I
n with Apple」と書いてあるページもたまに見かけるのですが、現在調べると小文字が正式のようです。 ↩姓名が取れるようにも見える参考ガイド https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_js/configuring_your_webpage_for_sign_in_with_apple ↩
「Private Email Relay Service」というAppleのサービスに対応することになります。その名の如く、実際のメールアドレスにリレーしてくれるサービスです。 ↩
このご時世で延長されました。 ↩
- 投稿日:2020-03-31T20:55:22+09:00
仮想環境でRails API × Nuxt.jsのアプリケーション開発をしたいが、まずブラウザに表示されない!
自己紹介
- 現在プログラミングの学習中の者です
- 言い回しや知識に関して、諸所間違い等あるかと思います
- その際は、ご指摘いただけますと幸いです
やりたいこと
RailsをAPIとして使用し、Nuxt.jsをフロント側に使用する開発において、
それらを仮想環境で開発を開始すること。具体的には、@saongtx7様が書いてくださった
こちらの記事を仮想環境で進めたいと思ったことがきっかけです。[入門]Rails API × Nuxt SPA × Firebase Authで作る Todo Appチュートリアル
https://qiita.com/saongtx7/items/d97ef5aec393e704fd3f本当に素晴らしいチュートリアルでした。
この場を借りて感謝申し上げます。問題点
私の場合このような問題が起こりました。
- Rails側でポート指定をしてもブラウザに表在されない(rails s -b 5000)
- Rails側でポートを指定せずに起動した場合、Nuxt.jsとポート番号が競合する
結論
1.Vagrantfileへ追記をする
まず、仮想環境のあるディレクトリに移動してください。
Vagrantfileがあると思いますのでテキストエディターで起動し、以下の追記をお願いします。
Vagrantfile
//省略 config.vm.network "forwarded_port", guest: 3000, host: 3000 config.vm.network "forwarded_port", guest: 5000, host: 5000 #追記! //省略2.Railsで起動をする際に-b 0.0.0.0を指定する。
大前提としてrails new --apiができており、アプリケーションのディレクトリは完成しているものとします。所定の場所に移動したら、ターミナルで以下を入力し、起動してください。
rails s -b 0.0.0.0 -p 5000
3.Nuxt.jsのpackage.jsonを書き換える
こちらも大前提として、npx create-nuxt-appができているものとします。所定の場所に移動する前に、テキストエディターでディレクトリを開き、直下のpackage.jsonを開いてください。
package.json//省略 "scripts": { "dev": "HOST=0.0.0.0 PORT=3000 nuxt", //変更後 "build": "nuxt build", "start": "nuxt start", "generate": "nuxt generate" }, //省略これができたら、通常通り
npm run dev
(yarnでインストールしている方は違うかも…?)そして、
locallhost:3000
にアクセス。
自分はこれで解決し、無事仮想環境でもRails/Nuxtの同時起動ができました!参考
初学者ながら加筆させていただいた部分としましては、
- Rails s時の書き方
- Vagrantfileの書き方
以上になります。
超独学プログラマ様の以下の記事に救われました。
本当に何日も悩みましたので・・・Nuxt.jsからRailsへ、初めてのapi通信でHelloを表示しよう
https://blog.cloud-acct.com/posts/spa-nuxt-firstapi/最後に、初投稿となりますので至らない点もあるかと思います。
何かお気づきの点がございましたら、後学のためご指摘をお願いいたします。
この記事が誰かのためになれば幸いです。
- 投稿日:2020-03-31T20:37:09+09:00
【vue】 Vueインスタンスの出力結果を調整したい
はじめに
フロント側からAPIでサーバ側から情報取得する際に、取得データの日時がunixタイムで、このunixタイムをフロントで受けたときに、画面に表示したい場合の方法をメモします。
内容
結論
filtersプロパティを使う。
詳細
<template> <div v-for="list in lists"> <!-- ←適当にv-forでぶん回して要素を持ってくる --> <p> {{ list.datetime | datetime }} </p> </div> </template> <script> export default ({ filters: { // 以下でunixタイムをフォーマットするようにする datetime: function(unixtime) { // フォーマット処理 } } }) </script>上記のように、templateの内部のhtml要素に、変換したいものと実行したい関数をパイプで結ぶ。
filters はVueインスタンスの出力結果を調整するのに使います。 |(パイプ) で区切ることで呼び出せます。ただし、構成によっては不必要に呼ばれる場合などあるので
computedプロパティの中で定義してもいいと思います。<script> export default ({ computed: { // 以下でunixタイムをフォーマットするようにする datetime(unixtime) { // フォーマット処理 } } }) </script>以上。
- 投稿日:2020-03-31T20:35:46+09:00
Vue.js で Font Awesome を使う
Vue.jsでFont Awesomeを使うのに少しだけ詰まったのでメモ程度に残しました。
npmインストールする
npm install --save @fortawesome/fontawesome-svg-core npm install --save @fortawesome/free-solid-svg-icons npm install --save @fortawesome/free-regular-svg-icons npm install --save @fortawesome/free-brands-svg-icons npm install --save @fortawesome/vue-fontawesomemain.jsに以下のコードを追加
main.jsimport { library } from '@fortawesome/fontawesome-svg-core' import { fas } from '@fortawesome/free-solid-svg-icons' import { far } from '@fortawesome/free-regular-svg-icons' import { fab } from '@fortawesome/free-brands-svg-icons' import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' library.add(fas, far, fab) Vue.component('font-awesome-icon', FontAwesomeIcon)Font Awesomeで使いたいマークを調べる(今回はsearch)
https://fontawesome.com/icons/search?style=solid
iタグをそのまま使わず、「これを使う」の部分のみvueでは使います。App.vue<!-- 先ほどのfasとsearchを入れる --> <template> <div class="app"> <h1>検索<font-awesome-icon :icon="['fas', 'search']" /></h1> </div> </template>詰まったところ
:icon="['fas', 'search']" :icon="['far', 'building']" :icon="['fab', 'artstation']"このようにfas、far、fabの指定し、その後ろにアイコン名を入力する必要あり。
参考: https://fontawesome.com/how-to-use/on-the-web/using-with/vuejs
- 投稿日:2020-03-31T20:35:46+09:00
Vue.jsでFont Awesomeを使う
Vue.jsでFont Awesomeを使うのに少しだけ詰まったのでメモ程度に残しました。
npmインストールする
npm install --save @fortawesome/fontawesome-svg-core npm install --save @fortawesome/free-solid-svg-icons npm install --save @fortawesome/free-regular-svg-icons npm install --save @fortawesome/free-brands-svg-icons npm install --save @fortawesome/vue-fontawesomemain.jsに以下のコードを追加
main.jsimport { library } from '@fortawesome/fontawesome-svg-core' import { fas } from '@fortawesome/free-solid-svg-icons' import { far } from '@fortawesome/free-regular-svg-icons' import { fab } from '@fortawesome/free-brands-svg-icons' import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' library.add(fas, far, fab) Vue.component('font-awesome-icon', FontAwesomeIcon)Font Awesomeで使いたいマークを調べる(今回はsearch)
https://fontawesome.com/icons/search?style=solid
iタグをそのまま使わず、「これを使う」の部分のみvueでは使います。App.vue<!-- 先ほどのfasとsearchを入れる --> <template> <div class="app"> <h1>検索<font-awesome-icon :icon="['fas', 'search']" /></h1> </div> </template>詰まったところ
:icon="['fas', 'search']" :icon="['far', 'building']" :icon="['fab', 'artstation']"このようにfas、far、fabの指定し、その後ろにアイコン名を入力する必要あり。
参考: https://fontawesome.com/how-to-use/on-the-web/using-with/vuejs
- 投稿日:2020-03-31T20:17:08+09:00
【Vue.js】ドラッグ&ドロップができる「Vue.Draggable」を使ってみた
はじめに
以下の学習教材でVueDraggableを利用したので、使い方に関して簡単にまとめておきます。
Vue.js/Vuexを使ってTrello風アプリを作成しよう!
使い方
Vue CLIで使う
npmでインストール。
$ npm i -S vuedraggable $ yarn add vuedraggable # yarnの場合
呼び出し方。(インポートしてコンポーネントとして使う。)
<template> <draggable> <!-- ★ここにドラッグ&ドロップさせたいコンポーネントを挿入 --> </draggable> </template> <script> import draggable from 'vuedraggable' export default { components: { draggable, }, } </script>
group
属性を使うことで他のコンポーネントへドラッグ&ドロップさせる、または他のコンポーネントからのドラッグ&ドロップを受け付けることが可能。
(その際は、互いのコンポーネントを同じname
にする。)
<draggable group="name"> <!-- ★ここにドラッグ&ドロップさせたいコンポーネントを挿入 --> </draggable>
実践編
やさしめ Vue.js チュートリアル(1) ~ Vue CLI でプロジェクト作成と Linter の設定こちらのチュートリアルを参考にVueDraggableの実装までしてみました。
yarnでインストール
$ yarn add vuedraggable $ npm i -g yarn # yarnコマンドが打てない場合はまずはこちらでyarnを導入
App.vueを編集
- <template v-else> + <draggable v-else> <VsRow v-for="todo in todos" :key="todo.id" vs-w="10"> <TaskCard :id="todo.id" :text="todo.text" @remove-task="remove" /> </VsRow> - </template> + </draggable> ~省略~ <script> import TaskCard from "@/components/TaskCard.vue"; + import draggable from 'vuedraggable' export default { name: "App", components: { TaskCard, + draggable }, ~省略~
動作確認⇓
動きました◎
参考サイト
以下のサイトがとても参考になります。
- 投稿日:2020-03-31T19:15:45+09:00
Vue.js+Vuetify.jsを使ったWEBアプリケーション構築 ~モックアップ作成~
はじめに
設計工程で画面レイアウトをExcelやHTMLなどで顧客と調整し、アプリケーションがやっと完成!
いざ、エンドユーザに使ってもらうと、「イメージと違う」、「もっとこうしてほしかった」、「使いづらいから直してほしい」など、せっかく苦労して作成したアプリケーションが喜ばれなかった経験はないでしょうか。エンドユーザには喜ばれたい。でも、調整の為に
- きれいなモックアップを作成する時間はない。
- フロントエンド部分だけ作成して顧客に見せたくても開発環境を顧客に作ってもらうわけにもいかない。
- アプリケーション構築後に顧客要望でUIが変わったときにモックアップのメンテナンスをする時間はない。
などのジレンマもあるかと思います。
SPAはこの問題を解決してくれます。
SPAは基本的にブラウザのみで動作する為、本物のソースコードをほぼそのままモックアップとして提供することができます。
とはいえ、バックエンドとの連携部分については若干モックアップ用のコードを書く必要があります。以前投稿した記事「Vue.js+Vuetify.jsを使ったWEBアプリケーション構築」のサンプルアプリケーションを基にモックアップの作成方法ついて説明したいと思います。
説明
SPAは基本的には本物ソースコードをそのままモックアップとして提供可能ですが、バックエンドとの連携部分はモックアップ用のコードを書く必要があります。
以下にモックアップ用のソースコードについて説明します。axiosのモックモジュール作成
サンプルアプリケーションはバックエンドとの連携にaxiosを使っています。
axiosのモックとして、axios-mock-serverを利用しています。axios-mock-serverはURLとファイルパスでマッピングして、URLに対応するモックモジュールを特定しています。
サンプルアプリケーションで、アクセスするURLとモックモジュールの対応は以下の通りです。
URL リクエストメソッド mockファイル /joho GET /mocks/joho.js /joho POST /mocks/joho.js /joho/:id DELETE /mocks/joho/_id.js ※ファイル名はaxios-mock-serverでの命名規則です。
URLにアクセスした場合の戻り値をmockファイルに実装します。
/mocks/joho.jsconst usersAll = [ {"id": "1", "name": "サンプル 名前1", "mailAddress": "sample1@example.com", "phoneNo": "09000000001", "torokuNichiji": "2020/01/01 01:00"}, // ・・・省略 ]; const usersSelf = [ {"id": "3", "name": "サンプル 名前3", "mailAddress": "sample3@example.com", "phoneNo": "09000000003", "torokuNichiji": "2020/01/03 03:00"}, // ・・・省略 ] export default { get({values, params}) { // params.modeが全データかマイデータかで返すデータを決めます。 let data = (params.mode == 'SELF') ? usersSelf : usersAll; // 検索の場合はparams.nameが指定されているので、データに絞り込みをかけます。 if (params.name) { console.log(params); let regex = new RegExp(params.name, 'i'); data = data.filter(datum => regex.test(datum.name)); } // 1番目がHTTPステータスコード、2番目がレスポンスデータ return [200, data]; }, post({data}) { // 渡されたデータに登録日時を追加してそのまま返します。 data.torokuNichiji = "2019/10/09 10:52"; return [200, data]; } }/mocks/joho/_id.jsexport default { // URLパラメータはvaluesに入ってきます。 delete({values}) { let status = 200; console.log(values); // idが13のデータを消そうとするとシステムエラーが発生します。 if (values.id === 13) status = 500; return [status]; } }これを作成したら次のコマンドを実行します。
("axios-mock-server -b"コマンドのエイリアスです。)$ npm run build:axios-mockコマンドが成功すると、「/mocks/$mock.js」が作成されます。
これでaxiosのモックアップの作成完了です。モックアップの設定
サンプルアプリケーションがaxiosのモックモジュールで動作するように設定します。
/src/.env・・・省略 # モックアップモード # true or false VUE_APP_MOCK_MODE=true ・・・省略/src/axiosObj.jsimport axios from 'axios'; import store from './store'; // axiosのモックモジュールを読み込む import mock from '../mocks/$mock.js' let axiosObj = axios.create({ baseURL: process.env.VUE_APP_API_BASE_URL }); // 環境変数でモックモードに設定されている場合のみmockを有効にする。 // ローディングダイアログを表示したいので、setDelayTimeでレスポンスを遅らせる。 if (process.env.VUE_APP_MOCK_MODE === 'true') mock(axiosObj).setDelayTime(500); // ・・・省略 export default axiosObj;main.js// ・・・省略 import axiosObj from './axiosObj' // ・・・省略 // axiosオブジェクトの設定 Vue.prototype.$axios = axiosObj; // ・・・省略モックアップの作成
サンプルアプリケーションのルートディレクトリで以下のコマンドを実行してください。
$ npm run build:mockルートディレクトリ配下に「dist_mock」ディレクトリが作成されます。この中のindex.htmlをブラウザで開くとサンプルアプリケーションの動作を確認することができます。
おわりに
「dist_mock」を顧客に提供し、本物と同等の操作感を味わってもらうことで、アプリケーション完成後に顧客からイメージと違うなんて言われることがなくなるのではないでしょうか。
- 投稿日:2020-03-31T15:31:20+09:00
Vue.jsによるバリデーションのサンプルを作ってみた(2)
前回実装したリアルタイムのバリデーションがいまいち意図した動作にならなかったので作り直してみました。
See the Pen OJVqPjo by YusukeIkeda (@YusukeIkeda) on CodePen.
watchを使えばよかったみたい
結論から書くと、リアルタイムで入力値を検証するようなフォームを実装する場合は
computed
ではなくwatch
を使うと良いようです。
computed
を使用して実装しようとすると、初回アクセス時の空白の時の入力値が空なのも監視されてしまいますが、watch
ではうまく動きました。HTML・CSS
HTML・CSSについては前回と大きな変更はありません。
HTML・CSS<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>Vue.jsによるサンプルバリデーション</title> <style> [v-cloak] { display: none; } table td{ width: 200px; } table input[type="text"]{ width: 100%; } </style> </head> <body> <div id="app"> <div v-cloak> <p v-show="checkName.valid">{{checkName.error}}</p> <p v-show="checkTel.valid">{{checkTel.error}}</p> <p v-show="checkEmail.valid">{{checkEmail.error}}</p> </div> <table> <tr> <th>名前:</th> <td><input type="text" v-model="checkName.message" value=""></td> </tr> <tr> <th>電話番号:</th> <td><input type="text" v-model="checkTel.message" value=""></td> </tr> <tr> <th>メール:</th> <td><input type="text" v-model="checkEmail.message" value=""></td> </tr> </table> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.6/dist/vue.js"></script> <script src="script.js"></script> </body> </html>JavaScript
JavaScriptについては先程記述したとおり、Vue.jsのバリデーションは
computed
ではなくwatch
で値を監視するようにしました。それによって、初回アクセス時に入力が空の時にバリデーションに引っかかる事がなくなりました。ちなみに、初回アクセス時にバリデーションを検知させたい場合はimmediate:true
を指定する必要があります。
また、deep:true
はオブジェクトの内側のネストされたプロパティの変更を監視したい時に設定するもので、handler
はウォッチャがオブジェクト内の変更を感知した際に実行する処理を記載する場所となります。script.jslet validation = (val, type, max) => { let checkVal = val.message.length; if(checkVal == 0) { val.valid = true; val.error = `${type}は必須です`; } else if(checkVal > max) { val.valid = true; val.error = `${type}は${max}文字以内で入力してください`; } else { val.error = ""; val.valid = false; } } let vm = new Vue({ el: '#app', data: { checkName: { message: '', error: '', valid: false, }, checkTel: { message: '', error: '', valid: false, }, checkEmail: { message: '', error: '', valid: false, }, }, watch: { checkName: { handler(val) { validation(val, '名前', 10); }, deep: true }, checkTel: { handler(val) { validation(val, '電話番号', 10); }, deep: true }, checkEmail: { handler(val) { validation(val, 'メールアドレス', 10); }, deep: true }, } });課題とまとめ
実際に運用されているサイトに組み込むには、以下のようなケースも考えて実装する必要がありそうなのでもう少し改良が必要ですが最低限のたたき台はできました。
追加で考える仕様・すべてのバリデーションを通過したら送信ボタンをアクティブにするような処理。 ・正規表現によるバリデーションの実装。 ・日付、年齢によるバリデーションの実装。 ・電話番号の入力フォームが分割されていた場合の処理。上に挙げた仕様は頻出するので導入するのであれば事前に実装の方針を考えておいたほうが良さそうです。
- 投稿日:2020-03-31T15:31:20+09:00
Vue.jsでリアルタイムのバリデーションを実装してみた2。
watchを使えばよかったみたい
Vue.jsによるバリデーションのサンプルを作ってみたで実装したリアルタイムのバリデーションの実装したときはcomputedを使用したのだけどイマイチ意図した動作にならなかったので、watchで作り直してみた。
HTML・CSS
HTML<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>Vue.jsによるサンプルバリデーション</title> <style> [v-cloak] { display: none; } table td{ width: 200px; } table input[type="text"]{ width: 100%; } </style> </head> <body> <div id="app"> <div v-cloak> <p v-show="checkName.valid">{{checkName.error}}</p> <p v-show="checkTel.valid">{{checkTel.error}}</p> <p v-show="checkEmail.valid">{{checkEmail.error}}</p> </div> <table> <tr> <th>名前:</th> <td><input v-model="checkName.message" /></td> </tr> <tr> <th>電話番号:</th> <td><input v-model="checkTel.message" /></td> </tr> <tr> <th>メール:</th> <td><input v-model="checkEmail.message" /></td> </tr> </table> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.6/dist/vue.js"></script> <script src="script.js"></script> </body> </html>JavaScript
script.jsnew Vue({ el: '#app', data: { checkName: { message: '', error: '', valid: false, }, checkTel: { message: '', error: '', valid: false, }, checkEmail: { message: '', error: '', valid: false, }, }, watch: { checkName: { handler(val) { let checkVal = val.message.length; if(checkVal == 0) { val.valid = true; val.error = "名前は必須です"; } else if(checkVal > 10) { val.valid = true; val.error = "名前は10文字以内で入力してください"; } }, deep: true }, checkTel: { handler(val) { let checkVal = val.message.length; if(checkVal == 0) { val.valid = true; val.error = "電話番号は必須です"; } else if(checkVal > 10) { val.valid = true; val.error = "電話番号は10文字以内で入力してください"; } }, deep: true }, checkEmail: { handler(val) { let checkVal = val.message.length; if(checkVal == 0) { val.valid = true; val.error = "メールアドレスは必須です"; } else if(checkVal > 10) { val.valid = true; val.error = "メールアドレスは10文字以内で入力してください"; } }, deep: true }, } });まとめ
似たような処理が何か所も記載されている。mixinを使えばよさそう。
- 投稿日:2020-03-31T15:31:20+09:00
Vue.jsによるバリデーションのサンプルを作ってみた(改良1)
watchを使えばよかったみたい
Vue.jsによるバリデーションのサンプルを作ってみたで実装したリアルタイムのバリデーションの実装したときはcomputedを使用したのだけどイマイチ意図した動作にならなかったので、watchで作り直してみた。
HTML・CSS
HTML<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>Vue.jsによるサンプルバリデーション</title> <style> [v-cloak] { display: none; } table td{ width: 200px; } table input[type="text"]{ width: 100%; } </style> </head> <body> <div id="app"> <div v-cloak> <p v-show="checkName.valid">{{checkName.error}}</p> <p v-show="checkTel.valid">{{checkTel.error}}</p> <p v-show="checkEmail.valid">{{checkEmail.error}}</p> </div> <table> <tr> <th>名前:</th> <td><input v-model="checkName.message" /></td> </tr> <tr> <th>電話番号:</th> <td><input v-model="checkTel.message" /></td> </tr> <tr> <th>メール:</th> <td><input v-model="checkEmail.message" /></td> </tr> </table> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.6/dist/vue.js"></script> <script src="script.js"></script> </body> </html>JavaScript
script.jslet validation = (val, type, max) => { let checkVal = val.message.length; if(checkVal == 0) { val.valid = true; val.error = type+ "は必須です"; } else if(checkVal > max) { val.valid = true; val.error = `${type}は${max}文字以内で入力してください`; } else { val.error = ""; val.valid = false; } } let vm = new Vue({ el: '#app', data: { checkName: { message: '', error: '', valid: false, }, checkTel: { message: '', error: '', valid: false, }, checkEmail: { message: '', error: '', valid: false, }, }, watch: { checkName: { handler(val) { validation(val, '名前', 10); }, deep: true }, checkTel: { handler(val) { validation(val, '電話番号', 10); }, deep: true }, checkEmail: { handler(val) { validation(val, 'メールアドレス', 10); }, deep: true }, } });
- 投稿日:2020-03-31T07:13:48+09:00
Vue/Vuex/Nuxtのformでinput type='file'を指定するとv-modelが使えない
きっかけ
Nuxt.jsとRails APIを使用してアプリを作っています。
画像アップロード機能をformで作成中、v-modelでひっかかってしまったので
その対処法を載せたいと思います。問題
formで画像をアップロードする場合、HTMLタグのinputを使うと
typeとしてはfile
を選ぶことになると思います。
そしてそこで取得したデータをdata()内のObjectに格納しようと思い、
v-modelを指定しました。<!-- ... は省略を示す --> <template> ... <input type="file" v-model="submittedArticle.image" style="display: none;" /> ... </template> <script> ... data() { return { submittedArticle: { title: "", description: "", image: null }, ... } } ... </script>するとVSCodeからnoticeが
'v-model' directives don't support 'file' input type.
v-modelはtype="file"をサポートしていない、とのことです。
対処法
@change
を使用して対処しました。
画像をアップロードするとこのtype="file"のinputに変化が生じるので、それを見逃さないようinputに@change
をつけて監視します。
そして@change
に画像データを取得するメソッド(下記ではonImageUploaded
)を結びつけることで、画像アップロード時に画像データを取得できるようにします。
あとは画像データを作成・保存するメソッドも作って、それを画像取得後に呼び出します。そこでできたObjectをdata()に格納します。<!-- ... は省略を示す --> <template> ... <input type="file" @change="onImageUploaded" style="display: none;" /> ... </template> <script> ... data() { return { submittedArticle: { title: "", description: "", image: null }, ... } }, methods: { onImageUploaded(e) { // event(=e)から画像データを取得する const image = e.target.files[0] this.createImage(image) }, createImage(image) { const reader = new FileReader() // imageをreaderにDataURLとしてattachする reader.readAsDataURL(image) // readAdDataURLが完了したあと実行される処理 reader.onload = () => { this.submittedArticle.image = reader.result } }, ... } ... </script>