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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

6429閲覧

Vue.jsのv-on:changeを外から発火させたい

SystemAjisai

総合スコア171

Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2017/10/11 08:19

編集2017/10/12 01:37

###前提・実現したいこと
勉強のためVue.jsでコードを入力したらAjaxで名称を取得し、名称フィールドに表示するコンポーネントを作りました。
名称を取得する処理はv-on:change="onChange()"で設定し、想定通りの挙動が実現できています。

しかし、実際の社内システムで使うと想定した場合、コード入力を音声でもできないといけません。
音声認識終了の関数(JavaScript)からコードをセットすることになるため、「値が変わった」という判定が行われず、名称取得のイベントが動いてくれません。

現状は、音声認識終了の関数の最後で、

javascript

1$('コードを入力するフィールド').trigger('change');

のようにしてchangeイベントを発火させていますが、
Vue.jsのコンポーネントでは、コードを入力するインプットタグにonchangeイベントが設定されているわけではないので、同じようにやっても名称を取得する処理が動いてくれません。

Vue.jsのインスタンス?の外の、全く関係ないJavaScript関数からv-on:changeで設定したイベントを動かすことはできないのでしょうか?

###該当のソースコード
動作確認は音声認識を使わず「Scriptで値をセットしたらonchangeイベントが動かない」に絞って行っています。
以下は動作確認用のソースです。

javascript

1// ↓値を変える関数(テスト用) 2function changeTest(){ 3 $('コードを入力するフィールド').val('存在するコード').trigger('change'); 4} 5 6// ↓Vueのコンポーネント 7Vue.component('test-codename', { 8 props: { 9 codeId: String, 10 nameId: String, 11 }, 12 template: '<input type="text" ' 13 + 'ref="codesearch" ' 14 + ':name="this.codeId" ' 15 + ':id="this.codeId" ' 16 + 'v-on:input="$emit(\'input\', $event.target.value)"' 17 + 'v-on:change="onChange() >"', 18 methods: { 19 onChange: function(){ 20 var val = this.$refs.codesearch.value; 21 var jqXHR = $.ajax({ 22 type: 'GET', 23 url: (名称取得のurl), 24 dataType: 'json' 25 }); 26 var setId = this.nameId; 27 jqXHR .done(function(data){ 28 if(data == null){ 29 $("#"+setId).val(""); 30 return; 31 } 32 $("#"+setId).val(data["名称"]); 33 }); 34 } 35 } 36})

###試したこと
■trigger('change')でイベント発火を試みる
GoogleChromeでF12を押したら出てくるツールでコード入力フィールドを確認したら
そもそもonchangeイベントが振られてないので、この方法では発火しませんでした。

■watchを使ってみる
watchも値の変更を監視するとあったので試してみましたが、
やはりscriptから値を入れた時だけ名称取得のイベントが走りませんでした。 

■参照を使ってみる?
該当ソースコードの通りコード入力フィールドをref="codesearch"としているので
これ越しにchangeが発火できないか試してみました。

 vueをnewしてるところで
