こんにちは!ファンリピートの加藤です。
今回の記事ではボタンを押下する度に新たな入力フォームが追加される機能をbubbleで実装する方法についてまとめていきます。
エレメントやワークフローを様々組み合わせて作成するので、整理しながら進めていくことをお勧めします。ぜひ参考にしてみてください!
\ ホワイトペーパー /
bubbleで実現するアプリ開発とその費用について

【わかること】
・bubbleでのアプリ作成を依頼するときの費用感
・ほかのツールとの比較
・弊社の開発事例の詳細(料金や開発の流れ)
bubbleとは
bubbleとはノーコードツールの名前のことですが、有名で老舗なツールと認識されている方も多いかもしれません。
一般的にウェブアプリケーションを作成しようとするとサーバーサイドとフロントサイドに関する知識やhtml、CSS、Java scriptなどの多数の言語の習得が必要となります。ただでさえ工数も多く必要になり、追加機能を付ける度にデータ構造の見直しなどさらに多くの手間がかかってしまいます。
しかし、ノーコードツールを利用すれば多少の知識は必要になるものの多数の言語習得の必要がなく、工数の大幅な削減が期待できます。
bubbleについての詳細は「ノーコードツール「Bubble」って?特徴・料金・使い方を解説」という記事でも解説しておりますので、気になる方は一度ご覧になってみてください。
実装していく!
任意のページを用意します。ここでは「form」として開発を進めていきます。
データを作成する!
まずはデータ構造などの前提についてご説明します。

OrderというData typeにproduct_name(商品名)、product_price(商品価格)、note(備考欄)のFieldを用意します。今回の実装ではOrderを一つのオーダー単位としていくつかのオーダーをフォームに入力していきます。
あくまでマスタデータとしての扱いではなく、注文や買取に関するフォームを想定して実装していきます。
ではエディターの画面左にある「Data」タブをクリックします。
そして、「New type」にOrderを新たなデータとして作成します。それぞれのデータ型は以下を参照してください。
ここでは商品価格をnumber型として扱います。価格をtext型にして「円」や「ドル」などの情報ごと入力させることもできますが、今回は金額の単位は統一させて考えます。

簡単に見た目を整える
以下のようなUIを目指して作っていくので完成図を思い浮かべながら実装してください。

まずは背景のStyleとLayoutを変更します。
form(ご自分で設定されたページの名前)のStyle Attributeから新しいスタイルを作成します。ここでは「Background」とし、「Edit style」を押下して編集を行います。
Styleを作成する理由はその後に同様のエレメントで同様の色やフォントを扱う場合の管理がしやすいことによります。本記事では「Background」を使いまわすことはないですが、基本的にエレメント作成時に新たなStyleを作る、もしくはすでにあるStyleを選択することにします。

Style「Background」は以下のように設定します。

作成するUIの構成は次の2点です。「入力フォーム」、「完了ボタン」で実装のメインは1番目の「入力フォーム」です。
画面左の「Containers」から「Group」を画面上にドラッグ&ドロップします。こちらでもStyleを「Form_Body」として新しく作成し、以下のように設定します。
ここで注意したいのはGroupのLayoutは格納したいエレメントを想定して、少し大き目で設定するということです。内包させたいエレメントの方がGroupよりも大きい場合、うまくGroup直下にならないことが理由となります。

作成したGroup内に画面左の「Visual elements」から「Text」と「input forms」から「Input」をドラッグ&ドロップします。

はじめに「商品名」に関する入力フォームを作成していきます。Textの表示を「商品名」とし、新しく「Section_title」というStyleを作成します。元のStyleから変更した点はFontを「Noto Sans JP」、Font sizeを「12px」です。


InputはPlaceholderないに「指輪など」と変更し、Styleを「Form_Input」として以下のように設定しました。





すると以下のようなUIとなります。

編集した二つのエレメントを選択し(WindowsではShiftキーを押しながらクリック)、右クリックから「Column container」を選択します。

配置した4つの「Text」をShiftキーを押しながら選択し、右クリックをします。「Croup elements in」から「Column container」を選びます。すると縦で配列されたグループ化が可能になります。
現在のElements treeからもグループ化が完了したことが確認できます。

LayoutからTextとInputの間隔を少し開けたいので、以下のような設定を行います。

入力項目はあと2つあるので、先ほど作成したGroupをコピー&ペーストを行い、各内容を「product_price」、「note」に対応したものに変更します。


1点気をつけていただきたい点はproduct_priceをnumber型と設定したため、Inputのフォーマットをそれに対応させなければいけません。Content placeを「Decimal(10進数)」とし、Shoe thousands separatorにチェックを入れます。すると、3桁ごとにコンマが表示されます。
例:1000000 → 1,000,000

以上のような要領でカード(オーダー一つに対するフォーム)を作成します。完成例は以下のようになります。

「オーダー1」、「×アイコン」を追加し、それぞれ「オーダーの何番目か」、「オーダーの削除」に対応したものになります。各設定は以下のようになります。「Elements tree」と各設定からエレメントの親子関係や設置を参考にしてください。




