このブログでは、ウィジェットからアプリケーション内のデータを永続的に変更する方法、ウィジェットを組み合わせて優れたエンドユーザー エクスペリエンスを作成する方法、カスタム フックなどについて学習します。
これは複数部構成のシリーズの 1 番目のブログです。ブログ 2 と XNUMX は、こちらからご覧いただけます。 ウィジェットを構築する Mendix React を使う — パート 1 — カラー カウンター の三脚と ウィジェットを構築する Mendix React パート 2 — タイマー.
始める前に、ちょっとした免責事項があります。このビルドでは、VS Code の一部の機能を活用していますが、別の IDE を希望する場合は手順が異なる場合があります。
私たちが構築しているもの
Mendix 最近リリースされた エピック、新しいフル機能のストーリー管理ツールです。
その一部として、ストーリーをドラッグ アンド ドロップできる非常に優れたコンポーネントがあります。同じようなものを作ってみたら面白いだろうと思いました。

すべてのカンバン ボードで実行できる必要がある機能がいくつかあります。
- ユーザーがカンバンステージを設定できるようにする
- ドラッグすることでアイテムのステージを変更できる
- ドラッグすることでセクション内のアイテムの並び順を変更できる
スタートガイド
まず、ウィジェット ジェネレーターを実行してウィジェットを素早くスキャフォールディングし、ウィジェットをスキャフォールディングします。次のコマンドを実行します。
yo @mendix/widget kanban
ウィジェットのプロパティを設定するときは、デフォルトのオプションを選択し、 Typescriptを使用する.
次に、ウィジェットと Mendix Kanban.xmlを更新することで、ウィジェットのユーザーが何を指定するかを指定できるように、データソース項目のリストを追加します。 Mendix 使用したいエンティティ。
ウィジェット内のアイテムを実際にレンダリングするには、従来のJSXを使用するか、ユーザーがウィジェット内で希望するデザインを構築できるようにするかの2つのオプションがあります。 Mendix2 番目のオプションには、主に 3 つの利点があります。
- 子データが表示される構造を規定しないようにします
- 編集が難しいコンパイル済みウィジェットファイル内のコードを隠さない
- ユーザーはWYSIWGエディタを活用できます Mendix
リストのレンダリング
オプション2が勝ちです!これを実装するには、「ウィジェット'タグから プラグイン可能なウィジェット API更新された Kanban.xml には次の内容が含まれます。
アイテムアイテムリストコンテンツデータソースを使用するウィジェット
次に、Kanban.TSX ファイルを更新して次の内容を含めます。
エクスポート関数Kanban({widgetList, items}: KanbanContainerProps): ReactElement { return ( {items.items && items.items.map(item => {return widgetList.get(item);})} ); }
上記のコードではいくつかのことが行われていますので、詳しく説明します。
- 「ウィジェットリスト」ウィジェットインターフェースは Mendix モデルでは、「widgetList」を右クリックして「型定義に移動」をクリックすると、この型のドキュメントが表示されます。
エクスポート宣言インターフェースListWidgetValue {
* 提供されたオブジェクト項目に基づいてレンダリングされた React ノードの形式で、ユーザーが構成したウィジェットを返します。*
* @param item リンクされたデータ ソースからの {@link ObjectItem} のインスタンス。*/
取得: (item: ObjectItem) => ReactNode;
}
これは基本的に、ウィジェットに1つのget関数があり、ReactNodeをレンダリングするためにObjectItemと呼ばれるものを期待していることを示しています。
- 「アイテム」は、ListValue( Mendix定義済みの型)で、「items」を右クリックして「型定義に移動」をクリックすると、この型のドキュメントが表示されます。このドキュメントから、ObjectItemの配列にアクセスできることがわかります。 .アイテム 財産
次に、組み込み関数 JS マップを使用して、アイテム リスト内の各要素を反復処理し、アイテムの 'get' 関数を使用して結果を返します。
- その後、我々 関数をラップする in 中括弧 JavaScriptであることを示し、 親div 各アイテムをレンダリングするために
- 最後に、 三項式 リストに項目がない場合に関数が呼び出されないようにするためです。
テスト
実装をテストするために、ウィジェットの「tests」フォルダにテストプロジェクトを設定します。 ブログ1.
というエンティティを追加します Item 文字列属性を持つ コンテンツ

次にマイクロフローをいくつか追加します After Start Up マイクロフローにいくつかの $Items を作成します。

次にターミナルからウィジェットをビルドします。 npm run build .
私たちが Mendix モデルを選択して F4 キーを押すと、ウィジェットをホームページに配置できるようになります。

