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

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

ただいまの
回答率

88.91%

input type fileの値をプログラム側で書き換えてサーバーに送信したい

解決済

回答 1

投稿 編集

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

mackintosh

score 211

以下の内容で、初回画像選択時に送信するとサーバー側にファイルが送られていない件で詰まっています。
環境技術等はlaravel, vue, vuetifyといったところですがajax通信は基本使っていません。

以下のソースは一部ですが、LINEのflex messageのような機能を作っています。
wordpressの投稿ページで例えると、見出し、テキスト、画像、動画、これらを4つのコンポーネントとして組み合わせて記事を作っていく感じのものです。

見出し、テキスト、画像、動画、いづれかのボタンを押したら、対応するコンポーネントを画面上に描画するものを作っていましたが
複数の画像だけしか扱わないページがありまして、ユーザービリティー向上のために、ボタンを押したら画像コンポが描画されてそれから画像設定...ではなく、
+ボタン的なものを押下したらPCのファイル選択ダイアログが表示されて複数設定したら複数の画像コンポーネントが描画されていてほしいとのことで以下のテスト実装を試していました。
(以下は説明用に修正してますが実際はコンポ化しています)

⑤のcomponent_typeは送られているのにimage_urlは送られていないという挙動を見るところ、
④のv-file-inputで設定したものではなく、
②で設定したものをimagesに突っ込んで、④のv-modelにマウントさせているからだとは思います。

image_urlはサーバー側に送られませんが、画像コンポはプレビュー付きのコンポにしているので、プレビューには画像が反映されてはいます。

試しに、②で設定して画面に描画されてきた④のv-file-inputで画像を再設定して送信するとimage_urlは送られています。
しかし、これではユーザビリティー向上のためにやっている実装が意味を成しません。

どこかの記事でfileは書き換えられない仕様だということを見かけた記憶があるのですが思い出せずです。
file inputの仕様上無理ということでしたら別のアプローチを考えないといけませんが、やはり無理なのでしょうか?

<template>
  <v-form method="POST" action="test" enctype="multipart/form-data">
    <!-- ③ 結果、ループでfile-inputに割り当てていってる-->
    <v-row v-for="(image, index) in images" :key="index">
      <v-col cols="3">
        <!-- ④ 各v-modelの値もvue developer toolで確認できている。ajax通信にしていないのでname属性指定する作りにしている。-->
        <v-file-input v-model="image['image_url']" :name="'images[' + index + '][image_url]'" />
        <input type="hidden" :name="'images[' + index + '][component_type]'" :value="image['component_type']" />
      </v-col>
    </v-row>

    <v-row>
      <v-col cols="3">
        <!-- ① ボタン押下後、ファイル選択ダイアログが表示される。-->
        <v-btn fab dark @click="clickImage">
          <v-icon dark>mdi-plus</v-icon>
        </v-btn>
        <!-- ② ファイル選択後、images配列にファイル選択数だけ追加していく。-->
        <input ref="image" type="file" accept="image/*" multiple style="display: none" @change="changeImage" />
      </v-col>
    </v-row>

    <v-row>
      <v-col cols="3">
        <!-- ⑤ 送信後、server側でdumpで確認すると、component_typeは送られてきているが、image_urlは送られてきていない。-->
        <v-btn type="submit" v-text="'送信'" />
      </v-col>
    </v-row>
  </v-form>
</template>
<script>
export default {
  data() {
    return {
      is_valid: false,
      images: [],
    }
  },
  methods: {
    clickImage() {
      // ①
      this.$refs.image.click()
      return false
    },
    changeImage() {
      // ②
      for (const file of this.$refs.image.files) {
        this.images.push({
          image_url: file,
          component_type: 3,
        })
      }
    },
  },
}
</script>

試しに、hiddenでimage_urlを追加してみましたがダメでした...

<input type="hidden" :name="'images[' + index + '][component_type]'" :value="image['component_type']" />
<input type="hidden" :name="'images[' + index + '][image_url]'" :value="image['image_url']" />

object Fileになっているので、name属性はfile inputに指定しないといけないみたいです...

  "images" => array:3 [▼
    0 => array:3 [▼
      "component_type" => "3"
      "image_url" => "[object File]"
    ]
    1 => array:3 [▼
      "component_type" => "3"
      "image_url" => "[object File]"
    ]
    2 => array:3 [▼
      "component_type" => "3"
      "image_url" => "[object File]"
    ]
  ]

追記

以下の記事を参考にajax通信でやってみると送信されていました。
http://tech.aainc.co.jp/archives/10714

  methods: {
    async send() {
      const formData = new FormData()
      formData.append('image_url', this.images[0].image_url)
      const config = {
        headers: {
          'content-type': 'multipart/form-data',
        },
      }
      await axios.post('/*****', formData, config)
    },
  },
[2020-07-22 23:52:26] local.INFO: Array
(
    [image_url] => Illuminate\Http\UploadedFile Object
        (
            [test:Symfony\Component\HttpFoundation\File\UploadedFile:private] =>
            [originalName:Symfony\Component\HttpFoundation\File\UploadedFile:private] => スクリーンショット 2020-07-14 12.23.11.png
            [mimeType:Symfony\Component\HttpFoundation\File\UploadedFile:private] => image/png
            [error:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 0
            [hashName:protected] =>
            [pathName:SplFileInfo:private] => /tmp/phpWYMY1n
            [fileName:SplFileInfo:private] => phpWYMY1n
        )

)

ajax使わないでやるパターンはなぜアップロードを認識できていないのか...何が違うのか...

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

0

ajax使わないでやるパターンはなぜアップロードを認識できていないのか

<input type="file">にプログラムから値をセットするには、「.filesFileListオブジェクトを入れる」という特殊な処理をする必要があります。

特に、「1箇所の選択ボックスで一気に複数ファイルを選択して、それを1つずつ<input type="file">に分配する」ような処理をしたい場合、自力でFileListを作成する必要がありますが、これはiOSやIEでは現在のところできません(参考)。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/07/23 19:26

    回答ありがとうございます。

    やはり普通は無理ですよね...
    シンプルにFormDataとajaxでやることにしました。

    キャンセル

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

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

関連した質問

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