ふぉーむ

Web


Warning: Attempt to read property "site_name" on bool in /home/goodhokkaido/sixwheel.net/public_html/muguruma/wp/wp-content/themes/frame/functions.php on line 208

Warning: Attempt to read property "title" on bool in /home/goodhokkaido/sixwheel.net/public_html/muguruma/wp/wp-content/themes/frame/functions.php on line 211

Warning: Attempt to read property "description" on bool in /home/goodhokkaido/sixwheel.net/public_html/muguruma/wp/wp-content/themes/frame/functions.php on line 217

Nuxt3でNetlify Formsを動かしてみる

Nuxt3をSSRで動かすために、Netlifyにデプロイした際、フォームもNetlify上で動くように色々試したので、メモ。確認画面やサンキュー画面への遷移はjsで操作したかったので、js操作で送信できる方法を探しました。実行環境は以下です。

nuxt 3.6.5
netlify-cli 17.16.0 
node v20.10.0
typescript 5.3.2 

JsでFetchする

下記を読むと、NetlifyFormを動かすにはいくつかの方法があるようです。私の場合、事前にSSGのために作ったプロジェクトがあり、送信機能はphpが担っていました。その部分をNetlifyに担当してもらおうと考えています。そのため、基本はベースを活かして、Netlifyで動くようにカスタマイズする形で作業しました。

Forms setup
Use built-in form handling to simplify adding and managing f…

上記サイトにある下記のSubmit JavaScript-rendered forms with AJAXのコードをもとに、自分のプロジェクトで使っていたtsをアレンジし、組み込むことに。そんなに手間がかからず対応できました。

const handleSubmit = (event) => {
  event.preventDefault();

  const myForm = event.target;
  const formData = new FormData(myForm);

  fetch("/", {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams(formData).toString(),
  })
    .then(() => navigate("/thank-you/"))
    .catch((error) => alert(error));
};
  <form
    data-netlify="true"
    name="pizzaOrder"
    method="post"
    onSubmit={handleSubmit}
  >
    <input type="hidden" name="form-name" value="pizzaOrder" />
    <label>
      What order did the pizza give to the pineapple?
      <input name="order" type="text" onChange={handleChange} />
    </label>
    <input type="submit" />
  </form>

なんか動かない

それを当てはめてみましたが、動かないし、tsエラーも発生します。const myForm = event.targetのところで値をとれていないようなので、console.logeventnetlify devで見てみることに。すると、かなり奥まった場所に、submit◯◯というinputやtextareaで使っているnameと同じ名前の値が取れている場所があります。※submitも@click=”submit”だったので、おそらくsubmitになっていると予想。個人の名付けによって異なるハズです。ここから直接値を取れないかcopilotに聞いてみるとそれらはVueが生成する値くらいしか回答は得られませんでした。試しに、console.logしてみると、その名前だけで値が取れるのがわかりました。これは便利ですね。

次にエラーが出たのが、bodyのところ。typescriptのバージョンによっては、body: new URLSearchParams(formData).toString()が使えないと教えてくれます。そして、個別で拾うしかないとも。結果、typescriptエラーを回避しながらできたのが以下です。form-nameformタグで指定したnameで、contents、userName、emailinputtextarea指定したnameです。これらは必須項目で、任意項目はif文でありなしを判定し、inputで指定したname=”place”に値が入っていれば、FormDataに追加する形にしました。

const submit = (event: Event) => {
  event.preventDefault()
  console.log(event)

  const formData = new FormData()
  formData.append('form-name', 'contact')
  formData.append('contents', submitContents)
  formData.append('userName', submitUserName)
  formData.append('email', submitEmail)
  if (submitPlace) {
    formData.append('place', submitPlace)
  }
  console.log(submitContents, submitUserName, submitEmail, submitPlace)
  const params = new URLSearchParams();
  formData.forEach((value, key) => {
    if (typeof value === 'string') {
      params.append(key, value)
    }
  })

  fetch('/inquiry', {
    method: 'POST',
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: params.toString(),
  })
    .then((response) => {
      if (response.ok) {
        return response.text()
      } else {
        throw new Error(response.statusText)
      }
    })
    .then((result) => {
      console.log(result)
    })
    .catch((error) => {
      console.error(error)
    })
}

