Share via


Création de contrôles personnalisés pour le volet de propriétés

L’infrastructure SharePoint contient un ensemble de contrôles standard pour le volet de propriétés. Seulement, des fonctionnalités supplémentaires sont parfois nécessaires. Par exemple, des mises à jour asynchrones pour les données d’un contrôle ou une interface utilisateur spécifique. Créez un contrôle personnalisé dans le volet de propriétés pour bénéficier d’une fonctionnalité sur mesure.

Dans cet article, vous allez construire un contrôle de liste déroulante personnalisé qui charge ses données de manière asynchrone à partir d'un service externe sans bloquer l'interface utilisateur du composant Web.

Chargement des éléments disponibles dans la liste déroulante « Élément » après sélection d’une liste dans la liste déroulante « Liste »

La source du composant WebPart de travail est disponible sur GitHub à l’adresse sp-dev-fx-webparts/samples/react-custompropertypanecontrols/.

Remarque

Avant de suivre la procédure décrite dans cet article, n’oubliez pas de configurer votre environnement de développement pour générer des solutions SharePoint Framework.

Création d’un projet

  1. Commencez par créer un dossier pour votre projet :

    md react-custompropertypanecontrol
    
  2. Accédez au dossier du projet :

    cd react-custompropertypanecontrol
    
  3. 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
    
  4. 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 type de composant côté client créer? Composant WebPart
    • Quel est le nom de votre composant WebPart ? Éléments de liste
    • Quel modèle souhaitez-vous utiliser ? Réagir
  5. Ensuite, ouvrez le dossier de votre projet dans votre éditeur de code.

Définir la propriété du composant WebPart pour stocker la liste sélectionnée

Le composant Web que vous créez affiche les éléments de la liste SharePoint sélectionnée. Les utilisateurs peuvent sélectionner une liste dans les propriétés du composant Web. Pour stocker la liste sélectionnée, créez une propriété pour le composant WebPart intitulée listName.

  1. 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ée listName.

    {
      ...
      "preconfiguredEntries": [{
        ...
        "properties": {
          "listName": ""
        }
      }]
    }
    
  2. Ouvrez le fichier src/webparts/listItems/ListItemsWebPart.ts, puis mettez à jour l’interface IListItemsWebPartProps comme suit :

    export interface IListItemsWebPartProps {
      description: string;
      listName: string;
    }
    
  3. 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,
            description: this.properties.description,
            isDarkTheme: this._isDarkTheme,
            environmentMessage: this._environmentMessage,
            hasTeamsContext: !!this.context.sdks.microsoftTeams,
            userDisplayName: this.context.pageContext.user.displayName
          }
        );
    
        ReactDom.render(element, this.domElement);
      }
    
      // ...
    }
    
  4. Mettez à jour la méthode getPropertyPaneConfiguration() de la façon suivante :

    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.ListFieldLabel
                    })
                  ]
                }
              ]
            }
          ]
        };
      }
    
      // ...
    }
    
  5. Dans le fichier src/webparts/listItems/loc/mystrings.d.ts, ajoutez une nouvelle propriété ListFieldLabel de type string à l’interface IListItemsWebPartStrings existante :

    declare interface IListItemsWebPartStrings {
      PropertyPaneDescription: string;
      BasicGroupName: string;
      ..
      ListFieldLabel: string;
    }
    
  6. Dans le fichier src/webparts/listItems/loc/en-us.js, ajoutez une nouvelle propriété ListFieldLabel à l’objet renvoyé :

    define([], function() {
      return {
        "PropertyPaneDescription": "Description",
        "BasicGroupName": "Group Name",
        ...
        "ListFieldLabel": "List"
      }
    });
    
  7. Ouvrez le fichier src/webparts/listItems/components/IListItemsProps.ts, puis ajoutez la propriété listName à l’interface de liste :

    export interface IListItemsProps {
      description: string;
      isDarkTheme: boolean;
      environmentMessage: string;
      hasTeamsContext: boolean;
      userDisplayName: string;
      listName: string;
    }
    
  8. Dans le fichier src/webparts/listItems/components/ListItems.tsx, remplacez le contenu de la méthode render() par :

    export default class ListItems extends React.Component<IListItemsProps, {}> {
      public render(): React.ReactElement<IListItemsProps> {
        const {
          description,
          isDarkTheme,
          environmentMessage,
          hasTeamsContext,
          userDisplayName,
          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>
        );
      }
    }
    
  9. Exécutez la commande suivante pour vérifier l’exécution du projet :

    gulp serve
    
  10. 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.

    Composant WebPart affichant la valeur de la propriété « listName »

