値のバインディング
ネイティブのトグル、タブ選択、テキストコントロールは、Webフォールバックが非表示の間にも変わることがあります。現在の値を反映し、表示されたときにフォールバックとアプリケーションが同じ選択を確認できるようにします。これは投影状態とは別です。選択されたタブはコンポーネントのデータであり、描画先をネイティブとWebの間で移す要求ではありません。
たとえば、Webフォールバックが非表示の間にユーザーがネイティブのトグルをオンにしたとします。その後キャプチャが利用できなくなると、変更されていないフォールバックはオフを表示してしまいます。readValuesから現在の真偽値を返し、対応するホストのcheckedプロパティへ対応付けます。アプリのフォーム通知には引き続きコンポーネントの既存アダプターを使い、Engineは表示データだけを揃えます。
この接続は、プラグインの既存のNativeUIProjection初期化で設定します。アプリ側のラッパーは不要です。CapacitorとCordovaの両方の登録で使えます。値はprojectionSelectorが一致する同じ要素に適用され、子コントロールや別のバインド先には適用されません。ion-toggleや、checkedまたはvalueを公開するアプリのカスタム要素など、対応する投影コンテナを選んでください。HTMLのinput、select、textareaは直接の投影コンテナにはできません。これらをラッパーで囲む場合、ラッパー自身の属性監視またはプロパティのsetterが、内側のコントロールに値を渡す必要があります。Engineは内側のコントロールを探索しません。このバインディングはネイティブ登録に属します。低レベルのレンダラーAPIでは、レンダラーの既存の値同期を維持します。
データ属性から始める
readValuesを指定すると値の反映が有効になります。プログラムからの変更を含め、プラグインの現在の値を読み取ります。イベントのペイロードを値の保存場所としては使いません。返された各キーは、デフォルトでdata-native-ui-value-<key>になります。readValuesを省略すると、値の要求を行わず既存の動作を維持します。
たとえば、Swiftの登録に次の引数を指定すると、選択中のタブをdata-native-ui-value-selectedとして公開します。
receiveListeners: .init(update: ["updated", "tabSelected"]),
readValues: { [weak self] in
["selected": self?.selectedTabID ?? ""]
},
キーは小文字を使い、先頭を英字、以降を英字・数字・ハイフンにします。JSON互換の値を返してください。文字列はそのまま書き込み、数値、真偽値、配列、オブジェクト、nullはJSONテキストにします。nullは属性の文字列nullになり、空文字列は空の属性になります。どちらも属性を削除しません。省略したキーは以前の値を維持します。JSONのnullを返すには、SwiftではNSNull()、KotlinではJSONObject.NULLを使います(JSONObject.put(key, null)はキーを削除します)。
Engineは一致するDOMが現れたとき、ページ再接続後、設定されたupdateイベントで値を読み取ります。すでに離れたDOMや、後続の要求に置き換えられた要求への応答は無視します。コールバックはネイティブのUIスレッドで実行されるため、ブロッキング処理ではなく保存済みの状態を読み取ってください。
コンポーネントが必要とするDOMプロパティを選ぶ
対応するWebコンポーネントのホストは、属性を読む代わりにvalue、checkedなどのデータプロパティを公開する場合があります。valuesで必要なキーだけを上書きします。
receiveListeners: .init(update: ["updated", "selectionChanged"]),
values: ["selected": .init(property: "value")],
readValues: { [weak self] in
["selected": self?.selectedTabID ?? ""]
},
Kotlinでの同等の登録引数は次のとおりです。
receiveListeners = NativeUIProjection.ReceiveListeners(
update = listOf("updated", "selectionChanged")
),
values = mapOf(
"selected" to NativeUIProjection.ValueBinding(property = "value")
),
readValues = { JSONObject().put("selected", selectedTabID) },
プロパティへの代入はJSONの型を維持します。真偽値は属性の文字列にならず、真偽値のままです。コンポーネントが対応する書き込み可能なデータプロパティを選んでください。HTML、スタイル、イベントハンドラーのプロパティはバインド先にできません。プロパティの指定は、そのキーの属性への反映を置き換えます。他のキーには引き続きデフォルトのデータ属性を使います。
プロパティバインディングの対象が、まだ定義されていない自律カスタム要素(<my-toggle>など)の場合、Engineは定義されるまで待ってから値を読み取り、代入します。これにより、早すぎる代入で後から用意されるsetterが隠されるのを防ぎます。待機後にDOMの所有権と保留中の更新を再確認します。属性だけのバインディングでは、カスタム要素の定義前でも値を反映できます。カスタマイズされた組み込み要素(<input is="my-input">など)は、カスタム定義名をDOMから確実に取得できないため、プロパティバインディングを有効にする前に定義してください。
アプリケーションイベントはコンポーネントのアダプターに残す
Engineはネイティブの状態とDOMを接続します。フレームワークの双方向バインディングを実装したり、input、change、ionChangeなどのコンポーネントイベントを送出したりはしません。初回読み取り、ユーザーの選択、プログラムによる更新はすべて同じ反映経路を通ります。同時に読み取りが発生した場合は最新の応答を使い、すでに離れたコンテナへの応答は無視します。
アプリケーションへの通知には、プラグインの既存のイベントAPIを使い続けます。ネイティブイベントでアプリのモデルをどう更新するかは、フォームコントロール、カスタム要素、フレームワークのアダプターが決めます。たとえば、タブプラグインのtabSelectedイベントでアプリの選択タブ状態を更新する一方、Engineは現在の選択をフォールバックのvalueプロパティへ別途反映します。イベントハンドラーからDOMを読む際、非同期のEngine更新が完了済みだと想定しないでください。代わりに、プラグインイベントに文書化されたペイロードを使います。
カスタム要素はattributeChangedCallbackで反映された属性に反応したり、setterでプロパティを受け取ったりできます。そのフックで現在の値を描画してください。アプリケーションイベントを発行するsetterは、その固有の動作を維持します。Engineはイベントを抑制せず、汎用的なイベント形式も作りません。プロパティを反映するだけでは、フレームワークのフォームには接続されません。
Engineはネイティブのsetterを呼び出さず、DOMプロパティを監視してネイティブへ値を送り返さず、操作を再実行しません。コンポーネントの既存のWebからネイティブへのハンドラーを維持し、無条件にsetterとイベントが循環することを避けてください。
終了処理後も、反映した値はWebフォールバックで利用できます。Engineは投影状態のマーカーを削除しますが、コンポーネントのデータはリセットしません。