ここでは、クラス「カード' とコンテンツを表示する文字列を追加します。そして、出来上がり! レンダリングされます。

ドラッグ&ドロップ
静的なリストを持つことは良いスタートですが、それらのアイテムを移動できるようにする必要があります。
Reactドラッグアンドドロップライブラリを選択しましょう。これは自分で構築できます(そして賢い Mendix 開発者はすでにそうしました!)しかし、 十分にサポートされ、頻繁に使用されるライブラリの幅広い選択肢.
私は 反応-美しい-dnd それは 使いやすい APIであり、非常に 機能豊富な.
次に、ウィジェットディレクトリ(./kanban)に移動してコマンドを実行し、ドラッグアンドドロップライブラリをインポートします。
npm i react-beautiful-dnd .
ドキュメントを読むと、ウィジェットに必要な主な領域が 3 つあることがわかります。

<DragDropContext />– ドラッグアンドドロップを有効にしたいアプリケーションの部分をラップします<Droppable />– ドロップできるエリア。<Draggable />– 引きずり回せるもの
ステップ1 — ドラッグ可能
それでは、まずは最下位レベルから始めて、アイテムをドラッグ可能に変換してみましょう。
まず、ItemList を別の関数に分割しますが、開発を容易にするために今のところはコンポーネント内に保持します (後で別のコンポーネントに移動できます)。
エクスポート関数 Kanban({ widgetList, items }: KanbanContainerProps): ReactElement {
const ItemList = (): ReactElement => {
戻る ( {items.items && items.items.map(item => {return widgetList.get(item);})} );
}
戻る ( ) }
各リスト項目をドラッグ可能にするには、ウィジェットをドラッグ可能なコンポーネントでラップする必要があります。 一意のIDが必要です ドラッグ可能なアイテムの場合 — アイテムを並べるためのインデックス、およびコンポーネントをレンダリングする子関数。
残りの実装については react-beautiful-dnd ライブラリのドキュメントに従って、次のコードを作成します。
const ItemList = (): ReactElement => { return ( {items.items &&items.items.map((item, i) => { return ( {提供 => ( {ウィジェットリスト.get(アイテム)} )} ); })} ); };
ここで行ったのは、ウィジェット コンポーネントを「ドラッグ可能な」ラッパーでラップして、参照とプロパティを渡すことです。
参照は、これらのブログではまだ取り上げていない概念であり、React の重要な部分です。参照は基本的にページ内の要素にアクセスする方法であり、このインスタンスでは、ドラッグされているものを追跡することを目的としています。 Ref と DOM – React.
ステップ2 — ドロップ可能
ドラッグ可能なコンポーネントができたので、ドラッグ アンド ドロップ キャンバスを作成する必要があります。
これを実現するには、上で概説したパターンと非常によく似たパターンを使用して、Draggable コンポーネントの ItemList を Droppable コンテナーにラップする必要があります。
{提供 => ( )}
ステップ3 — コンテキスト
最後に、機能が存在するドラッグ アンド ドロップ コンテキストを提供する必要があります。
{提供 => ( )}
コンテキストでは、アイテムがドラッグされると関数が呼び出されることを期待しています。今のところは、関数が呼び出されたことだけをログに記録しましょう。
現時点でのコードは次のようになります。
エクスポート関数 Kanban({ widgetList, items }: KanbanContainerProps): ReactElement { const ItemList = (): ReactElement => { return ( {items.items && items.items.map((item, i) => { return ( {提供 => ( {ウィジェットリスト.get(アイテム)} )} ); })} ); };
関数 onDragEnd(結果: DropResult): void { console.log("ドラッグされました"); }
戻る ( {提供 => ( )} ); }
走れば npm run build そして、 Mendix アプリでは、カードをドラッグできるようになりました。ちょっと…

この問題については後で再度検討します。最も重要なのは、アイテムをドラッグできることです。
複数の列
つまり、1 つのリスト内で項目を上下にドラッグすることはできますが、実際にやりたいのは、列間で項目をドラッグしてステータスを決定できるようにすることです。
ウィジェットのユーザーが、必要な列の数を指定できるようにしたいと考えています。
これを行うには、 「オブジェクト」 Kanban.xml で、既存のプロパティを次のようにオブジェクト リストにラップするだけです。
セクション名前名前セクション項目アイテムリストコンテンツデータソースを使用するウィジェット
鋭い目を持つ皆さんは、列を追跡できるように名前を付けたことにも気付くでしょう。
あなたが開いたら Mendix 素敵な新しいインターフェースをチェックしてみましょう:

いいですね。でも今度は列をレンダリングする必要があるので、ウィジェットに戻りましょう...
これは実は非常に簡単です。
まず、JSX を更新して、各オブジェクトの列をレンダリングします。
{myObject.map((obj, i) => { 戻り値 ( {提供 => ( )} ); })}
また、 ドロップ可能なID unique にして、ItemList にいくつかのプロパティを渡します。
{myObject.map((obj, i) => { 戻り値 ( {提供 => ( )} ); })}
つまり、新しいプロパティを受け入れるためにアイテム リストも更新する必要があり、ここで、もう少し読みやすいものにリファクタリングしたほうがよいでしょう。コンポーネント フォルダーに 2 つの新しいファイルが作成されます。
ドラッグ可能.TSX
「react」から ReactElement、createElement をインポートします。「react-beautiful-dnd」から Draggable をインポートします。「mendix」から ObjectItem、ListWidgetValue をインポートします。
エクスポートインターフェース DraggableProps { item: ObjectItem; i: number; widgetList: ListWidgetValue; }
エクスポート関数DraggableItem({ item, i, widgetList }: DraggableProps): ReactElement { return ( {提供 => ( {ウィジェットリスト.get(アイテム)} )} ); }
そしてItemList.TSX
「react」から ReactElement、createElement をインポートします。「mendix」から ListValue、ListWidgetValue をインポートします。「./Draggable」から DraggableItem をインポートします。
エクスポートインターフェース ItemListProps { items: ListValue; widgetList: ListWidgetValue; }
エクスポートconst ItemList = ({ items, widgetList }: ItemListProps): ReactElement => { return ( items && ( {items.items && items.items.map((item, i) => { 戻り値; })} ) ); };
スタイリング
醜いアヒルの子を美しい白鳥に変えるには、カンバン ボードにスタイルを追加する必要があります。
これを主に 2 つの方法で実行します。
- CSSクラスを活用し、 'className'プロパティ すべてのDOM要素には
- インラインスタイルを活用して、コード内で計算されたプロパティ(列幅など)を活用する
まず、Kanban.cssファイルを更新しましょう。
.kanban-col { マージン: 15px; パディング: 10px; 背景: #9bedff; 境界線の半径: 15px; }
.kanban-col h6 { テキスト配置: center; }
次に、いくつかの追加の DOM 要素、クラス、およびスタイルを使用して、次のようになります。
「./components/ItemList」から {ItemList} をインポートします。「../typings/KanbanProps」から {KanbanContainerProps} をインポートします。
「./ui/Kanban.css」をインポートします。
エクスポート関数 Kanban({ myObject }: KanbanContainerProps): ReactElement {
関数 onDragEnd(結果: DropResult): void { console.log("dragged"); }
戻る ( {myObject.map((obj, i) => { 戻り値 ( {提供 => ( {obj.セクション名} {提供されたプレースホルダー} )} ); })} ); }
ちょっと待って……あれは何ですか? ${100/myObject.length}%
これは テンプレートリテラル これにより、文字列を “ で記述し、式を ${} で囲むことで、JS で文字列をすばやく構築できるようになります。
しかし、ウィジェットに戻ると、アイテムを含むユーザー定義の列ができました。

ドラッグ&ドロップアクション
ここで、ドラッグ アンド ドロップで実際に何かを実行したいと思います...

これを実現するには、データ ソースと組み合わせて Pluggable Widget アクション API を使用します。
まず最初に、Kanban.xmlのオブジェクトに2つの新しいプロパティを追加しましょう。
セクション項目アイテムリストすべての商品アイテムリスト
アクションをデータソースにリンクすることで、パラメータを指定してアクションを実行できます。 Mendixこれにより、アイテムの属性を変更できるようになります。
これで、「ドラッグ終了時”アクションを実行する関数。
react-beautiful-dnd のドキュメントを読むと、onDragEnd が結果オブジェクトを受け取り、draggableId と droppableID にアクセスできることがわかります。これらを使用して、どのアイテムがドラッグされているか、どこにドラッグされているか (したがって、どのアクションを呼び出す必要があるか) を判断できます。
最初に行うことは、結果を構造化解除して正しいオブジェクトを見つけることです。
const { source, destination } = 結果; const destObj = myObject[parseInt(destination.droppableId, 10)];
ここでは、droppableId(オブジェクトのインデックスに設定)を解析し、それを使用してオブジェクトを取得します。 マイオブジェクト アレイ。
正しいオブジェクトを取得したら、ドラッグされているアイテムの表現を取得することができます。 すべてのアイテム.
const destObjItem = destObj.allItems.items!.find(item => { return item.id === result.draggableId; });
アクションは同じオブジェクトに属するアイテムに対してのみ呼び出すことができるため、すべてのオブジェクトに対して allItems を指定する必要があることに注意してください。
次に、オブジェクトに対してアクションを実行します。
const actionOnObj = destObj.action!.get(destObjItem!); if (actionOnObj.canExecute) { actionOnObj.execute(); }
アイテムがリストにドラッグされたことを確認するためにいくつかのチェックを追加すると、最終的な関数は次のようになります。
function onDragEnd(result: DropResult): void { const { source, destination } = result; if (!destination) { return; } const destObj = myObject[parseInt(destination.droppableId, 10)]; const destObjItem = destObj.allItems.items!.find(item => { return item.id === result.draggableId; }); const actionOnObj = destObj.action!.get(destObjItem!); if (actionOnObj.canExecute) { actionOnObj.execute(); } }
これで、ドラッグ アンド ドロップ カンバン ボードがうまく機能するようになりました。あとは Studio Pro でいくつかの作業を行うだけです。まず、さまざまなステータスを含むステータス属性を追加しましょう。

次に、設定したいステータスごとにナノフローを追加しましょう。

次に、関連するステータスと正しいドロップ時のアクションを持つすべてのアイテムをアイテムとして設定し、AllItems のデータベース内のすべてのアイテムへのリンクを追加して、各セクションを構成しましょう。

ドラッグアンドドロップもあります!

選別
もうすぐ終わりです。あと 1 つ、ソートを導入する必要があります。そのためには、プラグ可能なウィジェットからデータを取得するための便利なパターンを使用します。
理想的には、これをすべて「アイテム」の値を使用して管理しますが、現在、Pluggable Widget API には、リストの一部であるオブジェクトの属性を直接変更できないという制限があります。この制限は、削除される予定です。それまでの間、次のアプローチを取ることができます。
まず、ソート順を Mendix エンティティ: アイテム。

ついでに、ソート値を持つアイテムを毎回データベースに再入力するように ASU を更新します。

ウィジェットに戻り、Kanban.xml を更新して新しい「Sorting」プロパティ グループを追加します。このプロパティ グループを使用して、アイテムをドラッグしたときに、以前の並べ替えインデックスと更新された並べ替えインデックスを保存できます。
新しい並べ替えソート値の保存前の並べ替えソート値の保存
次に、onDrag関数を更新して、これらのプロパティを Mendix モデル:
function onDragEnd(result: DropResult): void { const { source, destination } = result; if (!destination) { return; } const destObj = myObject[parseInt(destination.droppableId, 10)]; const destObjItem = destObj.allItems.items!.find(item => { return item.id === result.draggableId; });
prevSort.setValue(新しいBig (source.index)) newSort.setValue(新しいBig (destination.index))
const actionOnObj = destObj.action!.get(destObjItem!); if (actionOnObj.canExecute) { actionOnObj.execute(); } }
もし私たちが Mendix モデルでは、これらの値を使用して並べ替えロジックを構築できます。
以前の並べ替え値と新しい並べ替え値を保持するエンティティを設定しましょう。

次に、このエンティティを提供するデータ ビューでウィジェットをラップします。

次に、ウィジェットを構成して、並べ替え値をエンティティに渡すことができます。

ウィジェットをデータ ビューにラップしたので、onDrag で実行されるアクションに KanbanHelper をパラメーターとして追加できるようになりました。

私たちは、それぞれの onDrag ナノフローで主に 3 つのことを行います。
- ストア 開始ステータス アイテムの(これは、並べ替え計算のためにアイテムの列が変更されたかどうかを判断します)
- アイテムを更新する 新しいステータスと 新しいソート 値
- 実施する ソートロジック 残りのアイテム
ソートロジックについては、サブナノフローで構築できます。

ここでは、これがどのように組み立てられたかの詳細には触れませんが、 ナノフローは、 Githubレポ.
次に、アプリケーションを実行して最後にもう一度テストします。

製品概要
これで、歌って踊れるカンバンボードが完成しました。 react-beautiful-dndライブラリと、 Mendix ウィジェットといくつかのシンプルなナノフローを使用して、完全に機能する、ユーザー定義可能なカンバン ボードを構築します。
このウィジェットの最終状態は次のようになります: GitHub – joe-robertson-mx/カンバンウィジェット
このカンバン ボードを実装し、作成したものを披露したい場合は、以下のコメント欄で共有してください。
次に 実装について見ていきます マップ プラグ可能なウィジェットで、複雑な外部ライブラリの使用方法や、ビルドにカスタム ファイルを含める方法を検討します。