```javascript
var test = new Vue({
el:'#xxxx',
data:{省略},
})

 として、changeTestの中で ```javascript function changeTest(){ // アクセスできるか試してみる  alert(test.$refs.codesearch.value); }

としてみました。
中身を見てみたら$refsはオブジェクトとなっていましたが、codesearchはundefinedになってしまいました。

###補足情報(言語/FW/ツール等のバージョンなど)
Vue.js 2.2.4

###追記:解決しました
mio-cさんの回答から、もう1回音声入力の結果をVueで受け取る方法を考え直してみてうまく実装することができました!
質問のタイトルとは方法になるので、解決方法を記載しておきます。

javascript

1window.SpeechRecognition = window.SpeechRecognition || webkitSpeechRecognition; 2// ↓音声入力APIのインスタンスを入れる変数 3var rec = null; 4 5//コードが変わったときの処理はVueの外に出す↓ 6var codeChange = function(val, setId, url){ 7 if(val==""){ 8 $("#"+setId).val(""); 9 return; 10 } 11 var json = ajax_json(url, val); 12 json.done(function(data){ 13 if(data == null){ 14 $("#"+setId).val(""); 15 return; 16 } 17 $("#"+setId).val(data["名称"]); 18});

コンポーネントのテンプレートの中に、マイクを起動するリンクも入れてしまってクリックした時の処理をコンポーネントのmethodsの中に移動させました。

javascript

1methods:{ 2 onChange: function(){ 3 var val = this.$refs.codesearch.value; 4 codeChange (val, this.nameId, this.url); 5 }, 6 onMicStart: function(){ 7 var setId = this.nameId; 8 var url = this.url; 9 if(rec === null){ 10 // 音声入力のAPI 11 rec = new webkitSpeechRecognition(); 12 : 13 : 14 } 15 // 音声入力が終わったときの処理はonresultに入れる 16 // Vueの中でセットしてもちゃんと動いた 17 rec.onresult = function(event){ 18 var val = event.results[0][0].transcript; 19 codeChange (val, setId, url); 20 } 21 rec.start(); 22 }

やってみれば単純だったのですが、既存の処理をそのまま使おうとしすぎて思いつきませんでした。。。
ありがとうございました!!

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

Vueではinputなどのフォーム要素にはv-modelを使うと楽ですよ。

Vueの外から値を変える方法ですが、直接Vueコンポーネントのデータを変えれば良いのではないでしょうか。

Demo: https://jsfiddle.net/0u2nfr2h/3/

refを使って外からVueコンポーネントのインスタンスを取得できるようにしました。
Ajaxの代わりに適当にsetTimeoutで表示を更新しています。

投稿2017/10/11 13:39

編集2017/10/11 13:40
karamarimo

総合スコア2551

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

SystemAjisai

2017/10/12 00:23 編集

回答ありがとうございます。 v-modelは使っている…と思いま、す。た、たぶん…。 このコンポーネントをいろんな画面で何回も使うので、テンプレ―トのinputタグに書くと名前が固定されてしまうと思い、色々調べてコンポーネントを使う時に書くようにしています。 (理解が甘くて用語がよくわかってないので変な説明ですみません…) ■HTML <test-codename v-model="hoge" ・・・></test-codename> ■Javascript var test = new Vue({ el:'#xxxx', data:{ 'hoge':'aaaa' }, }) これがどうやってテンプレートに書かれているinputタグと結びついたのかちゃんと理解できてませんが、{{ hoge }} で出力してみると値が連動して変わるので、とりあえずOKにしてしまいました…。 Demoまで書いて頂いてありがとうございました! 複数回コンポーネントを使った時に、データのプロパティ名(キー名?)をどうやって特定するかがまだ課題ですが、外からデータの値を変える方法を教えて頂けたので道筋が見えてきた気がします。 ありがとうございました。
karamarimo

2017/10/12 04:44

v-modelはtwo-way-bindingといって、両方向に結びつけます。 たとえばコンポーネント内で <input v-model="message" placeholder="edit me"> というのがあると、コンポーネントのmessageを変更するとinputの表示に反映されるし、ユーザーがinputを変更するとコンポーネントのmessageに反映されます。 その"hoge"が単に親から子に一方向にデータを渡すだけのものなら、v-modelは必要なく、v-bindでいいです。 子がhogeを変更して親にそれが伝わってほしい、というならv-modelが必要になりますが、コンポーネントにv-modelを使う際はちょっとコードが必要になります。 こちらに書かれています。 https://vuejs.org/v2/guide/components.html#Form-Input-Components-using-Custom-Events v-modelはv-bind:valueとv-on:inputのシンタックスシュガーなんですね。
karamarimo

2017/10/12 04:55

あ、すみません。すでに v-on:input="$emit(\'input\', $event.target.value)" でinput eventをemitするようになさっていましたね。 ただ、前コメントのリンクにあるように props: ['value'], を入れておく必要があるかと思います。
SystemAjisai

2017/10/12 07:04

ありがとうございます。 propsにvalue入ってました。 最初にテンプレート作った時に、html拡張タグっぽくしようと思ってnameやclassなどよくある属性をそのままプロパティに入れていたので、valueもその時入れてたみたいです。 読みづらいと思って質問に貼る時に削ってしまっていました。 すみません。。。 教えて頂いたURLの日本語版をいつも読んでるんですが、リンクして頂いたところは全然読んでませんでした。。。 勉強不足で「コンポーネントでv-modelでどう使うんだろう」じゃなくて「こんなことしたい・・・どやって?」というところからスタートするんで、折角のガイドなのに使いこなせてないようです。 また読み直してみます! ありがとうございました!
guest

0

ベストアンサー

音声入力の結果を jQuery で $(el).val() するという想定でしたら
Vue や Vuex のインスタンスを使って変更を直接伝えるか(app1)
mounted などで変更時のコールバックを書く(app2)のはどうでしょう?

ただコードを見た限り jQuery を挟まなくても出来るとおもうので、既存のシステムの修正ではなく新しく作るなら音声データを受け取る時点で Vue で処理するのがいいんじゃないかと。

js

1jqXHR.done((data) => { 2 // ↓ 結果はフォームではなく Vue のデータに入れる 3 if(data == null){ 4 this.inputValue = '' 5 return; 6 } 7 this.inputValue = data["名称"] 8});

おまけ

html

1<div id="app1"> 2 <input type="input" v-model="inputData"> 入力:{{ inputData }} 3 <p><button id="outside1">外部から</button></p> 4</div> 5<div id="app2"> 6 <input type="input" v-model="inputData" id="input2"> 入力:{{ inputData }} 7 <p><button id="outside2">外部から</button></p> 8</div> 9

js

1const app1 = new Vue({ 2 el: '#app1', 3 data: { 4 inputData: 'aaa' 5 } 6}) 7$('#outside1').on('click', event => { app1.$set(app1, 'inputData', 'bbb') }) 8// store.commit('changeData', 'bbb') 9 10const app2 = new Vue({ 11 el: '#app2', 12 data: { 13 inputData: 'aaa' 14 }, 15 mounted() { 16 $('#input2').on('change', event => { 17 this.inputData = event.target.value 18 }) 19 }, 20 beforeDestroy() { 21 $('#input2').off('change') 22 } 23}) 24$('#outside2').on('click', event => { $('#input2').val('bbb').trigger('change') })

投稿2017/10/11 11:56

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

SystemAjisai

2017/10/11 23:46

回答ありがとうございます。 既に動いているシステムが使っている諸々バージョンが古くなっているので、リプレイスするにはどんなもの使ったらどんなふうになるのかを勉強していました。 音声入力結果をVueで受け取るというのは私もやってみようと思ったのですが、既存ソースがwebkitSpeechRecognitionというのをnew して、そのインスタンスに対してonresult(認識終了のイベント)をセットするようになっていて、どうやったらそれをVueに取り込めるかがよくわからず封印してしまっていました。。。 教えて頂いた2つの方法試して両方動かすことができました。 作っているコンポーネントは同じ画面内でも複数使用するので、コンポーネント側ではdata{}の中のプロパティ名(キー名?)をどうやって特定すればいいのかわからず、まだコンポーネントには取り込めていませんが道筋が見えてきた気がします! まだ何を共通化して、何を個別の画面に書けばいいのか理解しきれてないので、整理しつつ完成させたいと思います。 ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問