Création d’un contrôle de liste déroulante asynchrone pour le volet de propriétés

L’infrastructure SharePoint met à votre disposition un contrôle de liste déroulante standard qui vous permet de sélectionner une valeur spécifique. Vous devez connaître toutes les valeurs du contrôle de liste déroulante avant de le créer. Si vous souhaitez charger les valeurs dynamiquement ou si vous chargez des valeurs de façon asynchrone à partir d’un service externe et que vous ne souhaitez pas bloquer l’ensemble du composant WebPart, la création d’un contrôle de liste déroulante personnalisée est une option.

Lorsque vous créez un contrôle de volet de propriétés personnalisé qui utilise React dans SharePoint Framework, le contrôle comprend une classe qui enregistre le contrôle avec le composant WebPart, et un composant qui affiche la liste déroulante et gère ses données.

Ajout d’un composant React dans le contrôle de liste déroulante asynchrone du volet de propriétés

  1. Créez le dossier « components ». Dans le dossier src du projet, créez une hiérarchie de trois nouveaux dossiers pour que la structure de vos dossiers se présente sous la forme suivante : src/controls/PropertyPaneAsyncDropdown/components.

    Dossier « components » mis en surbrillance dans Visual Studio Code

  2. Définissez les propriétés du composant React de liste déroulante asynchrone. Dans le dossier src/controls/PropertyPaneAsyncDropdown/components, créez un fichier nommé IAsyncDropdownProps.ts, puis entrez le code suivant :

    import { IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown';
    
    export interface IAsyncDropdownProps {
      label: string;
      loadOptions: () => Promise<IDropdownOption[]>;
      onChanged: (option: IDropdownOption, index?: number) => void;
      selectedKey: string | number;
      disabled: boolean;
      stateKey: string;
    }
    

    La classe IAsyncDropdownProps définit les propriétés pouvant être définies sur le composant React utilisé par le contrôle du volet de propriétés personnalisé :

    • La propriété label indique le nom du contrôle de liste déroulante.
    • La fonction associée au délégué loadOptions est appelée par le contrôle pour charger les options disponibles.
    • La fonction associée au délégué onChanged est appelée lorsque l’utilisateur sélectionne une option dans la liste déroulante.
    • La propriété selectedKey indique la valeur sélectionnée (chaîne de caractères ou nombre).
    • La propriété disabled indique si le contrôle de liste déroulante est désactivé.
    • La propriété stateKey est utilisée pour forcer le composant React à se réinitialiser.
  3. Définissez l’interface du composant React de liste déroulante asynchrone. Dans le dossier src/controls/PropertyPaneAsyncDropdown/components, créez un fichier nommé IAsyncDropdownState.ts, puis entrez le code suivant :

    import { IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown';
    
    export interface IAsyncDropdownState {
      loading: boolean;
      options: IDropdownOption[];
      error: string;
    }
    

    L’interface IAsyncDropdownState décrit l’état du composant React :

    • La propriété loading indique si le composant charge ses options en ce moment.
    • La propriété options contient toutes les options disponibles.
    • Si une erreur s’est produite, elle est affectée à la propriété error depuis l’endroit où elle est communiquée à l’utilisateur.
  4. Définissez le composant React de liste déroulante asynchrone. Dans le dossier src/controls/PropertyPaneAsyncDropdown/components, créez un fichier nommé AsyncDropdown.tsx, puis entrez le code suivant :

    import * as React from 'react';
    import { Dropdown, IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown';
    import { Spinner } from 'office-ui-fabric-react/lib/components/Spinner';
    import { IAsyncDropdownProps } from './IAsyncDropdownProps';
    import { IAsyncDropdownState } from './IAsyncDropdownState';
    
    export default class AsyncDropdown extends React.Component<IAsyncDropdownProps, IAsyncDropdownState> {
      private selectedKey: React.ReactText;
    
      constructor(props: IAsyncDropdownProps, state: IAsyncDropdownState) {
        super(props);
        this.selectedKey = props.selectedKey;
    
        this.state = {
          loading: false,
          options: undefined,
          error: undefined
        };
      }
    
      public componentDidMount(): void {
        this.loadOptions();
      }
    
      public componentDidUpdate(prevProps: IAsyncDropdownProps, prevState: IAsyncDropdownState): void {
        if (this.props.disabled !== prevProps.disabled ||
          this.props.stateKey !== prevProps.stateKey) {
          this.loadOptions();
        }
      }
    
      private loadOptions(): void {
        this.setState({
          loading: true,
          error: undefined,
          options: undefined
        });
    
        this.props.loadOptions()
          .then((options: IDropdownOption[]): void => {
            this.setState({
              loading: false,
              error: undefined,
              options: options
            });
          }, (error: any): void => {
            this.setState((prevState: IAsyncDropdownState, props: IAsyncDropdownProps): IAsyncDropdownState => {
              prevState.loading = false;
              prevState.error = error;
              return prevState;
            });
          });
      }
    
      public render(): JSX.Element {
        const loading: JSX.Element = this.state.loading ? <div><Spinner label={'Loading options...'} /></div> : <div />;
        const error: JSX.Element = this.state.error !== undefined ? <div className={'ms-TextField-errorMessage ms-u-slideDownIn20'}>Error while loading items: {this.state.error}</div> : <div />;
    
        return (
          <div>
            <Dropdown label={this.props.label}
              disabled={this.props.disabled || this.state.loading || this.state.error !== undefined}
              onChanged={this.onChanged.bind(this)}
              selectedKey={this.selectedKey}
              options={this.state.options} />
            {loading}
            {error}
          </div>
        );
      }
    
      private onChanged(option: IDropdownOption, index?: number): void {
        this.selectedKey = option.key;
        // reset previously selected options
        const options: IDropdownOption[] = this.state.options;
        options.forEach((o: IDropdownOption): void => {
          if (o.key !== option.key) {
            o.selected = false;
          }
        });
        this.setState((prevState: IAsyncDropdownState, props: IAsyncDropdownProps): IAsyncDropdownState => {
          prevState.options = options;
          return prevState;
        });
        if (this.props.onChanged) {
          this.props.onChanged(option, index);
        }
      }
    }
    

    La classe AsyncDropdown représente le composant React utilisé pour afficher le contrôle de liste déroulante asynchrone du volet de propriétés :

L’étape suivante consiste à définir le contrôle personnalisé du volet de propriétés. Ce contrôle est utilisé dans le composant WebPart lors de la définition des propriétés dans le volet de propriétés et s’affiche à l’aide du composant React défini précédemment.

Ajout d’un contrôle de liste déroulante asynchrone dans le volet de propriétés

  1. Définissez les propriétés du contrôle de liste déroulante asynchrone du volet de propriétés. Un contrôle de volet de propriétés personnalisé possède deux ensembles de propriétés.

    Le premier est exposé publiquement et sert à définir la propriété du composant WebPart dans le composant WebPart. Ces propriétés sont des propriétés spécifiques du composant, comme le nom affiché à côté du contrôle, les valeurs minimale et maximale d’un compteur ou les options disponibles d’une liste déroulante. Lorsque vous définissez un contrôle de volet de propriétés personnalisé, vous devez transmettre le type TProperties qui décrit ces propriétés, lors de l’implémentation de l’interfaceIPropertyPaneField<TProperties>.

    Le second ensemble de propriétés comprend des propriétés privées utilisées en interne à l’intérieur du contrôle de volet de propriétés personnalisé. Ces propriétés doivent respecter les interfaces API de l’infrastructure SharePoint pour que le contrôle personnalisé s’affiche correctement. Ces propriétés doivent implémenter l’interface IPropertyPaneCustomFieldProps à partir du package @microsoft/sp-property-pane .

  2. Définissez les propriétés publiques du contrôle de liste déroulante asynchrone du volet de propriétés. Dans le dossier src/controls/PropertyPaneAsyncDropdown, créez un fichier nommé IPropertyPaneAsyncDropdownProps.ts, puis entrez le code suivant :

    import { IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown';
    
    export interface IPropertyPaneAsyncDropdownProps {
      label: string;
      loadOptions: () => Promise<IDropdownOption[]>;
      onPropertyChange: (propertyPath: string, newValue: any) => void;
      selectedKey: string | number;
      disabled?: boolean;
    }
    

    Dans l’interface IPropertyPaneAsyncDropdownProps:

    • label: définit le nom affiché à côté de la liste déroulante.
    • loadOptions: définit la méthode appelée pour charger les options disponibles de la liste déroulante.
    • onPropertyChange: définit une méthode appelée lorsque l’utilisateur sélectionne une valeur dans la liste déroulante.
    • selectedKey: renvoie la valeur de la liste déroulante sélectionnée.
    • disabled: indique si le contrôle est désactivé.
  3. Définissez les propriétés internes du contrôle de liste déroulante asynchrone du volet de propriétés. Dans le dossier src/controls/PropertyPaneAsyncDropdown, créez un fichier nommé IPropertyPaneAsyncDropdownInternalProps.ts, puis entrez le code suivant :

    import { IPropertyPaneCustomFieldProps } from '@microsoft/sp-property-pane';
    import { IPropertyPaneAsyncDropdownProps } from './IPropertyPaneAsyncDropdownProps';
    
    export interface IPropertyPaneAsyncDropdownInternalProps extends IPropertyPaneAsyncDropdownProps, IPropertyPaneCustomFieldProps {
    }
    

Bien que l'interface IPropertyPaneAsyncDropdownInternalPropsne définisse pas de nouvelles propriétés, elle combine les propriétés de l'interface précédemment définieIPropertyPaneAsyncDropdownProps et de l'interface SharePoint Framework standardIPropertyPaneCustomFieldProps, ce qui est nécessaire pour qu'un contrôle personnalisé fonctionne correctement.

  1. Définissez le contrôle de liste déroulante asynchrone du volet de propriétés. Dans le dossier src/controls/PropertyPaneAsyncDropdown, créez un fichier nommé PropertyPaneAsyncDropdown.ts, puis entrez le code suivant :

    import * as React from 'react';
    import * as ReactDom from 'react-dom';
    import {
      IPropertyPaneField,
      PropertyPaneFieldType
    } from '@microsoft/sp-property-pane';
    import { IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown';
    import { IPropertyPaneAsyncDropdownProps } from './IPropertyPaneAsyncDropdownProps';
    import { IPropertyPaneAsyncDropdownInternalProps } from './IPropertyPaneAsyncDropdownInternalProps';
    import AsyncDropdown from './components/AsyncDropdown';
    import { IAsyncDropdownProps } from './components/IAsyncDropdownProps';
    
    export class PropertyPaneAsyncDropdown implements IPropertyPaneField<IPropertyPaneAsyncDropdownProps> {
      public type: PropertyPaneFieldType = PropertyPaneFieldType.Custom;
      public targetProperty: string;
      public properties: IPropertyPaneAsyncDropdownInternalProps;
      private elem: HTMLElement;
    
      constructor(targetProperty: string, properties: IPropertyPaneAsyncDropdownProps) {
        this.targetProperty = targetProperty;
        this.properties = {
          key: properties.label,
          label: properties.label,
          loadOptions: properties.loadOptions,
          onPropertyChange: properties.onPropertyChange,
          selectedKey: properties.selectedKey,
          disabled: properties.disabled,
          onRender: this.onRender.bind(this),
          onDispose: this.onDispose.bind(this)
        };
      }
    
      public render(): void {
        if (!this.elem) {
          return;
        }
    
        this.onRender(this.elem);
      }
    
      private onDispose(element: HTMLElement): void {
        ReactDom.unmountComponentAtNode(element);
      }
    
      private onRender(elem: HTMLElement): void {
        if (!this.elem) {
          this.elem = elem;
        }
    
        const element: React.ReactElement<IAsyncDropdownProps> = React.createElement(AsyncDropdown, {
          label: this.properties.label,
          loadOptions: this.properties.loadOptions,
          onChanged: this.onChanged.bind(this),
          selectedKey: this.properties.selectedKey,
          disabled: this.properties.disabled,
          // required to allow the component to be re-rendered by calling this.render() externally
          stateKey: new Date().toString()
        });
        ReactDom.render(element, elem);
      }
    
      private onChanged(option: IDropdownOption, index?: number): void {
        this.properties.onPropertyChange(this.targetProperty, option.key);
      }
    }
    

    La classePropertyPaneAsyncDropdown met en œuvre l'interface standard IPropertyPaneFieldSharePoint Framework en utilisant l'interfaceIPropertyPaneAsyncDropdownProps comme un contrat pour ses propriétés publiques qui peuvent être définies à partir de la partie web. Cette classe contient les trois propriétés publiques suivantes, définies par l’interface IPropertyPaneField :

    • type: Doit être défini sur PropertyPaneFieldType.Custom pour un contrôle de volet de propriété personnalisé.
    • targetProperty: permet d’indiquer le nom de la propriété du composant WebPart à utiliser avec le contrôle.
    • properties: permet de définir les propriétés spécifiques au contrôle.

    Remarquez comment la propriétéproperties est du typeIPropertyPaneAsyncDropdownInternalProps interne plutôt que de l'interfaceIPropertyPaneAsyncDropdownProps publique implémentée par la classe. En effet, le but est de permettre à la propriété properties de définir la méthode requise paronRender() SharePoint Framework. Si la méthode onRender() faisait partie de l’interface IPropertyPaneAsyncDropdownPropspublique, vous devriez lui affecter une valeur dans le composant WebPart lors de l’utilisation du contrôle de liste déroulante asynchrone dans le composant WebPart, ce qui n’est pas souhaitable.

    La classePropertyPaneAsyncDropdown définit une méthode render()publique, qui peut être utilisée pour repeindre le contrôle. Cette méthode est utile dans les listes déroulantes affichées en cascade lorsqu’une valeur définie dans l’une détermine les options disponibles dans l’autre. En appelant la méthode render() après avoir sélectionné un élément, la liste déroulante dépendante charge les options disponibles. Pour cela, vous devez faire comprendre à React que le contrôle a été modifié en définissant la valeur de la propriété stateKey sur la date actuelle. Grâce à cette astuce, le composant est réinitialisé et met à jour les options disponibles lorsque la méthode onRender() est appelée. N’oubliez pas d’implémenter la méthode onDispose() pour démonter l’élément chaque fois que vous fermez le volet de propriétés.

Utilisation du contrôle de liste déroulante asynchrone du volet de propriétés dans le composant WebPart

Lorsque le contrôle de liste déroulante asynchrone du volet de propriétés est prêt, il ne vous reste plus qu’à l’utiliser dans le composant WebPart pour permettre aux utilisateurs de sélectionner une liste.

Ajouter une interface d’informations pour les listes

Pour transmettre des informations sur les listes disponibles de manière cohérente, définissez une interface qui affiche les informations de la liste. Dans le dossier src/webparts/listItems, créez un fichier nommé IListInfo.ts, puis entrez le code suivant :

export interface IListInfo {
  Id: string;
  Title: string;
}

Utiliser le contrôle de liste déroulante asynchrone du volet de propriétés pour afficher la propriété du composant WebPart « listName »

  1. Référencez les types requis. Dans la partie supérieure du fichier src/webparts/listItems/ListItemsWebPart.ts, importez la classe PropertyPaneAsyncDropdown créée précédemment en ajoutant :

    import { PropertyPaneAsyncDropdown } from '../../controls/PropertyPaneAsyncDropdown/PropertyPaneAsyncDropdown';
    
  2. À la suite de ce code, ajoutez une référence à l’interface IDropdownOption et deux fonctions auxiliaires qui fonctionnent avec les propriétés du composant WebPart.

    import { IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown';
    import { update, get } from '@microsoft/sp-lodash-subset';
    
  3. Ajoutez une méthode pour charger les listes disponibles. Dans la classe ListItemsWebPart, ajoutez la méthode loadLists() suivante pour charger les listes disponibles. Dans cet article, vous utilisez des données fictives, mais vous pourriez également appeler l'API REST SharePoint pour récupérer la liste des listes disponibles sur le Web actuel. Pour simuler le chargement des options à partir d'un service externe, la méthode utilise un délai de deux secondes.

    private loadLists(): Promise<IDropdownOption[]> {
      return new Promise<IDropdownOption[]>((resolve: (options: IDropdownOption[]) => void, reject: (error: any) => void) => {
        setTimeout(() => {
          resolve([{
            key: 'sharedDocuments',
            text: 'Shared Documents'
          },
            {
              key: 'myDocuments',
              text: 'My Documents'
            }]);
        }, 2000);
      });
    }
    
  4. Ajoutez une méthode pour modifier la valeur dans la liste déroulante. Dans la classe ListItemsWebPart, ajoutez une méthode nommée onListChange() :

    private onListChange(propertyPath: string, newValue: any): void {
      const oldValue: any = get(this.properties, propertyPath);
      // store new value in web part properties
      update(this.properties, propertyPath, (): any => { return newValue; });
      // refresh web part
      this.render();
    }
    

    Lorsqu’une liste est sélectionnée dans la liste déroulante « Liste », la valeur sélectionnée doit se trouver dans les propriétés du composant WebPart et le composant WebPart doit être réinitialisé pour afficher la propriété sélectionnée.

  5. Affichez la propriété du composant WebPart « Liste » à l’aide du contrôle de liste déroulante asynchrone du volet de propriétés. Dans la classeListItemsWebPart, modifiez la méthodegetPropertyPaneConfiguration() pour utiliser le contrôle asynchrone du volet de propriété du menu déroulantlistName pour rendre la propriété de la partie web.

    export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {
      // ...
    
      protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
        return {
          pages: [
            {
              header: {
                description: strings.PropertyPaneDescription
              },
              groups: [
                {
                  groupName: strings.BasicGroupName,
                  groupFields: [
                    new PropertyPaneAsyncDropdown('listName', {
                      label: strings.ListFieldLabel,
                      loadOptions: this.loadLists.bind(this),
                      onPropertyChange: this.onListChange.bind(this),
                      selectedKey: this.properties.listName
                    })
                  ]
                }
              ]
            }
          ]
        };
      }
    
      // ...
    }
    
  6. À ce stade, vous pouvez sélectionner une liste à l’aide du contrôle de volet de propriétés de liste déroulante asynchrone nouvellement créé. Pour vérifier que le contrôle fonctionne comme prévu, ouvrez la console et exécutez :

    gulp serve
    

    Contrôle de liste déroulante asynchrone du volet de propriétés en train de charger ses options sans bloquer l’interface utilisateur du composant WebPart

    Sélection d’une option dans le contrôle de liste déroulante asynchrone du volet de propriétés

Implémentation des listes déroulantes en cascade à l’aide du contrôle de liste déroulante asynchrone du volet de propriétés

Lorsque vous créez des composants WebPart dans SharePoint Framework, il se peut que vous deviez implémenter une configuration où les options disponibles dépendent d’une autre option choisie précédemment. Un exemple courant est de permettre aux utilisateurs de choisir une liste et, dans cette liste, de sélectionner un élément. La liste des éléments disponibles dépendraient alors de la liste sélectionnée. Voici comment implémenter ce scénario en utilisant le contrôle de liste déroulante asynchrone du volet de propriétés implémenté précédemment.

Ajouter la propriété du composant WebPart « Élément »

  1. Dans l’éditeur de code, ouvrez le fichier src/webparts/listItems/ListItemsWebPart.manifest.json. Dans la section properties, ajoutez une propriété nommée item pour qu’elle apparaisse de la manière suivante :

    {
      ...
      "preconfiguredEntries": [{
        ...
        "properties": {
          "description": "List items",
          "listName": "",
          "item": ""
        }
      }]
    }
    
  2. Remplacez le code de l’interface IListItemsWebPartProps dans le fichier src/webparts/listItems/ListItemsWebPart.ts par :

    export interface IListItemsWebPartProps {
      description: string;
      listName: string;
      item: string;
    }
    
  3. Mettez à jour le contenu du fichier src/webparts/listItems/components/IListItemsProps.ts pour ajouter la propriété item :

    export interface IListItemsProps {
      ...
      listName: string;
      itemName: string;
    }
    
  4. Dans le fichier src/webparts/listItems/ListItemsWebPart.ts, remplacez le code de la méthode render() pour inclure la propriété item :

    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.item,
          ...
        });
    
        ReactDom.render(element, this.domElement);
      }
    
      // ...
    }
    
  5. Dans le fichier src/webparts/listItems/loc/mystrings.d.ts, remplacez l’interface IListItemsWebPartStrings pour inclure la propriété ItemFieldLabel :

    declare interface IListItemsWebPartStrings {
      ...
      PropertyPaneDescription: string;
      BasicGroupName: string;
      ListFieldLabel: string;
      ItemFieldLabel: string;
    }
    
  6. Dans le fichier src/webparts/listItems/loc/en-us.js, ajoutez la définition manquante pour la chaîne ItemFieldLabel :

    define([], function() {
      return {
        ...
        "PropertyPaneDescription": "Description",
        "BasicGroupName": "Group Name",
        "ListFieldLabel": "List",
        "ItemFieldLabel": "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(): React.ReactElement<IListItemsProps> {
    const {
      description,
      isDarkTheme,
      environmentMessage,
      hasTeamsContext,
      userDisplayName,
      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>
    );
  }
}

Ajouter 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. En fonction de la liste sélectionnée précédemment, la méthode loadItems() renvoie des éléments de liste fictifs. Si aucune liste n’a été sélectionnée, la méthode résout la promesse sans aucune donnée.

private loadItems(): Promise<IDropdownOption[]> {
  if (!this.properties.listName) {
    // resolve to empty options since no list has been selected
    return Promise.resolve([]);
  }

  const wp: ListItemsWebPart = this;

  return new Promise<IDropdownOption[]>((resolve: (options: IDropdownOption[]) => 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);
  });
}

Ajoute une méthode pour sélectionner un élément

Dans la classe ListItemsWebPart, ajoutez une méthode nommée onListItemChange() : Après avoir sélectionné un élément dans la liste déroulante des éléments, le composant WebPart doit stocker la nouvelle valeur dans les propriétés du composant WebPart et réinitialiser le composant WebPart pour afficher les modifications apportées à l’interface utilisateur.

private onListItemChange(propertyPath: string, newValue: any): void {
  const oldValue: any = get(this.properties, propertyPath);
  // store new value in web part properties
  update(this.properties, propertyPath, (): any => { return newValue; });
  // refresh web part
  this.render();
}

Afficher la propriété du composant WebPart « Élément » dans le volet de propriétés

  1. Dans la classeListItemsWebPart, ajoutez une nouvelle propriété de classe appeléeitemsDropdown :

    export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {
      private itemsDropDown: PropertyPaneAsyncDropdown;
      // ...
    }
    
  2. Remplacez le code de la méthode getPropertyPaneConfiguration() par :

    export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {
      // ...
    
      protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
        // reference to item dropdown needed later after selecting a list
        this.itemsDropDown = new PropertyPaneAsyncDropdown('item', {
          label: strings.ItemFieldLabel,
          loadOptions: this.loadItems.bind(this),
          onPropertyChange: this.onListItemChange.bind(this),
          selectedKey: this.properties.item,
          // should be disabled if no list has been selected
          disabled: !this.properties.listName
        });
    
        return {
          pages: [
            {
              header: {
                description: strings.PropertyPaneDescription
              },
              groups: [
                {
                  groupName: strings.BasicGroupName,
                  groupFields: [
                    new PropertyPaneAsyncDropdown('listName', {
                      label: strings.ListFieldLabel,
                      loadOptions: this.loadLists.bind(this),
                      onPropertyChange: this.onListChange.bind(this),
                      selectedKey: this.properties.listName
                    }),
                    this.itemsDropDown
                  ]
                }
              ]
            }
          ]
        };
      }
      // ...
    }
    

    La liste déroulante pour la propriété « item » est initialisée de la même manière que la liste déroulante de la propriété « listName ». La seule différence est qu’une instance du contrôle doit être affectée à la variable de classe, car la liste déroulante des éléments doit être actualisée lorsqu’une liste est sélectionnée.

