注: 以下の翻訳の正確性は検証されていません。AIPを利用して英語版の原文から機械的に翻訳されたものです。
ほぼすべてのアプリケーションでユーザーインタラクションが必要です。Slate は、インタラクションを有効にするための3つの主要な機能を提供します。
ユーザー入力を受け取る最もシンプルなパターンは、静的なフォームです。入力ウィジェットを追加して固定の選択肢を指定すると、ユーザーの選択をクエリや関数で参照して、動的な表示を提供できます。ただし通常は、1つ以上の入力での選択が、次の入力で利用可能な選択肢に影響する「連鎖した」入力があり、多少複雑になります。この連鎖を短く、理解しやすいものに保つことが重要です。設定するパラメーターが多すぎると、直感的に操作できず、パフォーマンスの低いアプリケーションになりかねません。以下の「制限のない探索」のアンチパターンを参照してください。
このように入力が依存し合う複雑な設定では、フィルターを設定するワークフローと、結果のデータを分析するワークフローを分離することがベストプラクティスです。簡単に言えば、これらのユーザー入力に依存するクエリをすべて manual に設定し、ユーザーがデータを更新するためのボタンウィジェットを用意するということです。このパターンにより、フィルターが変更されるたびにすべてのクエリを再実行して、アプリケーションがリソース(およびユーザーの時間)を浪費するのを防げます。これは、自由入力のテキストを受け取るウィジェット(テキストフィールドまたはテキストエリアの種類のウィジェット)がある場合に特に重要です。そうしないと、クエリなどの下流の依存関係が、ユーザーがキーを押すたびに再評価されます。
アプリケーションがデータをライトバックするためにユーザー入力を受け取る場合は、必ずクエリを手動実行に設定し、ユーザーの明示的な操作でクエリをトリガーするようにしてください。そうしないと、テキスト入力ウィジェットでキーを押すたびも含め、入力が変更されるたびにデータを保存するクエリが実行され、まったく予期しない動作につながります。
有用な表示を得るために、アプリケーションでさまざまな入力を設定する必要がある場合、ユーザーは設定を「保存」して共有したり、後でその設定に戻ったりする方法を求めることがあります。
この機能のカスタムバージョンを作成することもできますが、組み込みの共有可能なビュー機能を使用する方が簡単です。
もう1つの一般的なパターンは、ユーザーが1回の操作ですべての項目をデフォルト値にリセットできるようにすることです。ここで最もシンプルなパターンは、v_defaults 変数を定義することです。
Copied!1 2 3 4 5 6{ "w_multiselectWidget_raw": ["a", "b"], "w_multiselectWidget_display": ["Alpha", "Beta"], "w_textInput": "default", ... }
次に、各ウィジェットの設定で、JSON 定義(</> アイコンの下)にある選択値のプロパティを、そのウィジェットに対応する形でテンプレート化できます。
生の値に加えて表示値もあるウィジェットでは、selectedValues と selectedDisplayValues の両方を必ずテンプレート化してください。
Copied!1 2 3 4 5 6{ ... selectedValues: "{{v_defaults.w_multiselectWidget_raw}}", selectedDisplayValues: "{{v_defaults.w_multiselectWidget_display}}", ... }
最後の手順は、v_defaults 変数の更新をトリガーするイベントを設定することです。これにより、依存関係グラフがすべての下流ノードを更新します。その対象には、選択値がテンプレート化されたすべての入力ウィジェットが含まれ、選択がデフォルトに戻ります。
次のようなイベントを設定するだけで十分に思えるかもしれません。w_resetWidgetButton.click → v_defaults.set
Copied!1 2// v_defaults をそれ自体に設定します return {{v_defaults}}
上記の Slate で処理が発生する理由のセクションで説明したように、ノードの解決後の値が変わっていない場合に、依存関係グラフを「強制的に」再評価させるには少し工夫が必要です。そのため、Slate が新しい値だと認識できるように、「エントロピー」を追加する必要があります。次のようにするだけです。
Copied!1 2 3 4 5 6 7 8// デフォルト値を取得します const defaults = {{v_defaults}} // 乱数を生成します defaults.entropy = Math.random() // 値を設定します return defaults
このパターンを使うと、ユーザーがクリックしてデフォルト値にリセットするためのボタンを簡単に用意したり、クエリが送信された後にデフォルト値にリセットしたりできます。
URL パラメーターを通じて変数の値を設定すると、デフォルト値をさらに活用できます。たとえば、あるアプリケーションからリンクをたどってきたユーザーには、アプリに直接アクセスしたユーザーとは異なるデフォルト値を設定し、さらに、まったく別のツール内の iframe で閲覧するユーザーには、また別のデフォルト値を設定したい場合があります。
これを上記のパターンに組み込むには、複数のプロパティを持つ1個の複雑な変数を使用するのではなく、その変数を「分解」してデフォルト値ごとに1個の変数を用意します。そうすることで、URL 内で変数名を使用できます。この仕組みの詳細については、変数を参照してください。追加の変数を1個用意して「エントロピー」として使用し、それらをすべて関数で組み合わせることで、元々1個の変数に格納していたものと同じオブジェクトを返すことができます。
Copied!1 2 3 4 5 6 7const defaults = { "w_multiselectWidget_raw": {{v_multiSelect_raw}}, "w_multiselectWidget_display": {{v_multiSelect_raw}}, "w_textInput": {{v_textInput}}, "entropy": {{v_entropy}} ... }
デフォルト値に戻したいときは、イベントで v_entropy をランダムな値にリセットするだけで、デフォルト値がリセットされます。
操作を無効にしたり、ユーザーにフィードバックを提供したりするために、ユーザー入力の検証が必要になることはよくあります。Slate ではさまざまな方法でこれを実現できますが、ここでは一般的なケースで役立つことがある、よく使われるパターンを紹介します。この関数は、すべてのユーザー入力を集めてからチェックを行います。各チェックでは、フォームを無効にすることも、ユーザーにフィードバックを提供することも、その両方を行うこともできます。
この例では、タイトル、URL、連絡先名、プロジェクトの説明、プロジェクトのステータスなど、プロジェクトに関する情報を収集するフォームを検証します。ユーザー入力が有効であること(メールアドレスの書式が正しいことなど)と、プロジェクトがまだ存在していないこと(主キーがまだ使用されていないことなど)の両方をチェックします。
最終的に、検証結果を表す JSON 出力を生成します。この出力をアプリケーション全体で参照して、ユーザーにフィードバックを提供したり、特定の操作を無効にしたりできます。
f_validateInputs
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83// ----------------------------- // Collect Inputs for Validation // ----------------------------- // Values coming from user input var inputs = { Project_Title: {{i_projectTitle.text}}, Primary_URL: {{i_primaryUrl.text}}, Contact: {{i_contact.text}}, Project_Quote: {{i_projectQuote.text}}, Status: {{i_status.selectedValue}}, } // Other values useful for validation var uniqueTitle = {{q_searchDuplicateProject.result.[0].hits.length}} ? false : true // -------------------- // Initialize Variables // -------------------- // Global flag to determine if the action should be disabled var disable = false; // Messages to display to the user var messages = []; // Text to display in the 'Save' button var button_text = "Save " + (inputs.Project_Title ? inputs.Project_Title : "") // -------------------------------- // Implement Form Validation Checks // -------------------------------- // For all new projects, check if the `title` is already in use if ({{i_newProjectToggle.selectedValue}} && !uniqueTitle){ disable = true; messages.push(`Title must be unique. "${{{i_projectTitle.text}}}" already exists.`) } // For new projects, check if the title is already a primary key if ({{i_newProjectToggle.selectedValue}} && {{q_checkUniquePrimaryKey.result.[0].rows.length}}){ disable = true; messages.push(`This title conflicts with an existing project. The project was created as "${{{q_checkUniquePrimaryKey.result.[0].rows.[0].primaryKey.project_id}}}" and is now titled as "${{{q_checkUniquePrimaryKey.result.[0].rows.[0].columns.title}}}"`) } // Check if all the required fields have a value if (!(inputs.Project_Title && inputs.Contact && inputs.Primary_URL && inputs.Project_Quote && inputs.Status )){ disable = true; messages.push("Complete all required fields."); } const email_regex = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; if (inputs.Contact && !email_regex.test(inputs.Contact)){ messages.push('Enter a valid email for "Contact Email"') disable = true; } // Check character count for project description if (inputs.Project_Quote && inputs.Project_Quote.length > 140){ messages.push ("'Project Quote' must be less that 140 characters."); disable = true; } // Dynamic Save vs. Update text for the button if (inputs.Project_Title && uniqueTitle) { button_text = "Update " + inputs.Project_Title } return { inputs, disable, messages, button_text }
この関数の出力を使用して、w_submit ボタンの disabled プロパティを {{f_validate.disable}} にテンプレート化できます。また、シンプルなテキストウィジェットで、エラーメッセージを赤色の警告として表示することもできます。
Copied!1 2 3{{#each f_validateForm.messages}} <div class='pt-tag pt-intent-danger pt-minimal'>{{this}}</div> {{/each}}
これは非常にシンプルな例であり、簡単に拡張して、チェックごとのメッセージを特定のウィジェットの横に表示したり、特定のウィジェットに適用するクラスを用意して表示を制御したりできます。たとえば、入力ヘッダーを赤色にする CSS を持つ invalid クラスを適用できます。
固定値の入力ウィジェットでは対応できそうにない入力を受け付ける必要がある場合があります。多くの場合は、問題の捉え方を変えることでシンプルな解決策が見つかります。しかし、ユーザーがより複雑なフィルターを作成できるようにする必要がある場合や、固定値の入力をどのように工夫して使ってもユースケースを実現できそうにない場合を考えてみましょう。
このワークフローには繰り返しコンテナウィジェットを使いたくなるかもしれませんが、このウィジェットは表示専用です。繰り返しコンテナ内で入力ウィジェットを使用することはできますが、そのスコープはそのコンテナのみに限定され、同じコンテナ内の別のウィジェット以外からは、その入力ウィジェットのどのインスタンスも参照できません。
代わりに、入力のインスタンスを1つだけ用意し、ユーザーが選択内容を「保存」できるようにすることで、繰り返し選択できるようにします。蓄積された選択内容を HTML ウィジェットに表示し、以前の選択内容を削除する機能を組み込むこともできます。
このパターンを実装するには、空の配列([])に設定した変数 v_userSelections を使用します。その後、ユーザーが選択内容を保存するボタンをクリックするたびに、この変数を更新できます。
w_saveSelection.click → v_userSelections.set
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15// 既存の選択内容を取得します const userSelections = {{v_userSelections}} // 入力ウィジェットの現在の状態から新しい選択内容を取得します const newSelection = { primaryCategory: {{w_primaryCategory.selectedValue}}, secondaryCategories: {{w_secondaryCategory.selectedValues}} ... } // 新しい選択内容を以前の選択内容と結合します userSelections.push(newSelection); // 変数の値を更新します return userSelections;
さらにイベントを実装して、ユーザーが既存の選択内容を操作できるようにすることもできます。最も一般的なのは、それぞれの選択内容を削除できるように「削除」アクションを用意することです。
このパターンを使うと、ユーザーは任意の複雑さの入力条件を組み立てられます。複雑さが増すことに注意し、上記のイベントセクションで、イベントを多用するパターンの考慮事項を詳しく確認してください。
一般に、このパターンは、以下で詳しく説明する汎用的なステートフルアプリケーションパターンの特定のケースです。
依存関係グラフの性質上、ウィジェットが循環して互いに依存するようには設定できません。入力ウィジェット間の依存関係は下流へと伝わる必要があり、どのフィルターで選択してもすべてのウィジェットに影響するようなフィルター群は作成できません。
共有可能なビューを使うと、ユーザーは Slate アプリケーションの現在の状態を取得し、ほかのユーザーと共有できる一意の URL を生成できます。別のユーザーがその URL を開くと、ビューの作成時と同じ選択内容と設定でアプリケーションが読み込まれます。
共有可能なビューには、次の内容が保存されます。
selectedValue など、ユーザーのインタラクションによって変更できるプロパティです。共有可能なビューの URL が読み込まれると、保存された値がウィジェットとローカル変数のデフォルト値を上書きし、それに応じて下流の依存関係が初期化されます。
共有可能なビューを手動で作成するには、アプリケーションを表示モードで開き、操作ドロップダウンメニューから共有可能なビューを取得を選択します。これにより、共有できるビューID付きの一意の URL が生成されます。
Slate アプリケーションの作成者は、slate.saveView アクションと slate.loadView アクションを使って、共有可能なビューをプログラムで作成および読み込みできます。slate.viewSaved イベントは、ビューが保存された後に発生し、slate.loadView に渡すことができるビューIDを返します。
共有可能なビューには、次の制限事項があります。