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

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

ただいまの
回答率

91.37%

  • Vue.js

    181questions

Vueで親から子に関数を渡す方法

解決済

回答 2

投稿 2017/11/30 09:50

  • 評価
  • クリップ 2
  • VIEW 225

SystemAjisai

score 40

前提・実現したいこと

Vue.jsで自作した子コンポーネントを親から複数箇所で呼び出しています。
そのうちの1つでだけ値の入力後に独自の処理を行いたいため、
親から子に対してコールバック関数を渡したいです。

コンポーネントの中身はテキストボックスにコードを入れると名称を取得してきて隣に表示するというものです。
コールバックで行いたいのは、名称以外の値も一緒に変更するという処理です。
一緒に変更したい値が18個ぐらいあるので、変更したい側に書くよりコード変更時に処理したいと思っています。

Vue.jsのサイトを見るとpropsの型にFunctionが有ったので渡せるのでは?と思っていたのですが、
色々試してみても文字列になってしまいます。
どうやって関数自体を渡せばいいのでしょうか。

該当のソースコード

※コンポーネントのソースが長いので、関数が渡せるかどうか試しているテストコードを載せています。
子コンポーネント

var child =  {
    props:{
        testFnc : Function
    },
    template: "<input type='text' v-on:change='onChange' />",
    methods:{
        onChange:function(){
            this.testFnc("aaaa")
        }
    }
}


親側

window.onload = function(){
    new Vue({
        el:'#vue_contents',
        methods:{
            setTest: function(msg){
                alert(msg);
            }
        },
        components : {
           'child':child
        },
    });
}


呼び出すところ

<child test-fnc="{{setTest}}"></child>


this.testFncに何が入っているかデバッグツールで覗くと「{{setTest}}」が入っています。

試したこと

1.呼び出しのところにv-bindを付けないと文字列になるという記載を見つけて

<child v-bind:test-fnc="{{setExtendInfo}}"></child>


にしてみました。
結果、ページ全体が表示されなくなりました。

2.関数を変数に入れて変数名を渡してみました。

var test = function(){
  alert("呼べてますか…?");
}


無駄な抵抗で呼び出し側でもダブルクォーテーションを取ってみる。

<child test-fnc=test></child>


文字列「test」が渡されました…。

3.そもそも親側でwatchしてコールバックを書いてみる
親のデータとバインドしていたので、親側でデータをwatchしてみました。

 watch:{
   testdata:function(newVal, oldVal){
      alert("ここがコールバックになる予定");
   }
 },


呼ばれることは呼ばれましたが、1文字入力するごとに呼ばれてしまいます。
入力するコードが長さが決まっていないという仕様なので、入力値の長さでチェックすることもできません。

4.3案でフォーカスが当たっている間は処理しないようにしてみる
暫定でコードを入れるテキストボックスにid="testdata"と名付けました。

 watch:{
   testdata:function(newVal, oldVal){
      if (document.activeElement.id === "testdata") {
          return;
      }
      alert("ここがコールバックになる予定");
   }
 },


alertが呼ばれることはありませんでした。
よく考えたら最後の文字が入力されたときに呼ばれてもフォーカスはまだ当たりっぱなしなので、当たり前でした…。

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

言語:Vue.js 2.2.4

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

+1

ハマリポイントがいくつかありました。

  • 入力を受け付けるイベントはchangeではなくinputです
  • 渡す側(親側)の方では必ずハイフンつなぎで小文字でプロパティを書いてください(Vueが守っているHTMLの仕様)。JSで受け取る側では自動的にキャメルケースに変換されます

ということで動きが検証できたコードは下記になります。

var child =  {
  props: {
    testFnc: Function
  },
  template: "<input type='text' v-on:input='onChange' />",
  methods: {
    onChange: function(ev) {
      this.testFnc(ev.target.value)
    }
  }
}; 

new Vue({
  el:'#vue_contents',
  methods:{
    setTest: function(msg){
      alert(msg);
    }
  },
  components : {
    'child':child
  },
});
  <div id="vue_contents">
    <child :test-fnc="setTest" />
  </div>

ただし、子から親へと値を伝達したいということであれば、emitを使うべきです。
あくまでも関数を渡すことは可能だということのみ、示しましたのでご留意ください。

投稿 2017/12/01 02:56

