Partilhar via


Conectar os componentes da Estrutura do SharePoint usando dados dinâmicos

Você pode conectar dois ou mais componentes da Estrutura do SharePoint e trocar informações entre eles usando dados dinâmicos. Esse recurso permite criar experiências ricas e soluções atraentes para o usuário final.

Três Web Parts conectadas da Estrutura do SharePoint conectadas umas às outras, mostrando informações sobre eventos

Observação

Dados dinâmicos é o padrão recomendado para compartilhar dados entre componentes da Estrutura do SharePoint, incluindo extensões e as Web Parts do cliente. Foi introduzido na Estrutura do SharePoint v1.7.

Expor dados usando a fonte de dados dinâmicos

Os dados dinâmicos na Estrutura do SharePoint se baseiam no modelo de notificação de origem. Os componentes nomeados como uma fonte de dados dinâmica, fornecem dados e notificam a Estrutura do SharePoint quando os dados são alterados.

Outros componentes na página podem assinar para receber notificações emitidas por uma fonte de dados dinâmicos. A Estrutura do SharePoint notifica o componente consumidor de que a fonte informou que os seus dados foram alterados. O componente do cliente então solicita os dados do componente de origem.

Toda fonte de dados dinâmica implementa a interface IDynamicDataCallables.

O código a seguir demonstra uma Web Part que exibe uma lista dos próximos eventos. A Web Part de eventos apresenta informações sobre o evento selecionado para outros componentes na página, de duas maneiras: as informações de eventos completas e o endereço do local.

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
}

Importante

A interface IDynamicDataCallables pode ser implementada por qualquer classe, não apenas por Web Parts e extensões. Se a fonte de dados dinâmica exigir lógica complexa, considere movê-la para uma classe separada ao invés de implementá-la diretamente dentro de uma extensão ou Web Part.

A classe que implementa a IDynamicDataCallables interface deve estabelecer dois métodos: getPropertyDefinitions() e getPropertyValue().

O método getPropertyDefinitions() retornará uma matriz de tipos de dados que a fonte de dados dinâmicos específica retorna. No exemplo anterior, a Web Part expõe informações detalhadas sobre um evento e o respectivo local. Mesmo que a informação venha de um único objeto (_selectedEvent) expondo-o em duas formas diferentes, a Web Part é mais reutilizável e pode ser usada em combinação com outras Web Parts que não são específicas para eventos, assim como uma Web Part de mapa que pode mostrar um mapa para o endereço especificado. A lista dos tipos de dados expostos pela fonte de dados é exibida para usuários finais ao conectar as web parts a essa fonte.

Importante

Objeto retornado pelo método getPropertyValue() deverá ser simples, por exemplo:

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

Objetos complexos serão achatados durante a serialização. Isso pode levar a resultados imprevisíveis. Por exemplo, um objeto como o seguinte:

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

...seria serializado para o seguinte:

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

O método getPropertyValue() retorna o valor para o tipo de dados específico. O valor do argumento propertyId corresponde à id da definição especificada no método getPropertyDefinitions().

Para registrar um componente como uma fonte de dados dinâmica, chame o this.context.dynamicDataSourceManager.initializeSource() método e passe a instância dessa fonte de dados como parâmetro. No exemplo anterior, a própria Web Part implementa a interface IDynamicDataCallables, razão pela qual o método initializeSource() é chamado com this como argumento.

O código de exemplo, a Web Part exibe eventos futuros em uma lista. Todas as vezes, o usuário seleciona um evento na lista e a Web Part chama o método _eventSelected(). Nesse método, a Web Part atribui o evento selecionado à variável de classe _selectedEvent e emite uma notificação de que as informações sobre o evento selecionado e o local foram alteradas, chamando o método this.context.dynamicDataSourceManager.notifyPropertyChanged() e passando o id da definição, que representa o conjunto de dados alterado.

Consumir dados dinâmicos em Web Parts

Web Parts podem consumir dados expostos por fontes de dados dinâmicos presentes na página. Este é o código de uma Web Part mostrando, em um mapa, o local do evento selecionado na Web Part de lista de eventos mostrada anteriormente.

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

A Estrutura do SharePoint inclui uma experiência do usuário (UX) para conectar duas web parts as fontes de dados dinâmicas. Esse UX simplifica o trabalho com dados dinâmicos, descobrindo as fontes de dados dinâmicas disponíveis, suas propriedades e mantendo a conexão configurada. Para utilizar a UX, uma Web Part que consome dados dinâmicos deve incluir alguns blocos de construção específicos.

Definir propriedades dinâmicas de Web Part

Cada propriedade da web part para a qual os dados podem ser recuperados de uma fonte de dados dinâmicos, deve ser definida como DynamicProperty<T>ondeT indica o tipo dos dados armazenados na propriedade, por exemplo:

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

  // ... omitted for brevity
}

