Verbinden von SharePoint Framework-Komponenten mit dynamischen Daten

Sie können zwei oder mehr SharePoint Framework-Komponenten miteinander verbinden und mit dynamischen Daten Daten zwischen ihnen austauschen. Mit dieser Funktion können Sie vielfältige Oberflächen und ansprechende Lösungen für Endbenutzer erstellen.

Drei miteinander verbundene SharePoint Framework-Webparts, die Informationen zu Ereignissen anzeigen

Hinweis

Dynamische Daten ist das empfohlene Muster für den Datenaustausch zwischen SharePoint- Framework-Komponenten, einschließlich clientseitiger Webparts und Erweiterungen. Sie wurde in SharePoint Framework v 1.7 eingeführt.

Verfügbarmachen von Daten mithilfe einer dynamischen Datenquelle

Dynamische Daten im SharePoint Framework basieren auf dem Quellbenachrichtigungsmodell. Komponenten, die als dynamische Datenquelle genannt werden, stellen Daten bereit und benachrichtigen das SharePoint Framework, wenn sich die Daten ändern.

Andere Komponenten auf der Seite können Benachrichtigungen abonnieren, die von einer dynamischen Datenquelle ausgegeben werden. Das SharePoint-Framework benachrichtigt die Consumer-Komponente, dass die Quelle mitgeteilt hat, dass die Daten geändert wurden. Die Consumer-Komponente fordert dann die Daten aus der Quellen-Komponente an.

Jede dynamische Datenquelle implementiert die IDynamicDataCallables-Schnittstelle.

Der folgende Code ist ein Beispiel für ein Webpart, das eine Liste bevorstehender Ereignisse anzeigt. Das Ereignisse-Webpart stellt anderen Komponenten auf der Seite auf zweierlei Weise Informationen zu dem ausgewählten Ereignis zur Verfügung: die vollständigen Ereignisinformationen und die Adresse des Orts.

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
}

Wichtig

Die IDynamicDataCallables-Schnittstelle kann von einer beliebigen Klasse und nicht nur von Webparts und Erweiterungen implementiert werden. Wenn die dynamische Datenquelle eine komplexe Logik erfordert, sollten Sie in Betracht ziehen, diese in eine separate Klasse zu verschieben, anstatt sie direkt in ein Webpart oder eine Erweiterung zu implementieren.

Die Klasse, die die IDynamicDataCallables-Schnittstelle implementiert, muss zwei Methoden definieren: getPropertyDefinitions() und getPropertyValue().

Die getPropertyDefinitions()-Methode gibt ein Array von Datentypen zurück, die von der jeweiligen dynamischen Datenquelle zurückgegeben werden. Im vorherigen Beispiel macht das Webpart ausführliche Informationen zu einem Ereignis und dessen Ort verfügbar. Auch wenn die Informationen von einem einzelnen Objekt (_selectedEvent) stammen, kann das Webpart, indem es in zwei unterschiedlichen Formen verfügbar gemacht wird, besser wiederverwendet und in Kombination mit anderen Webparts verwendet werden, die nicht spezifisch für Ereignisse sind, z. B. ein Karten-Webpart, in dem eine Karte für die angegebene Adresse angezeigt werden kann. Die Liste der Datentypen, die von der Datenquelle verfügbar gemacht werden, wird Endbenutzern angezeigt, wenn Webparts mit der Datenquelle verbunden werden.

Wichtig

Das von der getPropertyValue()-Methode zurückgegebene Objekt sollte einfach sein, z. B.:

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

Komplexe Objekte werden während der Serialisierung vereinfacht. Dies kann zu unerwarteten Ergebnissen führen. Bei einem Objekt wie dem folgenden:

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

... würde folgendermaßen serialisiert werden:

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

Die getPropertyValue()-Methode gibt den Wert für den bestimmten Datentyp zurück. Der Wert des propertyId-Arguments entspricht dem Wert id der in der getPropertyDefinitions()-Methode angegebenen Methode.

Um eine Komponente als dynamische Datenquelle zu registrieren, rufen Sie die this.context.dynamicDataSourceManager.initializeSource()-Methode auf und übergeben die Instanz der dynamischen Datenquelle als Parameter. Im vorherigen Beispiel implementiert das Webpart selbst die IDynamicDataCallables-Schnittstelle, weshalb die initializeSource()-Methode mit this als Argument aufgerufen wird.

