Conectar componentes de SharePoint Framework utilizando datos dinámicos
Puede conectar dos o más componentes de SharePoint Framework e intercambiar datos entre ellos mediante datos dinámicos. Esta funcionalidad le permite crear experiencias ricas y soluciones atractivas para el usuario final.
Nota:
Los datos dinámicos son el patrón recomendado para compartir datos entre componentes de SharePoint Framework, incluidos los elementos web y las extensiones del lado del cliente. Se presentó en SharePoint Framework v1.7.
Exponer datos utilizando un origen de datos dinámicos
Los datos dinámicos en SharePoint Framework se basan en el modelo de notificación de origen. Los componentes nombrados como origen de datos dinámicos, proporcionan datos y notifican a SharePoint Framework cuando los datos cambian.
Otros componentes en la página pueden suscribirse a las notificaciones emitidas por un origen de datos dinámicos. SharePoint Framework notifica al componente del consumidor que el origen ha notificado que sus datos han cambiado. El componente del consumidor entonces solicita los datos del componente de origen.
Cada origen de datos dinámicos implementa la interfaz IDynamicDataCallables
.
El código siguiente muestra un elemento web con una lista de los próximos eventos. El elemento web de eventos expone información sobre el evento seleccionado a otros componentes en la página de dos maneras: la información completa del evento y la dirección de ubicación.
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
La interfaz IDynamicDataCallables
se puede implementar por cualquier clase, no solo extensiones y elementos web. Si el origen de datos dinámicos requiere lógica compleja, considere moverlo a una clase separada en lugar de implementarlo directamente dentro de una extensión o elemento web.
La clase que implementa la interfaz IDynamicDataCallables
debe definir dos métodos: getPropertyDefinitions()
y getPropertyValue()
.
El método getPropertyDefinitions()
devuelve una matriz de tipos de datos que devuelve el origen de datos dinámicos particular. En el ejemplo anterior, el elemento web expone información detallada sobre un evento y su ubicación. Aunque la información proviene de un solo objeto (_selectedEvent
), al exponerlo en dos formas diferentes, el elemento web es más reutilizable y podría usarse en combinación con otros elementos web que no son específicos de los eventos, como un elemento web de mapa que puede mostrar un mapa para la dirección especificada. La lista de los tipos de datos expuestos por el origen de datos se muestra a los usuarios finales cuando conectan elementos web al origen de datos.
Importante
El objeto devuelto por el método getPropertyValue()
debe ser plano, por ejemplo:
{
"date": "2018-06-01T11:21:59.446Z",
"name": "Tampa Home Show",
"organizerEmail": "GradyA@contoso.onmicrosoft.com",
"organizerName": "Grady Archie"
}
Los objetos complejos se aplanarán durante la serialización. Esto podría dar lugar a resultados inesperados. Por ejemplo, objetos como el siguiente:
{
"date": "2018-06-01T11:21:59.446Z",
"name": "Tampa Home Show",
"organizer": {
"email": "GradyA@contoso.onmicrosoft.com",
"name": "Grady Archie"
}
}
...se incluirían en la serialización siguiente:
{
"date": "2018-06-01T11:21:59.446Z",
"name": "Tampa Home Show",
"organizer.email": "GradyA@contoso.onmicrosoft.com",
"organizer.name": "Grady Archie"
}
El método getPropertyValue()
devuelve el valor para el tipo particular de datos. El valor del argumento propertyId
corresponde a la id
de la definición especificada en el método getPropertyDefinitions()
.
Para registrar un componente como un origen de datos dinámicos, llame al método this.context.dynamicDataSourceManager.initializeSource()
y pase la instancia del origen de datos dinámicos como un parámetro. En el ejemplo anterior, el elemento web implementa la interfaz IDynamicDataCallables
, que es la razón por la cual el método initializeSource()
se llama con this
como argumento.
En el código de ejemplo, el elemento web muestra los próximos eventos en una lista. Cada vez que el usuario selecciona un evento de la lista, el elemento web llama al método _eventSelected()
. En ese método, el elemento web asigna el evento seleccionado a la variable de clase _selectedEvent
y emite una notificación de que la información sobre el evento y la ubicación seleccionados ha cambiado al llamar al método this.context.dynamicDataSourceManager.notifyPropertyChanged()
que pasa el id
de la definición que representa el conjunto de datos modificado.
Consumir datos dinámicos en elementos web
Los elementos web pueden consumir datos expuestos por los orígenes de datos dinámicos en la página. A continuación se muestra el código de un elemento web que muestra en un mapa la ubicación del evento seleccionado en el elemento web de lista de eventos mostrado 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;
}
}
SharePoint Framework incluye una experiencia del usuario (UX) para conectar dos elementos web a orígenes de datos dinámicos. Esta experiencia de usuario simplifica el trabajo con datos dinámicos al descubrir los orígenes de datos dinámicos disponibles y sus propiedades y conservar la conexión configurada. Para usar la experiencia de usuario, un elemento web que usa datos dinámicos debe incluir algunos bloques de creación específicos.
Definir las propiedades de elementos web dinámicos
Cada propiedad del elemento web, para la que se pueden recuperar los datos desde un origen de datos dinámicos, se define como DynamicProperty<T>
donde T
indica el tipo de datos almacenados en la propiedad, por ejemplo:
/**
* Map web part properties
*/
export interface IMapWebPartProps {
/**
* The address to display on the map
*/
address: DynamicProperty<string>;
// ... omitted for brevity
}
En este ejemplo, la dirección es una cadena, pero se admiten otros tipos de datos como booleano, números u objetos. Las propiedades de elementos que se definen como DynamicProperty
pueden recuperar los datos de orígenes de datos dinámicos o valores proporcionados directamente en las propiedades del elemento web. Puesto que la propiedad del mismo elemento web puede usarse para orígenes de datos dinámicos y valores estáticos configurados en las propiedades de elementos web, no es necesario definir varias propiedades del elemento web, lo que simplifica la creación de elementos web versátiles.
Definir el tipo de datos almacenados en las propiedades dinámicas
Para cada propiedad dinámica, debe especificar el tipo de datos que contiene. Esto es necesario para que pueda serializarse correctamente la instancia del elemento web agregado a una página. Para cada propiedad del elemento web dinámica, en el captador propertiesMetadata
, especifique el 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'
}
};
}
Los posibles valores de la propiedad dynamicPropertyType
son: boolean
, number
, string
, array
y object
.
Use la experiencia de usuario estándar para conectar los elementos web a orígenes de datos dinámicos.
Para permitir a los usuarios conectar los elementos web a orígenes de datos dinámicos en la página, SharePoint Framework ofrece una experiencia de usuario estándar a la que se puede acceder desde el panel de propiedades del elemento web.
Importante
Al usar la experiencia de usuario estándar para conectar un elemento web a un origen de datos dinámicos, asegúrese de que el origen de datos dinámicos devuelve un valor para la propiedad dinámica determinada (en el ejemplo anterior, hay un evento seleccionado en la lista de eventos). Si no lo hace, la experiencia de usuario no podrá determinar el tipo de datos devueltos por el origen de datos y se producirá un error al establecer la conexión.
En su forma más sencilla, la interfaz de usuario podría definirse como sigue:
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
groups: [
{
groupFields: [
PropertyPaneDynamicFieldSet({
label: 'Select event source',
fields: [
PropertyPaneDynamicField('event', {
label: 'Event source'
})
]
})
]
}
]
}
]
};
}
Para cada conjunto de propiedades dinámicas, agregue un nuevo grupo mediante el método PropertyPaneDynamicFieldSet()
. Para cada propiedad del elemento web dinámica, agregue un PropertyPaneDynamicField
, que permite a los usuarios seleccionar de qué propiedad debe recuperar los datos la propiedad del elemento web especificada en el elemento web PropertyPaneDynamicField
.
Si el conjunto de campos de datos dinámicos consta de varias propiedades dinámicas, puede especificar cómo se comparten los datos de conexión mediante la sharedConfiguration.depth
propiedad :
groupFields: [
PropertyPaneDynamicFieldSet({
label: 'Address',
fields: [
PropertyPaneDynamicField('address', {
label: strings.AddressFieldLabel
}),
PropertyPaneDynamicField('city', {
label: strings.CityFieldLabel
})
],
sharedConfiguration: {
depth: DynamicDataSharedDepth.Property
}
})
]
En este ejemplo, todas las propiedades dinámicas comparten la conexión seleccionada y la propiedad. Esto es útil en casos en que la propiedad seleccionada expuesta por el origen de datos es un objeto y quiere conectar sus propiedades dinámicas a las diferentes propiedades del objeto seleccionado. Si desea usar el mismo origen de datos, pero conectar cada propiedad del elemento web a una propiedad distinta expuesta por el origen de datos seleccionado, puede usar DynamicDataSharedDepth.Source
en su lugar. Por último, si desea que cada propiedad recupere los datos de un origen de datos distinto, puede establecer la propiedad sharedConfiguration.depth
en DynamicDataSharedDepth.None
.
Permitir a los usuarios elegir si desean usar datos dinámicos o especificar el valor ellos mismos
Al crear elementos web, puede permitir que los usuarios conecten elementos web a otros componentes en la página, o especificar valores de propiedades del elemento web ellos mismos. Esto requiere muy poco esfuerzo adicional y le permite crear elementos web más versátiles y adecuados para un rango más amplio de casos de uso.
Para permitir que los usuarios puedan elegir si desean cargar los datos de una propiedad dinámica o escribir el valor ellos mismos en las propiedades del elemento web, puede definir el grupo de propiedades del elemento web como un 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
]
}
]
};
}
Un grupo de panel de propiedades de elemento web condicional consta de un grupo principal y uno secundario. Con la propiedad showSecondaryGroup
, puede especificar cuándo el grupo secundario debería estar visible y el grupo principal debería estar oculto.
En el ejemplo anterior, el grupo secundario, que se usa para conectar el elemento web a un origen de datos dinámicos, será visible cuando el usuario seleccionado para conectar el elemento web a un origen de datos dinámicos haciendo clic en los puntos suspensivos (...).
Consideraciones
La funcionalidad de los datos dinámicos de SharePoint Framework tiene las características siguientes:
- cada página puede tener múltiples orígenes de datos dinámicos y consumidores
- cada componente puede proporcionar datos dinámicos a otros componentes y consumir datos dinámicos de otros componentes
- los componentes pueden consumir datos de múltiples orígenes de datos dinámicos
- SharePoint Framework ofrece una interfaz de usuario estándar para la conexión de elementos web a orígenes de datos y mantiene automáticamente la información de conexión