Charger les éléments de la liste sélectionnée

Initialement lorsque aucune liste n’est sélectionnée, la liste déroulante des éléments est désactivée. Elle est activée lorsque l’utilisateur sélectionne une liste. Lorsqu’une liste est sélectionnée, la liste déroulante des éléments charge aussi les éléments de liste de cette liste.

  1. Pour cela, remplacez la méthode onListChange() définie précédemment par :

    private onListChange(propertyPath: string, newValue: any): void {
      const oldValue: any = get(this.properties, propertyPath);
      // store new value in web part properties
      update(this.properties, propertyPath, (): any => { return newValue; });
      // reset selected item
      this.properties.item = undefined;
      // store new value in web part properties
      update(this.properties, 'item', (): any => { return this.properties.item; });
      // refresh web part
      this.render();
      // reset selected values in item dropdown
      this.itemsDropDown.properties.selectedKey = this.properties.item;
      // allow to load items
      this.itemsDropDown.properties.disabled = false;
      // load items and re-render items dropdown
      this.itemsDropDown.render();
    }
    

    Lorsqu’une liste est sélectionnée, l’élément sélectionné est réinitialisé, conservé dans les propriétés du composant WebPart et rétabli dans la liste déroulante des éléments. La liste déroulante de sélection d’un élément devient activée et la liste déroulante est actualisée pour charger ses options.

  2. Pour vérifier que tout fonctionne comme prévu, dans la console, exécutez :

    gulp serve
    

    Lorsque vous ajoutez le composant WebPart à la page pour la première fois et ouvrez le volet de propriétés, les listes déroulantes doivent être désactivées et en train de charger leurs options.

    Listes déroulantes dans le volet de propriétés du composant WebPart en train de charger leurs données

    Une fois les options chargées, la liste déroulante « Liste » est activée. Si aucune liste n’est sélectionnée, la liste déroulante « Élément » reste désactivée.

    La liste déroulante « Liste » dans le volet de propriétés du composant WebPart est activée. La liste déroulante « Élément » est désactivée

    Lorsqu’une liste est sélectionnée dans la liste déroulante « Liste », la liste déroulante « Élément » charge les éléments disponibles dans cette liste.

    Chargement des éléments disponibles dans la liste déroulante « Élément » après sélection d’une liste dans la liste déroulante « Liste »

    Une fois les éléments disponibles chargés, la liste déroulante « Élément » est activée.

    Sélection d’un élément dans la liste déroulante « Élément » dans le volet de propriétés du composant WebPart

    Lorsqu’un élément est sélectionné dans la liste déroulante « Élément », le composant WebPart est actualisé et l’élément sélectionné est affiché dans le corps du composant.

    Liste sélectionnée et élément affiché dans le composant WebPart

  3. Arrêtez le serveur web local en appuyant sur Ctrl+C dans la console.

Voir aussi