In dem Beispielcode zeigt das Webpart bevorstehende Ereignisse in einer Liste an. Jedes Mal, wenn der Benutzer ein Ereignis aus der Liste auswählt, ruft das Webpart die _eventSelected()-Methode auf. Bei dieser Methode weist das Webpart das ausgewählte Ereignis der _selectedEvent-Klassenvariablen zu und gibt eine Benachrichtigung aus, dass sich die Informationen zu dem ausgewählten Ereignis und der Speicherort geändert haben, indem die this.context.dynamicDataSourceManager.notifyPropertyChanged()-Methode aufgerufen wird, die id der Definition übergibt, die den geänderten Datensatz darstellt.

Nutzen von dynamischen Daten in Webparts

Webparts können Daten nutzen, die von dynamischen Datenquellen auf der Seite verfügbar gemacht werden. Nachfolgend finden Sie den Code eines Webparts, das auf einer Karte den Ort des ausgewählten Ereignisses im zuvor dargestellten Ereignislisten-Webpart anzeigt.

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;
  }
}

Das SharePoint-Framework umfasst eine Benutzeroberfläche (User Experience, UX) zum Verbinden zweier Webparts mit dynamischen Datenquellen. Diese Benutzeroberfläche vereinfacht das Arbeiten mit dynamischen Daten, indem verfügbare dynamische Datenquellen und deren Eigenschaften ermittelt werden und die konfigurierte Verbindung gespeichert wird. Um die Benutzeroberfläche zu verwenden, muss ein Webpart, das dynamische Daten verwendet, einige spezifische Bausteine umfassen.

Definieren der Eigenschaften dynamischer Webparts

Jede Webparteigenschaft, für die die Daten aus einer dynamischen Datenquelle abgerufen werden können, sollte als DynamicProperty<T> definiert werden, wobei T den Typ der in der Eigenschaft gespeicherten Daten bezeichnet, zum Beispiel:

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

  // ... omitted for brevity
}

In diesem Beispiel ist die Adresse eine Zeichenfolge, aber andere Datentypen wie boolesche Werte, Zahlen oder Objekte werden ebenfalls unterstützt. Webparteigenschaften, die als DynamicProperty definiert sind, können ihre Daten aus dynamischen Datenquellen oder Werten abrufen, die direkt in den Webparteigenschaften bereitgestellt werden. Da die gleiche Webparteigenschaft sowohl für dynamische Datenquellen als auch für statische Werte verwendet werden kann, die in Webparteigenschaften konfiguriert sind, müssen Sie nicht mehrere Webparteigenschaften definieren, wodurch das Erstellen vielseitiger Webparts erleichtert wird.

Definieren des in dynamischen Eigenschaften gespeicherten Datentyps

Für jede dynamische Eigenschaft müssen Sie den Typ von Daten festlegen, der in dieser gespeichert wird. Dies ist erforderlich, damit die Instanz des Webparts, das zu einer Seite hinzugefügt wird, ordnungsgemäß serialisiert werden kann. Geben Sie für jede dynamische Webpart-Eigenschaft im propertiesMetadata-Getter den Wert dynamicPropertyType an:

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'
    }
  };
}

Mögliche Werte für die dynamicPropertyType-Eigenschaft sind: boolean, number, string, array und object.

Verwenden der Standardbenutzeroberfläche (UX) zum Verbinden des Webparts mit dynamischen Datenquellen

Damit Benutzer Webparts mit dynamischen Datenquellen verbinden können, die auf der Seite zur Verfügung stehen, bietet SharePoint-Framework eine Standardbenutzeroberfläche (UX), auf die vom Webpart-Eigenschaftenbereich aus zugegriffen werden kann.

Standardbenutzeroberfläche (UX) zum Verbinden von SharePoint Framework-Webparts mit dynamischen Datenquellen, die auf der Seite verfügbar sind

Wichtig

Wenn Sie die Standardbenutzeroberfläche (UX) verwenden, um ein Webpart mit einer dynamischen Datenquelle zu verbinden, stellen Sie Sicher, dass die dynamische Datenquelle einen Wert für die angegebene dynamische Eigenschaft zurückgibt (im vorherigen Beispiel gibt es ein Ereignis, das in der Liste von Ereignissen ausgewählt wurde). Wenn dies nicht der Fall ist, kann die Benutzeroberfläche (UX) den Typ der von der Datenquelle zurückgegebenen Daten nicht ermitteln, und das Einrichten der Verbindung schlägt fehl.