さて、そろそろメールが取得できるかなと管理画面を確認しますが、なんの変化もありません。もちろん、管理画面上でもForm detection is enabledですし、受け入れ体制は万全なハズ。フォームもサンキュー画面に移行しているので、大きな問題ではなさそう。コンソールでもエラーは出ていないので、ボタンの掛け違いくらいな間違いの印象です。で、そこから色々検索し、フォームに加えたり、削ったりしました。下記がそのフォーム部分。VeeValidateをいれているので、その部分はそのままです。ボタンが4つあるのは、遷移中にボタンを隠したり、出したりするため。送信ボタンだけがフォームのトリガーです。

<form name="contact" method="POST" data-netlify="true" data-netlify-honeypot="bot-field">
<input type="hidden" name="form-name" value="contact" />
<p hidden>
  <label>Do not fill this out: <input name="bot-field" /></label>
</p>
<dl class="inquiry">
  <dt class="inquiry__ttl">
    <span class="required box__choice">必須</span>
    <label for="contents">内容</label>
    </dt>
  <dd class="inquiry__content">
    <textarea id="contents" v-model="contents" name="contents" class="inquiry__content--textarea input__appearance confirm__element"></textarea>
    <span v-if="errors.contents" class="invalid confirm__element">{{ errors.contents }}</span>
  </dd>
  <dt class="inquiry__ttl">
    <span class="required box__choice">必須</span>
    <label for="userName">名前</label>
    </dt>
  <dd class="inquiry__content">
    <input id="userName" v-model="userName" name="userName" class="inquiry__content--input input__appearance confirm__element" />
    <span v-if="errors.userName" class="invalid confirm__element">{{ errors.userName }}</span>
  </dd>
  <dt class="inquiry__ttl">
    <span class="required box__choice">必須</span>
    <label for="email">メールアドレス</label>
    </dt>
  <dd class="inquiry__content">
    <input id="email" v-model="email" name="email" class="inquiry__content--input input__appearance confirm__element" />
    <span v-if="errors.email" class="invalid confirm__element">{{ errors.email }}</span>
  </dd>
  <dt class="inquiry__ttl">
    <span class="optional box__choice">任意</span>
    <label for="place">在住の区市町村</label>
    </dt>
  <dd class="inquiry__content">
    <input id="place" name="place" class="inquiry__content--input input__appearance place confirm__element" />
  </dd>
</dl>

<ul class="btns">
  <li class="btn__wrap">
    <button class="button confirm" type="button" @click="confirm">確認</button>
  </li>
  <li class="btn__wrap">
    <button class="button reset" type="button" @click="reset">白紙</button>
  </li>
  <li class="btn__wrap">
    <button class="button back" type="button" @click="back">修正</button>
  </li>
  <li class="btn__wrap">
    <button class="button submit" type="button" @click="submit">送信</button>
  </li>
</ul>
</form>

ここまで、.vueファイルだけで、進めてきました。formタグも、トリガーもあるので、心の奥底では行けんじゃねと思ってましたが、メールは届きません。やはり、足りないみたいです。.htmlファイルを作ることを避けてきましたが、しょうがない試しにやってみるかと、ダミーHTMLの作り方を探します。最終的に役立ったのがこちらの記事。やはり、ダミーHTMLは必須のようで、publicフォルダにinquiry.htmlとして作成。FetchのURLをそのダミーHTMLに変更すると、ついに管理画面にメールが現れました。めでたし、めでたし。

Netlify Forms not being detected
Hi there, I’m recently deployed a Netlify site with Netlify …
<form name="contact" method="POST" data-netlify="true">
  <input type="hidden" name="form-name" value="contact" />
  <textarea name="contents"></textarea>
  <input type="text" name="userName" />
  <input type="email" name="email" />
  <input type="text" name="place" />
</form>

コメント