動的データを使用した、SharePoint Framework コンポーネントの接続

2 つ以上の SharePoint Framework コンポーネントを接続して、動的データ を使用して両者の間でデータを交換できます。 この機能により、豊富なエクスペリエンスと魅力的なエンドユーザー ソリューションを構築することができます。

イベントに関する情報を表示する、相互に接続されている SharePoint Framework の 3 つの web パーツ

注:

動的なデータは、クライアント側 Web パーツと拡張機能を含む SharePoint Framework コンポーネント間でデータを共有するための推奨パターンです。 これは、SharePoint Framework v1.7 で導入されました。

動的データ ソースを使用したデータの公開

SharePoint Framework の動的データは、ソース通知モデルに基づいています。 動的データソースという名前のコンポーネントは、データを提供し、データが変更されたときに SharePoint Framework に通知します。

ページ上の他のコンポーネントは、動的データ ソースが発行した通知をサブスクライブできます。 SharePoint Framework は、ソースがデータの変更を通知したことをコンシューマー コンポーネントに通知します。 その後、コンシューマー コンポーネントは、ソース コンポーネントからデータを要求します。

すべての動的なデータ ソースは、IDynamicDataCallables インターフェイスを実装します。

次のコードは、今後のイベントのリストを表示する Web パーツを示しています。 イベント Web パーツは、選択されたイベントの情報をイベントに関する完全な情報と場所のアドレスという 2 つの方法でページの他のコンポーネントに公開します。

import {
  IDynamicDataPropertyDefinition,
  IDynamicDataCallables
} from '@microsoft/sp-dynamic-data';

export default class EventsWebPart extends BaseClientSideWebPart<IEventsWebPartProps> implements IDynamicDataCallables {
  /**
   * Currently selected event
   */
  private _selectedEvent: IEvent;

  /**
   * Event handler for selecting an event in the list
   */
  private _eventSelected = (event: IEvent): void => {
    // store the currently selected event in the class variable. Required
    // so that connected component will be able to retrieve its value
    this._selectedEvent = event;
    // notify subscribers that the selected event has changed
    this.context.dynamicDataSourceManager.notifyPropertyChanged('event');
    // notify subscribers that the selected location has changed
    this.context.dynamicDataSourceManager.notifyPropertyChanged('location');
  }

  protected onInit(): Promise<void> {
    // register this web part as dynamic data source
    this.context.dynamicDataSourceManager.initializeSource(this);

    return Promise.resolve();
  }

  /**
   * Return list of dynamic data properties that this dynamic data source
   * returns
   */
  public getPropertyDefinitions(): ReadonlyArray<IDynamicDataPropertyDefinition> {
    return [
      { id: 'event', title: 'Event' },
      { id: 'location', title: 'Location' }
    ];
  }

  /**
   * Return the current value of the specified dynamic data set
   * @param propertyId ID of the dynamic data set to retrieve the value for
   */
  public getPropertyValue(propertyId: string): IEvent | ILocation {
    switch (propertyId) {
      case 'event':
        return this._selectedEvent;
      case 'location':
        return this._selectedEvent
            ? {
                city: this._selectedEvent.city,
                address: this._selectedEvent.address
              }
            : undefined;
    }

    throw new Error('Bad property id');
  }

  public render(): void {
    const element: React.ReactElement<IEventsProps> = React.createElement(
      Events,
      {
        displayMode: this.displayMode,
        onEventSelected: this._eventSelected,
        title: this.properties.title,
        updateProperty: (value: string): void => {
          this.properties.title = value;
        },
        siteUrl: this.context.pageContext.web.serverRelativeUrl
      }
    );

    ReactDom.render(element, this.domElement);
  }

  // ... omitted for brevity
}

重要

IDynamicDataCallables インターフェイスは、Web パーツと拡張機能だけでなく、どのクラスにも実装できます。 動的データ ソースが複雑なロジックを必要とする場合、ロジックを Web パーツまたは拡張機能の中に直接実装するのではなく、別のクラスに移動することを検討してください。