Neste exemplo, o endereço é uma cadeia de caracteres, mas também há outros tipos de dados compatíveis, tais como booliano, números ou objetos. Propriedades da Web Part definidas como DynamicProperty podem recuperar seus dados de fontes de dados dinâmicos ou valores fornecidos diretamente nas propriedades da Web Part. Devido à mesma propriedade da Web Part poder ser usada para fontes de dados dinâmicos e valores estáticos configurados nas propriedades da Web Part, não é necessário definir várias propriedades da Web Part, o que simplifica a criação de Web Parts versáteis.

Defina o tipo dos dados armazenados em propriedades dinâmicas

Para cada propriedade dinâmica, você precisa especificar o tipo de dados nela contidos. Isso é necessário para que a instância da Web Part adicionada a uma página possa ser serializada corretamente. Para cada propriedade de Web Part dinâmica, no getter propertiesMetadata, especifique o valor 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'
    }
  };
}

Os valores possíveis para a propriedade dynamicPropertyType são: boolean, number, string, array e object.

Use a UX padrão para conectar a Web Part as fontes de dados dinâmicas

Para permitir que os usuários conectem as Web Parts às fontes de dados dinâmicas disponíveis na página, a Estrutura do SharePoint fornece um UX padrão, que pode ser acessado no painel de propriedades da Web Part.

UX padrão para conectar as Web parts da Estrutura do SharePoint as fontes de dados dinâmicas disponíveis na página

Importante

Ao utilizar a UX padrão para conectar uma Web Part a uma fonte de dados dinâmica, verifique se a fonte de dados dinâmica retorna um valor para a propriedade dinâmica especificada (no exemplo anterior, há um evento selecionado na lista de eventos). Se não o fizer, o UX não poderá determinar o tipo de informações retornadas pela fonte de dados e a instalação da conexão falhará.

Em sua forma mais simples, a interface do usuário pode ser definida desta forma:

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

Para cada conjunto de propriedades dinâmicas, adicione um novo grupo usando o método PropertyPaneDynamicFieldSet(). Para cada propriedade de Web Part dinâmica, adicione um PropertyPaneDynamicField, que permitirá que os usuários selecionem de qual propriedade a Web Part especificada no PropertyPaneDynamicField deverá recuperar seus dados.

Se o conjunto de campos de dados dinâmico consistir em várias propriedades dinâmicas, você poderá especificar como os dados de conexão são compartilhados usando a sharedConfiguration.depth propriedade:

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

Neste exemplo, todas as propriedades dinâmicas compartilham a conexão e a propriedade selecionadas. Isso é útil em casos nos quais a propriedade selecionada exposta pela fonte de dados é um objeto e você deseja conectar propriedades dinâmicas às diferentes propriedades do objeto selecionado. Se quiser usar a mesma fonte de dados, mas conectar cada propriedade da Web Part a uma propriedade diferente exposta pela fonte de dados selecionada, você poderá usar DynamicDataSharedDepth.Source em vez disso. Por fim, se quiser que cada propriedade recupere seus dados de outra fonte de dados, você poderá definir a propriedade sharedConfiguration.depth para DynamicDataSharedDepth.None.

Permitir que os usuários escolham se desejam usar dados dinâmicos ou especificar o valor por conta própria

Durante a criação de Web Parts, você pode permitir que os usuários conectem Web Parts a outros componentes na página ou especificar valores de propriedades da Web Part por conta própria. Isso requer pouco esforço adicional e permite criar web parts mais versáteis e adequadas para uma variedade maior de casos de uso.

Para permitir que os usuários possam escolher se desejam carregar os dados de uma propriedade dinâmica ou inserir o valor por conta própria nas propriedades da web part, você pode definir o grupo de propriedades da web part como um grupo 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
        ]
      }
    ]
  };
}

Um grupo de painéis de propriedades de Web Part condicional consiste em um grupo principal e outro secundário. Usando a propriedade showSecondaryGroup, você pode especificar quando o grupo secundário deve estar visível e o grupo principal deve estar oculto.

No exemplo acima, o grupo secundário, usado para conectar a Web Part a uma fonte de dados dinâmica, ficará visível quando o usuário selecionar a opção de conectar a Web Part a uma fonte de dados dinâmica, clicando nas reticências (...).

Ponteiro do mouse passando sobre as reticências no painel de propriedades da Web Part, usado para conectar uma Web Part da Estrutura do SharePoint a uma fonte de dados dinâmicos

Considerações

O recurso de dados dinâmicos da Estrutura do SharePoint possui as seguintes características:

  • cada página pode ter vários clientes e fontes de dados dinâmicos
  • cada componente pode fornecer dados dinâmicos para outros componentes e consumir dados dinâmicos da outros componentes
  • componentes podem consumir dados de várias fontes de dados dinâmicos
  • A Estrutura do SharePoint oferece uma interface do usuário padrão para conectar Web Parts a fontes de dados e persiste informações de conexão automaticamente

Confira também