編集 2017/12/01 03:23

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/12/01 09:08

    無事に動かすことができました!
    やりたいのは値が変わったら(というか入力し終わったら)なのでon-inputではなくon-changeにしてました。watchで試したようなことを書いたせいだと思います。紛らわしくてすみません。

    またご指摘頂いた、「渡す側(親側)の方では必ずハイフンつなぎで小文字でプロパティを書いてください」がどこの事かわかりませんでした…。
    propsは「testFnc」で呼び出すところは「test-fnc」にしていたのであっていると思ったのですが…。
    関数も渡すならケバブにしないといけないということでしょうか。

    動かなかったのは関数名を渡す時に{{}}で囲っていたせいだったんですね。
    Vue.jsのver.0.12のページで{{}}で囲って関数を渡していたので、ヴァージョンが上がって何かが変わったんだ!とは思っていたのですが、そこは全く疑っていませんでした。
    なんでちょっと取ってみようと思いつかなかったのか…。

    子から親に値を伝達したいのではなくて、値を入力し終わったというトリガーを子⇒親に伝達したいという趣旨でした。値は親がバインドしているので、案3,4で書いている通り親側でwatchを書いても発火はできています。しかしその方法だと「入力し終わった」が判断できなくて断念しました。
    子側から親のイベントを$emitで発火しなかった理由は、
    ・コンポーネント側で独自処理をしたいかどうかを判別する方法
    ・他でも独自処理がしたくなった場合、どの独自処理を実行するかを判別する方法
    の2つを解決する方法が思いつかず、propsに関数が渡せるようになっていたの、じゃあ渡そうと思った次第です。

    質問後にextendsというのでコンポーネントを拡張できるというのに気が付き、独自処理がしたい場合は拡張したコンポーネントを作ればいいじゃない!と思って更なるドツボにはまっていたので回答頂けて本当に助かりました!
    ありがとうございました!

    キャンセル

  • 2017/12/01 14:39

    ケバブケースにしてましたね(汗)すいません。そこはコピペして動かしてなかったので、私のハマリポイントのようでしたw
    解決したようで何よりです^^

    キャンセル

0

$emit によるイベント発火でできませんか?

投稿 2017/12/01 01:01

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/12/01 08:29

    ありがとうございます。
    根本的に使い方を間違えているのかもしれませんが、本文に記載の通り親側でコンポーネントを複数回呼び出していて、入力後に独自の処理を行いたいのがそのうちの1つだけです。
    $emitで発火する場合はコンポーネント側に記載するのだと思うのですが、
    ・コンポーネント側で独自処理をしたいを判別する方法
    ・他でも独自処理がしたくなった場合、どの独自処理を実行するかを判別する方法
    の2つをスマートに解決する方法を思いつかず、propsに関数が渡せるようになってるんだから渡せばいいじゃないという方向に進んでいました。

    キャンセル

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

ただいまの回答率

91.37%

関連した質問

  • 解決済

    javascriptを使って2つの検索フォームの空検索を禁止する方法

    現在ページに検索フォームを2つ入れています。1つの場合は下記のようなコードで問題なかったのですが2つの場合だとうまく行きません。 <script> function searc

  • 解決済

    アコーディオンメニューの開閉を示すアイコンがうまく機能しない

    アコーディオンメニューを作っています。 スマホ用のもので、親メニューをクリックするとメニューバーの隣のプラスがマイナスとなり中のメニューが表示されます クリックしたメニュー以外

  • 解決済

    JavaScriptで値を取得する方法

    下記<a href="#">1983</a>をクリックしたときに javaScriptで「1983」を取得したいと考えています。 但しidやクラスはありません。 <div>

  • 受付中

    引数の使い方 ジャバスクリプト

    前提・実現したいこと 関数で出した値をほかの関数で使いたいです。 以下Aの一部の値だけBに持っていきたいのですが可能でしょうか。 該当のソースコード function A(){

  • 解決済

    [javascript] シフトキーを押しながら、文字キーを押す場合

    下記のコードは、シフトキーを押しながら(ture)、ひらがな入力の「つ」の文字を押すと、アラートで小文字の「っ」が表示される。 たま、シフトを押さずに(false) 「つ」の文字を

  • 解決済

    外部javascriptの読み込みが行えません

    下記のように、testボタンを押すと、「test」と表示したいのですが表示できません。 'Uncaught ReferenceError: test is not define

  • 解決済

    JavaScriptでタグの削除をしたい。

    下記コードにて bodyとimgのformを作成しているのですが formの中の値を消すのは $('#フォーム名')[0].reset(); で実装はできています。 ただ

  • 受付中

    javascriptについて

    前提・実現したいこと ここに質問したいことを詳細に書いてください (例)PHP(CakePHP)で●●なシステムを作っています。 ■■な機能を実装中に以下のエラーメッセージが発生し

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

  • Vue.js

    181questions