IDynamicDataCallables インターフェイスを実装するクラスは、getPropertyDefinitions()getPropertyValue() の 2 つのメソッドを定義する必要があります。

getPropertyDefinitions() メソッドは、特定の動的データ ソースが返すデータ型の配列を返します。 前の例では、Web パーツはイベントとその場所に関する詳細情報を公開します。 情報は 1 つのオブジェクト (_selectedEvent) からのものですが、2 つの異なるシェイプで公開すれば、Web パーツはより再利用が可能なものになり、イベントに固有ではない他の Web パーツと組み合わせて使用することができるようになります。たとえば、指定したアドレスの地図を表示できる地図 Web パーツなどです。 Web パーツをデータ ソースに接続すると、データ ソースが公開するデータの種類のリストがエンドユーザーに表示されます。

重要

たとえば次のように、getPropertyValue() メソッドによって返されるオブジェクトはフラットでなければなりません。

{
   "date": "2018-06-01T11:21:59.446Z",
   "name": "Tampa Home Show",
   "organizerEmail": "GradyA@contoso.onmicrosoft.com",
   "organizerName": "Grady Archie"
}

複雑なオブジェクトは、シリアル化中に平坦化されます。 予期しない結果になる可能性があります。 たとえば、次のようなオブジェクトは:

{
   "date": "2018-06-01T11:21:59.446Z",
   "name": "Tampa Home Show",
   "organizer": {
      "email": "GradyA@contoso.onmicrosoft.com",
      "name": "Grady Archie"
   }
}

...次のようにシリアル化されます:

{
   "date": "2018-06-01T11:21:59.446Z",
   "name": "Tampa Home Show",
   "organizer.email": "GradyA@contoso.onmicrosoft.com",
   "organizer.name": "Grady Archie"
}

getPropertyValue() メソッドは、特定のデータ型の値を返します。 propertyId 引数の値は、getPropertyDefinitions() メソッドで指定された定義の id に対応します。

動的データ ソースとしてコンポーネントを登録するには、this.context.dynamicDataSourceManager.initializeSource() メソッドを呼び出し、動的なデータ ソースのインスタンスをパラメーターとして渡します。 前の例で、Web パーツ自体が IDynamicDataCallables インターフェイスを実装しているため、initializeSource() メソッドは this を引数として呼び出されます。

サンプル コードでは、Web パーツが今後のイベントをリストにして表示します。 ユーザーがリストからイベントを選択するたびに、Web パーツは _eventSelected() メソッドを呼び出します。 そのメソッドでは、Web パーツは選択したイベントを _selectedEvent クラス変数に割り当て、選択されているイベントと場所に関する情報が変更されたことを示す通知を、変更されたデータ セットを示す定義の id を渡して this.context.dynamicDataSourceManager.notifyPropertyChanged() メソッドを呼び出すことにより発行します。

Web パーツでの動的データの使用

Web パーツは、ページに存在する動的データ ソースによって公開されるデータを使用できます。 前のイベント リスト Web パーツで選択されたイベントの場所を地図上で表示する Web パーツのコードを次に示します。

import { DynamicProperty } from '@microsoft/sp-component-base';
import {
  DynamicDataSharedDepth,
  IWebPartPropertiesMetadata,
  PropertyPaneDynamicFieldSet,
  PropertyPaneDynamicField
} from '@microsoft/sp-webpart-base';

/**
 * Map web part properties
 */
export interface IMapWebPartProps {
  /**
   * The address to display on the map
   */
  address: DynamicProperty<string>;
  /**
   * Bing maps API key to use with the Bing maps API
   */
  bingMapsApiKey: string;
  /**
   * The city where the address is located
   */
  city: DynamicProperty<string>;
  /**
   * Web part title
   */
  title: string;
}

