Connexion de composants SharePoint Framework avec des données dynamiques
Vous pouvez connecter plusieurs composants SharePoint Framework et échanger des données entre eux à l’aide de Dynamic Data. Cette fonctionnalité vous permet de créer des solutions attrayantes pour les utilisateurs finaux et des expériences enrichies.
Remarque
Dynamic Data est le modèle recommandé pour partager des données entre des composants WebPart SharePoint Framework, y compris les composants WebPart et extensions côté client. Il a été introduit dans SharePoint Framework v1.7.
Exposition des données à l’aide d’une source de données dynamiques
Les données dynamiques dans SharePoint Framework sont basées sur le modèle source-notification. Les composants nommés comme sources de données dynamiques fournissent des données et informent SharePoint Framework lorsque les données changent.
Les autres composants sur la page peuvent s’abonner aux notifications émises par une source de données dynamiques. SharePoint Framework informe le composant consommateur que la source a signalé que ses données ont changé. Le composant consommateur demande ensuite les données auprès du composant source.
Chaque source de données dynamiques implémente l’interface IDynamicDataCallables
.
Le code suivant montre un exemple de composant WebPart qui affiche une liste d’événements à venir. Le composant WebPart d’événements expose les informations suivantes sur l’événement sélectionné aux autres composants sur la page : les informations complètes sur l’événement et l’adresse de l’emplacement.
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
L’interface IDynamicDataCallables
peut être implémentée par n’importe quelle classe, pas seulement par les extensions et les composants WebPart. Si la source de données dynamiques requiert une logique complexe, vous pouvez la déplacer dans une classe distincte plutôt que de l’implémenter directement à l’intérieur d’une extension ou d’un composant WebPart.
La classe qui implémente l’interface IDynamicDataCallables
doit définir deux méthodes : getPropertyDefinitions()
et getPropertyValue()
.
La méthode getPropertyDefinitions()
renvoie un tableau de types de données renvoyés par la source de données dynamiques spécifique. Dans l’exemple précédent, le composant WebPart expose des informations détaillées sur un événement et sur son emplacement. Même si les informations proviennent d’un objet unique (_selectedEvent
), en l’exposant sous deux formes différentes, le composant WebPart est mieux réutilisable et peut être utilisé conjointement avec d’autres composants WebPart qui ne sont pas propres aux événements. Par exemple, un composant WebPart de carte affichant une carte associée à l’adresse spécifiée. La liste des types de données exposés par la source de données s’affiche pour les utilisateurs finaux lors de la connexion de composants WebPart à la source de données.
Importante
L’objet renvoyé par la méthode getPropertyValue()
doit être plat, par exemple :
{
"date": "2018-06-01T11:21:59.446Z",
"name": "Tampa Home Show",
"organizerEmail": "GradyA@contoso.onmicrosoft.com",
"organizerName": "Grady Archie"
}
Les objets complexes sont aplatis lors de la sérialisation. Cela peut provoquer des résultats inattendus. Par exemple, un objet semblable au suivant :
{
"date": "2018-06-01T11:21:59.446Z",
"name": "Tampa Home Show",
"organizer": {
"email": "GradyA@contoso.onmicrosoft.com",
"name": "Grady Archie"
}
}
... serait sérialisé comme suit :
{
"date": "2018-06-01T11:21:59.446Z",
"name": "Tampa Home Show",
"organizer.email": "GradyA@contoso.onmicrosoft.com",
"organizer.name": "Grady Archie"
}
La méthode getPropertyValue()
renvoie la valeur pour le type de données spécifique. La valeur de l’argument propertyId
correspond à l’id
de la définition spécifiée dans la méthode getPropertyDefinitions()
.
Pour inscrire un composant comme source de données dynamiques, appelez la méthode this.context.dynamicDataSourceManager.initializeSource()
et transmettez l’instance de la source de données dynamiques en tant que paramètre. Dans l’exemple précédent, le composant WebPart lui-même implémente l’interface IDynamicDataCallables
, c’est pourquoi la méthode initializeSource()
est appelée avec l’argument this
.
Dans l’exemple de code, le composant WebPart affiche les événements à venir dans une liste. À chaque fois que l’utilisateur sélectionne un événement dans la liste, le composant WebPart appelle la méthode _eventSelected()
. Avec cette méthode, le composant WebPart affecte l’événement sélectionné à la variable de classe _selectedEvent
et émet une notification indiquant que les informations relatives à l’événement sélectionné et à l’emplacement ont été modifiées en appelant la méthode this.context.dynamicDataSourceManager.notifyPropertyChanged()
transmettant l’id
de la définition qui représente le jeu de données modifié.
Consommation de données dynamiques dans les composants WebPart
Les composants WebPart peuvent consommer des données exposées par les sources de données dynamiques présentes sur la page. Voici le code correspondant à un composant WebPart qui indique l’emplacement sur une carte de l’événement sélectionné dans le composant WebPart de liste d’événements affiché précédemment.
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 inclut une expérience utilisateur pour la connexion de deux composants WebPart à des sources de données dynamiques. Cette interface utilisateur simplifie l’utilisation des données dynamiques via la détection des sources de données dynamiques disponibles et de leurs propriétés, tout en conservant la connexion configurée. Pour utiliser cette interface utilisateur, un composant WebPart qui consomme des données dynamiques doit inclure quelques blocs de construction spécifiques.
Définition des propriétés du composant WebPart dynamique
Chaque propriété de composant WebPart dont les données peuvent être récupérées à partir d’une source de données dynamiques doit être définie comme DynamicProperty<T>
, où T
indique le type de données stockées dans la propriété. Par exemple :
/**
* Map web part properties
*/
export interface IMapWebPartProps {
/**
* The address to display on the map
*/
address: DynamicProperty<string>;
// ... omitted for brevity
}
Dans cet exemple, l’adresse est une chaîne, mais les autres types de données comme les valeurs booléennes, les nombres ou les objets sont également pris en charge. Les propriétés de composant WebPart définies comme DynamicProperty
peuvent récupérer leurs données à partir de valeurs ou de sources de données dynamiques fournies directement dans les propriétés du composant WebPart. Étant donné qu’une même propriété de composant WebPart peut être utilisée pour les sources de données dynamiques et les valeurs statiques configurées dans les propriétés du composant WebPart, vous n’avez pas besoin de définir plusieurs propriétés de composant WebPart. Cela simplifie la création de composants WebPart polyvalents.
Définition du type de données stockées dans les propriétés dynamiques
Vous devez spécifier le type de données que contient chaque propriété dynamique. Cette opération est nécessaire afin que l’instance du composant WebPart ajouté à une page puisse être sérialisée correctement. Pour chaque propriété de composant WebPart dynamique, dans le getter propertiesMetadata
, spécifiez la valeur 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'
}
};
}
Les valeurs possibles pour la propriété dynamicPropertyType
sont les suivantes : boolean
, number
, string
, array
et object
.
Utiliser l’interface utilisateur standard pour la connexion d’un composant WebPart à des sources de données dynamiques
Pour permettre aux utilisateurs de connecter des composants WebPart à des sources de données dynamiques disponibles sur la page, SharePoint Framework fournit une interface utilisateur standard accessible à partir du volet de propriétés du composant WebPart.
Importante
Lorsque vous utilisez l’interface utilisateur standard pour connecter un composant WebPart à une source de données dynamiques, assurez-vous que la source de données dynamiques renvoie une valeur correspondant à la propriété dynamique donnée (dans l’exemple précédent, il s’agit d’un événement sélectionné dans la liste des événements). Sinon, l’interface utilisateur ne peut pas déterminer le type de données renvoyé par la source de données, et la configuration de la connexion échoue.
Dans sa forme la plus simple, l’interface utilisateur peut être définie comme suit :
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
groups: [
{
groupFields: [
PropertyPaneDynamicFieldSet({
label: 'Select event source',
fields: [
PropertyPaneDynamicField('event', {
label: 'Event source'
})
]
})
]
}
]
}
]
};
}
Pour chaque ensemble de propriétés dynamiques, ajoutez un nouveau groupe à l’aide la méthode PropertyPaneDynamicFieldSet()
. Pour chaque propriété de composant WebPart dynamique, ajoutez un champ PropertyPaneDynamicField
permettant aux utilisateurs de sélectionner la propriété de composant WebPart spécifiée dans le champ PropertyPaneDynamicField
à partir de laquelle les données doivent être récupérées.
Si votre jeu de champs de données dynamiques se compose de plusieurs propriétés dynamiques, vous pouvez spécifier la façon dont les données de connexion sont partagées à l’aide de la sharedConfiguration.depth
propriété :
groupFields: [
PropertyPaneDynamicFieldSet({
label: 'Address',
fields: [
PropertyPaneDynamicField('address', {
label: strings.AddressFieldLabel
}),
PropertyPaneDynamicField('city', {
label: strings.CityFieldLabel
})
],
sharedConfiguration: {
depth: DynamicDataSharedDepth.Property
}
})
]
Dans cet exemple, toutes les propriétés dynamiques partagent la connexion sélectionnée et la propriété. Cela s’avère utile dans les cas où la propriété sélectionnée exposée par la source de données est un objet, et où vous voulez connecter vos propriétés dynamiques aux différentes propriétés de l’objet sélectionné. Pour utiliser la même source de données, mais connecter chaque propriété de composant WebPart à une propriété différente exposée par la source de données sélectionnée, vous pouvez utiliser DynamicDataSharedDepth.Source
à la place. Enfin, si vous souhaitez que chaque propriété récupère ses données à partir d’une source de données différente, vous pouvez définir la propriété sharedConfiguration.depth
sur DynamicDataSharedDepth.None
.
Choix entre l’utilisation des données dynamiques ou la définition de la valeur par les utilisateurs
Lorsque vous créez des composants WebPart, vous pouvez permettre aux utilisateurs de connecter des composants WebPart à d’autres composants sur la page, ou de spécifier eux-mêmes la valeur des propriétés du composant WebPart. Cela demande un petit effort supplémentaire et permet de créer des composants WebPart plus polyvalents et adaptés à un éventail plus large de cas d’utilisation.
Pour permettre aux utilisateurs de choisir entre charger les données à partir d’une propriété dynamique ou saisir la valeur eux-mêmes dans les propriétés de composant WebPart, vous pouvez définir le groupe de propriétés de composant WebPart comme groupe 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 groupe de volet de propriétés de composant WebPart conditionnel se compose d’un groupe principal et d’un groupe secondaire. À l’aide de la propriété showSecondaryGroup
, vous pouvez spécifier quand le groupe secondaire doit être visible et quand le groupe principal doit être masqué.
Dans l’exemple ci-dessus, le groupe secondaire, qui est utilisé pour la connexion d’un composant WebPart à une source de données dynamiques, sera visible lorsque l’utilisateur choisit de connecter le composant WebPart à une source de données dynamiques en cliquant sur les points de suspension (...).
Considérations
La fonctionnalité de données dynamiques de SharePoint Framework présente les caractéristiques suivantes :
- Chaque page peut avoir plusieurs consommateurs et sources de données dynamiques.
- Chaque composant peut fournir des données dynamiques à d’autres composants et consommer des données dynamiques à partir d’autres composants
- Les composants peuvent consommer les données de plusieurs sources de données dynamiques.
- SharePoint Framework offre une interface utilisateur standard pour la connexion de composants WebPart à des sources de données et conserve automatiquement les informations de connexion.