Utiliser les listes déroulantes en cascade dans les propriétés du composant WebPart
Lors de la conception du volet de propriétés pour vos composants WebPart côté client SharePoint, vous pouvez avoir une propriété de composant WebPart qui affiche ses options en fonction de la valeur sélectionnée dans une autre propriété. En règle générale, ce scénario se produit lors de l’implémentation des contrôles de liste déroulante en cascade. Dans cet article, vous apprenez à créer des contrôles de liste déroulante en cascade dans le volet de propriétés du composant WebPart sans développement d’un contrôle de volet de propriétés personnalisé.
La source du composant WebPart de travail est disponible sur GitHub à l’adresse sp-dev-fx-webparts/samples/react-custompropertypanecontrols/.
Remarque
Avant de suivre les étapes décrites dans cet article, n’oubliez pas de configurer votre environnement de développement de composant WebPart côté client SharePoint.
Création d’un projet
Commencez par créer un dossier pour votre projet :
md react-cascadingdropdowns
Accédez au dossier du projet :
cd react-cascadingdropdowns
Dans le dossier du projet, exécutez le générateur Yeoman pour SharePoint Framework afin de structurer un projet SharePoint Framework :
yo @microsoft/sharepoint
Lorsque vous y êtes invité, entrez les valeurs suivantes (sélectionnez l’option par défaut pour toutes les invites qui ne sont pas mentionnées ci-dessous) :
- Quel est le nom de votre solution ? : react-cascadingdropdowns
- Quel type de composant côté client voulez-vous créer ? : WebPart
- Quel est le nom de votre composant WebPart ? : Éléments de la liste
- Quel modèle souhaitez-vous utiliser ? : React
Ensuite, ouvrez le dossier de votre projet dans votre éditeur de code. Dans cet article, Visual Studio Code est utilisé dans les étapes et les captures d’écran, mais vous pouvez utiliser un autre éditeur si vous le souhaitez.
Définir une propriété de composant WebPart pour stocker la liste sélectionnée
Vous allez créer un composant WebPart qui affiche les éléments de liste à partir d’une liste SharePoint sélectionnée. Les utilisateurs peuvent sélectionner une liste dans le volet de propriétés du composant WebPart. Pour stocker la liste sélectionnée, créez une propriété pour le composant WebPart intitulée listName
.
Dans l’éditeur de code, ouvrez le fichier src/webparts/listItems/ListItemsWebPartManifest.json. Remplacez la propriété
description
par défaut par une nouvelle propriété nomméelistName
.{ ... "preconfiguredEntries": [{ ... "properties": { "listName": "" } }] }
Ouvrez le fichier src/webparts/listItems/ListItemsWebPart.ts et remplacez l’interface par ce
IListItemsWebPartProps
qui suit :export interface IListItemsWebPartProps { listName: string; }
Dans le fichier src/webparts/listItems/ListItemsWebPart.ts, remplacez la méthode
render()
par :export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> { // ... public render(): void { const element: React.ReactElement<IListItemsProps> = React.createElement(ListItems, { listName: this.properties.listName }); ReactDom.render(element, this.domElement); } // ... }
Mettez à jour
getPropertyPaneConfiguration()
pour :export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> { // ... protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration { return { pages: [ { header: { description: strings.PropertyPaneDescription }, groups: [ { groupName: strings.BasicGroupName, groupFields: [ PropertyPaneTextField('listName', { label: strings.ListNameFieldLabel }) ] } ] } ] }; } // ... }
Dans le fichier src/webparts/listItems/loc/mystrings.d.ts, remplacez l’interface
IListItemsStrings
par :declare interface IListItemsStrings { PropertyPaneDescription: string; BasicGroupName: string; ListNameFieldLabel: string; }
Dans le fichier src/webparts/listItems/loc/en-us.js, ajoutez la définition manquante pour la chaîne
ListNameFieldLabel
:define([], function() { return { "PropertyPaneDescription": "Description", "BasicGroupName": "Group Name", "ListNameFieldLabel": "List" } });
Dans le fichier src/webparts/listItems/components/ListItems.tsx, remplacez le contenu de la méthode
render()
par :public render(): JSX.Element { const { listName } = this.props; return ( <section className={`${styles.listItems} ${hasTeamsContext ? styles.teams : ''}`}> <div className={styles.welcome}> <img alt="" src={isDarkTheme ? require('../assets/welcome-dark.png') : require('../assets/welcome-light.png')} className={styles.welcomeImage} /> <h2>Well done, {escape(userDisplayName)}!</h2> <div>{environmentMessage}</div> <div>List name: <strong>{escape(listName)}</strong></div> </div> </section> ); }
Dans le fichier src/webparts/listItems/components/IListItemsProps.ts, remplacez l’interface
IListItemsProps
par :export interface IListItemsProps { listName: string; }
Exécutez la commande suivante pour vérifier l’exécution du projet :
gulp serve
Dans le navigateur web, ajoutez le composant WebPart Éléments de liste dans la zone, puis ouvrez ses propriétés. Vérifiez que la valeur définie pour la propriété Liste s’affiche dans le corps du composant WebPart.
Remplir la liste déroulante avec des listes SharePoint à choisir
À ce stade, un utilisateur spécifie la liste que le composant WebPart doit utiliser en entrant manuellement le nom de la liste. Cela est source d’erreurs et, dans l’idéal, vous voulez que les utilisateurs choisissent l’une des listes du site SharePoint en cours.
Utiliser le contrôle de liste déroulante pour rendre la propriété listName
Dans la classe
ListItemsWebPart
, ajoutez une référence à la classePropertyPaneDropdown
dans la section supérieure du composant WebPart. Remplacez la clause d’importation qui charge la classePropertyPaneTextField
par :import { IPropertyPaneConfiguration, PropertyPaneTextField, PropertyPaneDropdown, IPropertyPaneDropdownOption } from '@microsoft/sp-property-pane';
Dans la classe
ListItemsWebPart
, ajoutez une nouvelle variable nomméelists
pour stocker des informations sur toutes les listes disponibles sur le site actuel :export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> { private lists: IPropertyPaneDropdownOption[]; // ... }
Ajoutez une nouvelle variable de classe nommée
listsDropdownDisabled
. Cette variable détermine si la liste déroulante est activée ou non. Jusqu’à ce que le composant WebPart récupère les informations sur les listes disponibles sur le site actuel, la liste déroulante doit être désactivée.export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> { // ... private listsDropdownDisabled: boolean = true; // ... }
Modifiez la méthode
getPropertyPaneConfiguration()
pour utiliser le contrôle de liste déroulante pour afficher la propriétélistName
:export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> { // ... protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration { return { pages: [ { header: { description: strings.PropertyPaneDescription }, groups: [ { groupName: strings.BasicGroupName, groupFields: [ PropertyPaneDropdown('listName', { label: strings.ListNameFieldLabel, options: this.lists, disabled: this.listsDropdownDisabled }) ] } ] } ] }; } }
Exécutez la commande suivante pour vérifier qu’elle fonctionne comme prévu :
gulp serve
Afficher les listes disponibles dans la liste déroulante
Auparavant, vous avez associé le contrôle de liste déroulante de la propriété listName
à la propriété de classe lists
. Étant donné que vous n’avez pas encore chargé toutes les valeurs dans celle-ci, la liste déroulante List du volet de propriétés du composant WebPart reste désactivée. Dans cette section, vous étendez le composant WebPart pour charger les informations sur les listes disponibles.
Dans la classe
ListItemsWebPart
, ajoutez une méthode pour charger les listes disponibles. Vous allez utiliser des données fictives, mais vous pouvez également appeler l’API REST de SharePoint pour récupérer la liste des listes disponibles depuis le service web en cours. Pour simuler le chargement des options à partir d’un service externe, la méthode applique un délai de deux secondes.export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> { // ... private loadLists(): Promise<IPropertyPaneDropdownOption[]> { return new Promise<IPropertyPaneDropdownOption[]>((resolve: (options: IPropertyPaneDropdownOption[]) => void, reject: (error: any) => void) => { setTimeout((): void => { resolve([{ key: 'sharedDocuments', text: 'Shared Documents' }, { key: 'myDocuments', text: 'My Documents' }]); }, 2000); }); } }
Chargez les informations sur les listes disponibles dans la liste déroulante. Dans la classe
ListItemsWebPart
, remplacez la méthodeonPropertyPaneConfigurationStart()
à l’aide du code suivant<:export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> { // ... protected onPropertyPaneConfigurationStart(): void { this.listsDropdownDisabled = !this.lists; if (this.lists) { return; } this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'lists'); this.loadLists() .then((listOptions: IPropertyPaneDropdownOption[]): void => { this.lists = listOptions; this.listsDropdownDisabled = false; this.context.propertyPane.refresh(); this.context.statusRenderer.clearLoadingIndicator(this.domElement); this.render(); }); } // ... }
La méthode
onPropertyPaneConfigurationStart()
est appelée par l’infrastructure SharePoint après l’ouverture du volet de propriétés du composant WebPart.- Tout d’abord, la méthode vérifie si les informations sur les listes disponibles sur le site actuel ont été chargées.
- Si les informations de liste sont chargées, la liste déroulante est activée.
- Si les informations de liste sur les listes n’ont pas encore été chargées, l’indicateur de chargement s’affiche et informe l’utilisateur que le composant WebPart charge les informations sur les listes.
Une fois que les informations sur les listes disponibles ont été chargées, la méthode affecte les données récupérées à la variable de classe
lists
, d’où elles peuvent être utilisées par la liste déroulante.Ensuite, la liste déroulante est activée, permettant ainsi à l’utilisateur de sélectionner une liste. Lorsque vous appelez la méthode
this.context.propertyPane.refresh()
, le volet de propriétés du composant WebPart est actualisé et il reflète les dernières modifications apportées à la liste déroulante.Une fois que les informations de liste sont chargées, l’indicateur de chargement est supprimé par un appel à la méthode
clearLoadingIndicator()
. Étant donné que l’appel de cette méthode efface l’interface utilisateur du composant WebPart, la méthoderender()
est appelée pour forcer le composant WebPart à effectuer un nouveau rendu.Exécutez la commande suivante pour vérifier que tout fonctionne comme prévu :
gulp serve
Lorsque vous ajoutez un composant WebPart à la zone de dessin et ouvrez le volet de propriétés, vous devez voir la liste déroulante de listes complétée avec les listes disponibles parmi lesquelles l’utilisateur peut choisir.
Autoriser les utilisateurs à sélectionner un élément dans la liste sélectionnée
Lorsque vous créez des composants WebPart, vous devez souvent permettre aux utilisateurs de choisir une option parmi un ensemble de valeurs déterminées par une valeur précédemment sélectionnée, telle que le choix d’un pays/région en fonction du continent sélectionné ou le choix d’un élément de liste dans une liste sélectionnée. Cette expérience utilisateur est souvent appelée listes déroulantes en cascade. En utilisant les fonctionnalités de composants WebPart côté client de SharePoint Framework standard, vous pouvez créer des listes déroulantes en cascade dans le volet de propriétés du composant WebPart. Pour ce faire, vous étendez le composant WebPart précédemment créé avec la possibilité de choisir un élément de liste en fonction de la liste sélectionnée précédemment.
Ajouter la propriété du composant WebPart « Élément »
Dans l’éditeur de code, ouvrez le fichier src/webparts/listItems/ListItemsWebPart.manifest.json. Dans la section
properties
, ajoutez une propriété nomméeitemName
pour qu’elle apparaisse de la manière suivante :{ // ... "properties": { "listName": "", "itemName": "" } // ... }
Remplacez le code dans le fichier src/webparts/listItems/IListItemsWebPartProps.ts par :
export interface IListItemsWebPartProps { listName: string; itemName: string; }
Remplacez le code dans le fichier src/webparts/listItems/components/IListItemsProps.ts par :
export interface IListItemsProps { listName: string; itemName: string; }
Dans le fichier src/webparts/listItems/ListItemsWebPart.ts, remplacez le code de la méthode
render()
par :export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> { // ... public render(): void { const element: React.ReactElement<IListItemsProps> = React.createElement(ListItems, { listName: this.properties.listName, itemName: this.properties.itemName }); ReactDom.render(element, this.domElement); } // ... }
Dans le fichier src/webparts/listItems/loc/mystrings.d.ts, remplacez l’interface
IListItemsStrings
par :declare interface IListItemsStrings { PropertyPaneDescription: string; BasicGroupName: string; ListNameFieldLabel: string; ItemNameFieldLabel: string; }
Dans le fichier src/webparts/listItems/loc/en-us.js, ajoutez la définition manquante pour la chaîne
ItemNameFieldLabel
.define([], function() { return { "PropertyPaneDescription": "Description", "BasicGroupName": "Group Name", "ListNameFieldLabel": "List", "ItemNameFieldLabel": "Item" } });
Afficher la valeur de la propriété du composant WebPart « Élément »
Dans le fichier src/webparts/listItems/components/ListItems.tsx, remplacez la méthode render()
par :
export default class ListItems extends React.Component<IListItemsProps, {}> {
public render(): JSX.Element {
const {
listName,
itemName
} = this.props;
return (
<section className={`${styles.listItems} ${hasTeamsContext ? styles.teams : ''}`}>
<div className={styles.welcome}>
<img alt="" src={isDarkTheme ? require('../assets/welcome-dark.png') : require('../assets/welcome-light.png')} className={styles.welcomeImage} />
<h2>Well done, {escape(userDisplayName)}!</h2>
<div>{environmentMessage}</div>
<div>List name: <strong>{escape(listName)}</strong></div>
<div>Item name: <strong>{escape(itemName)}</strong></div>
</div>
</section>
);
}
}
Autoriser les utilisateurs à choisir l’élément dans une liste
Tout comme les utilisateurs peuvent sélectionner une liste à l’aide d’une liste déroulante, ils peuvent sélectionner l’élément dans la liste des éléments disponibles.
Dans la classe
ListItemsWebPart
, ajoutez une nouvelle variable nomméeitems
que vous utilisez pour stocker des informations sur tous les éléments disponibles dans la liste actuellement sélectionnée.export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> { // ... private items: IPropertyPaneDropdownOption[]; // ... }
Ajoutez une nouvelle variable de classe nommée
itemsDropdownDisabled
. Cette variable détermine si la liste déroulante des éléments doit être activée ou non. Les utilisateurs ne peuvent pas sélectionner un élément uniquement après avoir sélectionné une liste.export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> { // ... private itemsDropdownDisabled: boolean = true; // ... }
Modifiez la méthode
getPropertyPaneConfiguration()
pour utiliser le contrôle de liste déroulante pour afficher la propriétéitemName
.export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> { // ... protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration { return { pages: [ { header: { description: strings.PropertyPaneDescription }, groups: [ { groupName: strings.BasicGroupName, groupFields: [ PropertyPaneDropdown('listName', { label: strings.ListNameFieldLabel, options: this.lists, disabled: this.listsDropdownDisabled }), PropertyPaneDropdown('itemName', { label: strings.ItemNameFieldLabel, options: this.items, disabled: this.itemsDropdownDisabled }) ] } ] } ] }; } }
Exécutez la commande suivante pour vérifier qu’elle fonctionne comme prévu :
gulp serve
Afficher les éléments disponibles dans la liste sélectionnée dans la liste déroulante d’éléments
Auparavant, vous avez défini un contrôle de liste déroulante pour le rendu de la propriété itemName
dans le volet de propriétés du composant WebPart. Ensuite, vous étendez le composant WebPart pour charger les informations concernant les éléments disponibles dans la liste sélectionnée et affichez les éléments dans la liste déroulante d’éléments.
Ajoutez la méthode pour charger les éléments de liste. Dans le fichier src/webparts/listItems/ListItemsWebPart.ts, dans la classe
ListItemsWebPart
, ajoutez une nouvelle méthode pour charger les éléments de liste disponibles à partir de la liste sélectionnée. (Comme pour la méthode de chargement des listes disponibles, vous utilisez des données fictives.)export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> { // ... private loadItems(): Promise<IPropertyPaneDropdownOption[]> { if (!this.properties.listName) { // resolve to empty options since no list has been selected return Promise.resolve(); } const wp: ListItemsWebPart = this; return new Promise<IPropertyPaneDropdownOption[]>((resolve: (options: IPropertyPaneDropdownOption[]) => void, reject: (error: any) => void) => { setTimeout(() => { const items = { sharedDocuments: [ { key: 'spfx_presentation.pptx', text: 'SPFx for the masses' }, { key: 'hello-world.spapp', text: 'hello-world.spapp' } ], myDocuments: [ { key: 'isaiah_cv.docx', text: 'Isaiah CV' }, { key: 'isaiah_expenses.xlsx', text: 'Isaiah Expenses' } ] }; resolve(items[wp.properties.listName]); }, 2000); }); } }
La méthode
loadItems()
renvoie des éléments de liste pour la liste précédemment sélectionnée. Si aucune liste n’a été sélectionnée, la méthode résout la promesse sans aucune donnée.Chargez les informations sur les éléments disponibles dans la liste déroulante d’éléments. Dans la classe
ListItemsWebPart
, étendez la méthodeonPropertyPaneConfigurationStart()
pour charger les éléments de la liste sélectionnée :export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> { // ... protected onPropertyPaneConfigurationStart(): void { this.listsDropdownDisabled = !this.lists; this.itemsDropdownDisabled = !this.properties.listName || !this.items; if (this.lists) { return; } this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'options'); this.loadLists() .then((listOptions: IPropertyPaneDropdownOption[]): Promise<IPropertyPaneDropdownOption[]> => { this.lists = listOptions; this.listsDropdownDisabled = false; this.context.propertyPane.refresh(); return this.loadItems(); }) .then((itemOptions: IPropertyPaneDropdownOption[]): void => { this.items = itemOptions; this.itemsDropdownDisabled = !this.properties.listName; this.context.propertyPane.refresh(); this.context.statusRenderer.clearLoadingIndicator(this.domElement); this.render(); }); } // ... }
Lors de l’initialisation, le composant WebPart détermine d’abord si la liste déroulante des éléments doit être activée ou non. Si l’utilisateur a précédemment sélectionné une liste, il peut sélectionner un élément à partir de cette liste. Si aucune liste n’a été activée, la liste déroulante d’éléments est désactivée.
Vous avez étendu le code précédemment défini, qui charge les informations sur les listes disponibles, pour charger les informations concernant les éléments disponibles dans la liste sélectionnée. Le code affecte ensuite les informations récupérées à la variable de classe
items
à utiliser par la liste déroulante d’éléments. Enfin, le code efface l’indicateur de chargement et permet à l’utilisateur de commencer à travailler avec le composant WebPart.Exécutez la commande suivante pour vérifier que tout fonctionne comme prévu :
gulp serve
Si nécessaire, la liste déroulante d’éléments est initialement désactivée, obligeant les utilisateurs à sélectionner au préalable une liste. Mais à ce stade, même après la sélection d’une liste, la liste déroulante d’éléments reste désactivée.
Mettez à jour le volet de propriétés du composant WebPart après avoir sélectionné une liste. Lorsqu’un utilisateur sélectionne une liste dans le volet de propriétés, le composant WebPart doit effectuer une mise à jour, pour activer la liste déroulante d’éléments et afficher la liste des éléments disponibles dans la liste sélectionnée.
Dans le fichier ListItemsWebPart.ts, dans la classe
ListItemsWebPart
, remplacez la méthodeonPropertyPaneFieldChanged()
par le code suivant :export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> { // ... protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void { if (propertyPath === 'listName' && newValue) { // push new list value super.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue); // get previously selected item const previousItem: string = this.properties.itemName; // reset selected item this.properties.itemName = undefined; // push new item value this.onPropertyPaneFieldChanged('itemName', previousItem, this.properties.itemName); // disable item selector until new items are loaded this.itemsDropdownDisabled = true; // refresh the item selector control by repainting the property pane this.context.propertyPane.refresh(); // communicate loading items this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'items'); this.loadItems() .then((itemOptions: IPropertyPaneDropdownOption[]): void => { // store items this.items = itemOptions; // enable item selector this.itemsDropdownDisabled = false; // clear status indicator this.context.statusRenderer.clearLoadingIndicator(this.domElement); // re-render the web part as clearing the loading indicator removes the web part body this.render(); // refresh the item selector control by repainting the property pane this.context.propertyPane.refresh(); }); } else { super.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue); } } // ... }
Une fois que l’utilisateur a sélectionné une liste, le composant WebPart conserve la valeur nouvellement sélectionnée. Étant donné que la liste sélectionnée est modifiée, le composant WebPart réinitialise l’élément de liste sélectionné précédemment. Maintenant que la liste est sélectionnée, le volet de propriétés du composant WebPart charge les éléments de liste pour cette liste spécifique. Lors du chargement d’éléments, l’utilisateur ne peut pas sélectionner un élément.
Une fois que les éléments de la liste sélectionnée sont chargés, ils sont affectés à la variable de classe items à partir de laquelle ils peuvent être référencés par la liste déroulante d’éléments. Maintenant que les informations concernant les éléments de liste disponibles sont disponibles, la liste déroulante d’éléments est activée, ce qui permet aux utilisateurs de choisir un élément. L’indicateur de chargement est supprimé, ce qui efface le corps du composant WebPart et explique pourquoi le composant WebPart doit effectuer un nouveau rendu. Enfin, le volet de propriétés du composant WebPart est actualisé afin de refléter les dernières modifications.