/**
 * Map web part. Shows the map of the specified location. The location can be
 * specified either directly in the web part properties or via a dynamic data
 * source connection.
 */
export default class MapWebPart extends BaseClientSideWebPart<IMapWebPartProps> {
  /**
   * Event handler for clicking the Configure button on the Placeholder
   */
  private _onConfigure = (): void => {
    this.context.propertyPane.open();
  }

  public render(): void {
    // Get the location to show on the map. The location will be retrieved
    // either from the event selected in the connected data source or from the
    // address entered in web part properties
    const address: string | undefined = this.properties.address.tryGetValue();
    const city: string | undefined = this.properties.city.tryGetValue();
    const needsConfiguration: boolean = !this.properties.bingMapsApiKey || (!address && !this.properties.address.tryGetSource()) ||
    (!city && !this.properties.city.tryGetSource());

    const element: React.ReactElement<IMapProps> = React.createElement(
      Map,
      {
        needsConfiguration: needsConfiguration,
        httpClient: this.context.httpClient,
        bingMapsApiKey: this.properties.bingMapsApiKey,
        dynamicAddress: !!this.properties.address.tryGetSource(),
        address: `${address} ${city}`,
        onConfigure: this._onConfigure,
        width: this.domElement.clientWidth,
        height: this.domElement.clientHeight,
        title: this.properties.title,
        displayMode: this.displayMode,
        updateProperty: (value: string): void => {
          this.properties.title = value;
        }
      }
    );

    ReactDom.render(element, this.domElement);
  }

  protected get dataVersion(): Version {
    return Version.parse('1.0');
  }

  protected get propertiesMetadata(): IWebPartPropertiesMetadata {
    return {
      // Specify the web part properties data type to allow the address
      // information to be serialized by the SharePoint Framework.
      'address': {
        dynamicPropertyType: 'string'
      },
      'city': {
        dynamicPropertyType: 'string'
      }
    };
  }

  protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
    return {
      pages: [
        {
          groups: [
            {
              groupName: strings.BingMapsGroupName,
              groupFields: [
                PropertyPaneTextField('bingMapsApiKey', {
                  label: strings.BingMapsApiKeyFieldLabel
                }),
                PropertyPaneLink('', {
                  href: 'https://www.bingmapsportal.com/',
                  text: strings.GetBingMapsApiKeyLinkText,
                  target: '_blank'
                })
              ]
            },
            // Web part properties group for specifying the information about
            // the address to show on the map.
            {
              // Primary group is used to provide the address to show on the map
              // in a text field in the web part properties
              primaryGroup: {
                groupName: strings.DataGroupName,
                groupFields: [
                  PropertyPaneTextField('address', {
                    label: strings.AddressFieldLabel
                  }),
                  PropertyPaneTextField('city', {
                    label: strings.CityFieldLabel
                  })
                ]
              },
              // Secondary group is used to retrieve the address from the
              // connected dynamic data source
              secondaryGroup: {
                groupName: strings.DataGroupName,
                groupFields: [
                  PropertyPaneDynamicFieldSet({
                    label: 'Address',
                    fields: [
                      PropertyPaneDynamicField('address', {
                        label: strings.AddressFieldLabel
                      }),
                      PropertyPaneDynamicField('city', {
                        label: strings.CityFieldLabel
                      })
                    ],
                    sharedConfiguration: {
                      depth: DynamicDataSharedDepth.Property
                    }
                  })
                ]
              },
              // Show the secondary group only if the web part has been
              // connected to a dynamic data source
              showSecondaryGroup: !!this.properties.address.tryGetSource()
            } as IPropertyPaneConditionalGroup
          ]
        }
      ]
    };
  }

  protected get disableReactivePropertyChanges(): boolean {
    // set property changes mode to reactive, so that the Bing Maps API is not
    // called on each keystroke when typing in the address to show on the map
    // in web part properties
    return true;
  }
}