ここまでで単一のフォーム、つまりカードを作ることができました。Repeating groupによりこのフォームを複数個作る動作をさせます。作成したカードをRepeating groupに格納して以下の設定をします。


次にRepeating group下部に「+」Buttonを追加し、全体をグループ化します。「+」ボタンを押下するたびにフォームが増えていくという内容だったと思いますが、その全容が見えつつあります。それぞれの設定は以下の通りです。



最後に完了ボタンを配置していきます。以下の通りの設定にしていきます。



最後に全体のElements treeを紹介するので親子関係とエレメント名を確認してください。

Repeating groupにフォームを表示させよう!
最初に一連の動作ロジックについて例を簡単に列挙すると以下の通りになります。
pageをloadする
→任意の値をオーダー1に与える
→フォームの値を保存する
→「+」ボタンを押す
→任意の値をオーダー2に与える
→フォームの値を保存する
→「完了する」ボタンを押下
→終了
Repeating groupに表示をさせることから始めていきます。
Repeating groupはすでに格納されているデータ(もしくはステイト)を表示させるものですが、空のデータを「+」ボタンor「×」アイコンに応じて作成、削除させます。そのため空データを入れるためだけのFieldを用意します。

ここでの空データとは具体的に文字、数字を含む8桁のランダムな値とします。
Group Form_listでその値を持たせるための設定を行います。まずType of contentを「text」、Data sourceを「Calculate formula」と選択します。

その後、Typeを「Generate random string」にし、以下のような設定をしてください。こうすれば自動的に今回空データとして扱いたい値が生成されます。

次に生成されたデータをRepeating groupに表示させていくためにCustom statesをしていきます。ここではRepeatingGroup Formに値を持たせます。右上の「i」アイコンを押下後に「Add a new custom state」で値を持たせられます。

state nameを「order_info」、state typeを「Order」とし、リスト化したデータを持つように選択します。

- 生成されたランダムな値によって空のorderができる
- Repeating groupのstateに空のorderを格納
- stateをRepeating groupに表示
というのが想定する流れです。
1は完了したので、2について実装していきます。
画面左の「workflow」タブから、「Click here to add an event…」から「Page is loaded」を選択します。

「Create a new thing…」からTypeを「Order」にし、「item id = Group Form_list’s text」とします。これでPageがロードされるたびに空データを持ったOrderを生成します。

「Set state of an element」から以下のように設定します。Valueの意味ですが「RepeatingGroup Form’s order_info(Repeating groupに持たせたステイト):plus item(追加する) Result of step 1(Step1の結果)」で、要約すると「新しく作成したorderのデータをステイトに追加する」というものです。これで2の要件は達成されます。

3についてデザイン画面に戻って設定をします。
Repeating groupのData sourceをRepeatingGroup Form’s order_info(orderを格納したステイト)としていきます。

ボタンに対応させてフォームを追加するには?
「+」ボタンに対応させて入力フォームを増やす機能を実装します。これは先程の実装とまったく同じworkflowを「+」ボタンに対応させます。
参考のためworkflowを乗せておくので、確認してみてください。


追加した入力フォームを削除するには?
「×」ボタンで追加したフォームを削除するには追加したロジックの真逆をすればよいです。Repeating groupに表示させているのはステイトであるためこちらを削除すれば良いだけです。
「Set state of an element」から以下のように設定します。こちらのValueも要約するとステイトから現在のオーダーを削除するといったものです。

そして、データ上からも対応のオーダーを削除したいので以下のようにデータを削除します。

入力したデータを保存しよう!
Repeating group内でステイトとして持たせた複数データを保存するのは難しいと思いますが、その方法として紹介するのは非常に簡単なものです。
「Enable auto-binding on parent element’s thing」にチェックを入れ、Fields to modifyに対応するデータにします。

そうしたら以下の注意文が出てきます。それにしたがって画面左の「Data」タブから「Privacy」を設定していきます。以上のデータを扱える条件のユーザー(ここでは誰でもできるようにする)がauto-binding可能であるようにチェックを入れます。
すると入力するたびにその内容が保存されていきます。
プレビュー画面から確認してみよう!
画面右上の「Preview」ボタンから実際の動作を確認できます。

以下に私が作成した例のリンクがあるので、ご自身の実装の動作と比較してみてください!
https://blogcontent202305.bubbleapps.io/version-test/form?debug_mode=true
今回の実装では必須項目などの制約がないため画面上に残している情報はすべて自動的に保存されてしまいます。必須項目や指定の条件にあっていない入力を削除したいなどという場合はBackendでの処理を追加する必要があると思います。
まとめ
以上、ボタンに対応するフォーム作成方法でした!
いかがでしたでしょうか?実装次第で本件のようにUXに配慮した使いやすいUIをbubbleでも作ることができます。ステイトを巧に操ることができれば実装の幅が大きく増えると思います。本件で扱った実装方法がご自身の実装にも参考になればと思います。
\ ホワイトペーパー /
bubbleで実現するアプリ開発とその費用について

【わかること】
・bubbleでのアプリ作成を依頼するときの費用感
・ほかのツールとの比較
・弊社の開発事例の詳細(料金や開発の流れ)