In ihrer einfachsten Form könnte die Benutzeroberfläche wie folgt definiert werden:

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

Fügen Sie für jeden Satz dynamischer Eigenschaften eine neue Gruppe mithilfe der PropertyPaneDynamicFieldSet()-Methode hinzu. Fügen Sie für jede dynamische Webparteigenschaft eine PropertyPaneDynamicField hinzu, damit Benutzer auswählen können, von welcher Eigenschaft das in PropertyPaneDynamicField angegebene Webpart seine Daten abrufen soll.

Wenn Ihr dynamischer Datenfeldsatz aus mehreren dynamischen Eigenschaften besteht, können Sie mithilfe der sharedConfiguration.depth -Eigenschaft angeben, wie die Verbindungsdaten freigegeben werden:

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

In diesem Beispiel verwenden alle dynamischen Eigenschaften die ausgewählte Verbindung und Eigenschaft gemeinsam. Dies ist hilfreich in Fällen, in denen die ausgewählte Eigenschaft, die von der Datenquelle verfügbar gemacht wird, ein Objekt ist und Sie die dynamischen Eigenschaften mit den unterschiedlichen Eigenschaften des ausgewählten Objekts verbinden möchten. Wenn Sie dieselbe Datenquelle verwenden möchten, aber jede Webparteigenschaft mit einer anderen Eigenschaft verbinden, die von der ausgewählten Datenquelle verfügbar gemacht wird, können Sie stattdessen DynamicDataSharedDepth.Source verwenden. Und wenn Sie schließlich möchten, dass jede Eigenschaft ihre Daten aus einer anderen Datenquelle abruft, können sie die sharedConfiguration.depth-Eigenschaft auf DynamicDataSharedDepth.None festlegen.

Zulassen, dass Benutzer entscheiden, ob sie dynamische Daten verwenden oder die Werte selbst angeben möchten

Beim Erstellen von Webparts, können Sie zulassen, dass Benutzer Webparts mit anderen Komponenten auf der Seite verbinden oder Werte der Webparteigenschaften selbst angeben. Dies bedeutet wenig zusätzlichen Aufwand, und Sie können auf diese Weise Webparts erstellen, die vielseitiger und für mehr Anwendungsfälle geeignet sind.

Um zuzulassen, dass Benutzer auswählen, ob sie Daten aus einer dynamischen Eigenschaft laden oder den Wert selbst in den Webparteigenschaften angeben möchten, können Sie die Webpart-Eigenschaftengruppe als eine IPropertyPaneConditionalGroup-Gruppe definieren.

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
        ]
      }
    ]
  };
}

Eine bedingte Webpart-Eigenschaftenbereichsgruppe besteht aus einer primären und einer sekundären Gruppe. Mithilfe der showSecondaryGroup-Eigenschaft können Sie angeben, wann die sekundäre Gruppe sichtbar sein soll und wann die primäre Gruppe ausgeblendet werden soll.

Im obigen Beispiel ist die sekundäre Gruppe, die zum Verbinden des Webparts mit einer dynamischen Datenquelle verwendet wird, sichtbar, wenn der Benutzer ausgewählt hat, dass das Webpart mit einer dynamischen Datenquelle verbunden werden soll, indem er auf die Auslassungspunkte (...) klickt.

Mauszeiger, der sich über die Auslassungspunkte im Webpart-Eigenschaftenbereich bewegt, der verwendet wird, um ein SharePoint Framework-Webpart mit einer dynamischen Datenquelle zu verbinden

Überlegungen

Die dynamische Datenfunktion von SharePoint Framework hat die folgenden Merkmale:

  • Jede Seite kann mehrere dynamische Datenquellen und Consumer haben.
  • Jede Komponente kann sowohl dynamische Daten für andere Komponenten bereitstellen und dynamische Daten von anderen Komponenten nutzen.
  • Komponenten können Daten aus mehreren dynamischen Datenquellen nutzen.
  • SharePoint Framework bietet eine Standardbenutzeroberfläche zum Verbinden von Webparts mit Datenquellen und zum automatischen Speichern von Verbindungsinformationen.

Siehe auch