SharePoint Framework には、2 つの Web パーツを動的データ ソースに接続するためのユーザー エクスペリエンス (UX) が含まれています。 この UX を使用すると、使用可能な動的データ ソースとそのプロパティを検出し、構成されている接続を保持することにより、動的データの操作が簡単になります。 UX を使用するには、動的データを使用する Web パーツにいくつかの特定の文書パーツを含める必要があります。

動的 Web パーツのプロパティを定義する

各 Web パーツのプロパティは、動的データ ソースからデータを取得でき、DynamicProperty<T> として定義する必要があります。ここで、T は、次のように、プロパティに格納されるデータの種類を示します。

/**
 * Map web part properties
 */
export interface IMapWebPartProps {
  /**
   * The address to display on the map
   */
  address: DynamicProperty<string>;

  // ... omitted for brevity
}

この例では、アドレスは文字列ですが、ブール値、数値、またはオブジェクトなどの他の種類のデータもサポートします。 DynamicProperty として定義されている Web パーツのプロパティは自分のデータを、動的データ ソースから取得することも、Web パーツのプロパティに直接入力された値から取得することもできます。 同じ Web パーツのプロパティを、Web パーツのプロパティに構成される動的データ ソースと静的な値の両方に使用できるため、複数の Web パーツのプロパティを定義する必要はなく、さまざまな Web パーツの構築が簡略化されます。

動的プロパティに格納されるデータの種類の定義

動的プロパティごとに、保持するデータの種類を指定する必要があります。 これは、ページに追加する Web パーツのインスタンスが正しくシリアル化できるようにするために必要です。 各動的 Web パーツのプロパティについて、propertiesMetadata get アクセス操作子で dynamicPropertyType 値を指定します。

protected get propertiesMetadata(): IWebPartPropertiesMetadata {
  return {
    // Specify the web part properties data type to allow the address
    // information to be serialized by the SharePoint Framework.
    'address': {
      dynamicPropertyType: 'string'
    },
    'city': {
      dynamicPropertyType: 'string'
    }
  };
}

dynamicPropertyTypeプロパティの値は、booleannumberstringarrayobject にすることができます。

Web パーツを動的データ ソースに接続するための標準的な UX の使用

ユーザーが Web パーツをページで使用可能な動的データ ソースに接続できるようにするため、SharePoint Framework には Web パーツのプロパティ ウィンドウからアクセスできる標準的な UX が用意されています。

SharePoint Framework Web パーツをページで使用できる動的データ ソースに接続するための標準的な UX

重要

Web パーツを動的データ ソースに接続する標準的な UX を使用する際、動的データ ソースが特定の動的プロパティの値 (前の例では、イベントのリストで選択されているイベント) を返すことを確認してください。 返さない場合、UX はデータ ソースによって返されるデータの種類を確認できず、接続の設定は失敗します。

最も簡単な形態では、UI を次のように定義できます。

protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
  return {
    pages: [
      {
        groups: [
          {
            groupFields: [
              PropertyPaneDynamicFieldSet({
                label: 'Select event source',
                fields: [
                  PropertyPaneDynamicField('event', {
                    label: 'Event source'
                  })
                ]
              })
            ]
          }
        ]
      }
    ]
  };
}

動的プロパティのセットごとに、PropertyPaneDynamicFieldSet() メソッドを使用して新しいグループを追加します。 各動的 Web パーツのプロパティについて、PropertyPaneDynamicField を追加します。こうすると、ユーザーは PropertyPaneDynamicField で指定された Web パーツのプロパティがそのデータをどのプロパティから取得するかを選択できます。

動的データ フィールド セットが複数の動的プロパティで構成されている場合は、 プロパティを使用して接続データを共有する方法を sharedConfiguration.depth 指定できます。

groupFields: [
  PropertyPaneDynamicFieldSet({
    label: 'Address',
    fields: [
      PropertyPaneDynamicField('address', {
        label: strings.AddressFieldLabel
      }),
      PropertyPaneDynamicField('city', {
        label: strings.CityFieldLabel
      })
    ],
    sharedConfiguration: {
      depth: DynamicDataSharedDepth.Property
    }
  })
]

この例では、すべての動的プロパティが、選択した接続およびプロパティを共有します。 これは、データ ソースによって公開される選択したプロパティがオブジェクトであり、選択したオブジェクトの別の複数のプロパティに動的プロパティを接続する場合に便利です。 同じデータ ソースを使用するものの、選択したデータ ソースが公開する別のプロパティに各 Web パーツのプロパティを接続する場合は、代わりに DynamicDataSharedDepth.Source を使用できます。 最後に、各プロパティが別のデータ ソースからデータを取得する場合は、sharedConfiguration.depth プロパティを DynamicDataSharedDepth.None に設定します。

動的データを使用するか自分で値を指定するかユーザーが選択できるようにする

Web パーツを作成するときに、ユーザーが Web パーツをページのその他のコンポーネントに接続できるようにすることも、自分で Web パーツのプロパティの値を指定できるようにすることもできます。 これを行うのに必要な労力はわずかに過ぎませんが、広範囲の用途に適したさまざまな Web パーツを作成できます。

動的プロパティからデータを読み込むか Web パーツのプロパティに自分で値を入力するかをユーザーが選択できるようにするには、Web パーツのプロパティのグループを IPropertyPaneConditionalGroup グループとして定義します。

protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
  return {
    pages: [
      {
        groups: [
          // Web part properties group for specifying the information about
          // the address to show on the map.
          {
            // Primary group is used to provide the address to show on the map
            // in a text field in the web part properties
            primaryGroup: {
              groupName: strings.DataGroupName,
              groupFields: [
                PropertyPaneTextField('address', {
                  label: strings.AddressFieldLabel
                }),
                PropertyPaneTextField('city', {
                  label: strings.CityFieldLabel
                })
              ]
            },
            // Secondary group is used to retrieve the address from the
            // connected dynamic data source
            secondaryGroup: {
              groupName: strings.DataGroupName,
              groupFields: [
                PropertyPaneDynamicFieldSet({
                  label: 'Address',
                  fields: [
                    PropertyPaneDynamicField('address', {
                      label: strings.AddressFieldLabel
                    }),
                    PropertyPaneDynamicField('city', {
                      label: strings.CityFieldLabel
                    })
                  ],
                  sharedConfiguration: {
                    depth: DynamicDataSharedDepth.Property
                  }
                })
              ]
            },
            // Show the secondary group only if the web part has been
            // connected to a dynamic data source
            showSecondaryGroup: !!this.properties.address.tryGetSource()
          } as IPropertyPaneConditionalGroup
        ]
      }
    ]
  };
}

条件付き Web パーツのプロパティ ウィンドウのグループには、プライマリ グループとセカンダリ グループがあります。 showSecondaryGroup プロパティを使用すると、セカンダリ グループを表示してプライマリ グループを非表示にするするタイミングを指定できます。

上記の例では、ユーザーが省略記号 (...) をクリックして Web パーツを動的データ ソースに接続することを選択すると、Web パーツを動的データ ソースに接続するために使用するセカンダリ グループが表示されます。

SharePoint Framework の Web パーツを動的データ ソースに接続するために使用する Web パーツのプロパティ ウィンドウで省略記号に置かれたマウス ポインター

考慮事項

SharePoint Framework の動的データ機能には、次の特徴があります:

  • 各ページは、複数の動的データ ソースやコンシューマーを持つことができる
  • 各コンポーネントは、他のコンポーネントに動的データを提供することも、他のコンポーネントの動的データを使用することもできる
  • コンポーネントは、複数の動的データ ソースからのデータを使用できる
  • SharePoint Framework は、Web パーツをデータ ソースに接続するための標準的な UI を提供し、接続情報を自動的に保持する

関連項目