Cursos
Módulo
Obtenga información sobre cómo habilitar configuraciones de elementos web con paneles de propiedades en SharePoint Framework.
Este explorador ya no se admite.
Actualice a Microsoft Edge para aprovechar las características y actualizaciones de seguridad más recientes, y disponer de soporte técnico.
SharePoint Framework contiene un conjunto de controles estándares para el panel de propiedades. Aun así, a veces es necesaria funcionalidad adicional más allá de los controles básicos. Podría necesitar actualizaciones asincrónicas de los datos en un control o una interfaz de usuario específica. Compile un control personalizado para el panel de propiedades para obtener la funcionalidad que necesita.
En este artículo, compilará un control desplegable personalizado que carga sus datos de forma asincrónica desde un servicio externo sin bloquear la interfaz de usuario del elemento web.
El origen del elemento web de trabajo está disponible en GitHub en sp-dev-fx-webparts/samples/react-custompropertypanecontrols/.
Nota
Antes de seguir los pasos de este artículo, asegúrese de configurar el entorno de desarrollo para crear soluciones de SharePoint Framework.
Empiece por crear una carpeta para el proyecto:
md react-custompropertypanecontrol
Vaya a la carpeta del proyecto:
cd react-custompropertypanecontrol
En la carpeta del proyecto, ejecute el generador de Yeoman de SharePoint Framework para aplicar scaffolding a un nuevo proyecto de SharePoint Framework:
yo @microsoft/sharepoint
En el momento en que se le solicite, introduzca los siguientes valores (seleccione la opción predeterminada para todas las solicitudes que se omitan a continuación):
Abra la carpeta del proyecto en el editor de código.
El elemento web que está generando muestra los elementos de lista de la lista de SharePoint seleccionada. Los usuarios pueden seleccionar una lista en las propiedades del elemento web. Para almacenar la lista seleccionada, cree una propiedad de elemento web denominada listName
.
En el editor de código, abra el archivo src/webparts/listItems/ListItemsWebPartManifest.json. Reemplace la propiedad de description
predeterminada por una nueva propiedad denominada listName
:
{
...
"preconfiguredEntries": [{
...
"properties": {
"listName": ""
}
}]
}
Abra el archivo src/webparts/listItems/ListItemsWebPart.ts y actualice la interfaz IListItemsWebPartProps
a lo siguiente:
export interface IListItemsWebPartProps {
description: string;
listName: string;
}
En el archivo src/webparts/listItems/ListItemsWebPart.ts, cambie el método render()
a:
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);
}
// ...
}
Actualizar el método getPropertyPaneConfiguration()
a:
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
})
]
}
]
}
]
};
}
// ...
}
En el archivo src/webparts/listItems/loc/mystrings.d.ts, agregue una nueva propiedad ListFieldLabel
de tipo string
a la interfaz IListItemsWebPartStrings
existente:
declare interface IListItemsWebPartStrings {
PropertyPaneDescription: string;
BasicGroupName: string;
..
ListFieldLabel: string;
}
En el archivo src/webparts/listItems/loc/en-us.js, agregue una nueva propiedad ListFieldLabel
al objeto devuelto:
define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
...
"ListFieldLabel": "List"
}
});
Abra el archivo src/webparts/listItems/components/IListItemsProps.ts y agregue la propiedad listName
a la interfaz de lista:
export interface IListItemsProps {
description: string;
isDarkTheme: boolean;
environmentMessage: string;
hasTeamsContext: boolean;
userDisplayName: string;
listName: string;
}
En el archivo src/webparts/listItems/components/ListItems.tsx, cambie los contenidos del método render()
a:
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>
);
}
}
Ejecute el comando siguiente para comprobar que el proyecto se está ejecutando:
gulp serve
En el explorador web, agregue el elemento web Lista de elementos al lienzo y abra sus propiedades. Compruebe que el valor establecido para la propiedad List se muestra en el cuerpo del elemento web.
SharePoint Framework ofrece un control desplegable estándar que permite a los usuarios seleccionar un valor específico. El control desplegable está construido de modo que requiere que se conozcan todos sus valores por adelantado. Si desea cargar los valores dinámicamente o está cargando valores de forma asincrónica desde un servicio externo y no quiere bloquear todo el elemento web, la creación de un control desplegable personalizado es una opción.
Al crear un control de panel de propiedades personalizado que utiliza React en SharePoint Framework, el control se compone de una clase que registra el control con el elemento web, y de un componente React que representa el desplegable y gestiona sus datos.
Cree la carpeta de componentes. En la carpeta src del proyecto, cree una jerarquía de tres nuevas carpetas de modo que la estructura de carpetas sea src/controls/PropertyPaneAsyncDropdown/components.
Defina las propiedades del componente React desplegable asincrónico. En la carpeta src/controls/PropertyPaneAsyncDropdown/components cree un archivo denominado IAsyncDropdownProps.ts y escriba el siguiente código:
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 clase IAsyncDropdownProps
define propiedades que pueden establecerse en el componente React usado por el control de panel de propiedades personalizado:
label
especifica la etiqueta del control desplegable.loadOptions
para cargar las opciones disponibles.onChanged
.selectedKey
especifica el valor seleccionado, que puede ser una cadena o un número.disabled
especifica si el control desplegable está deshabilitado o no.stateKey
se usa para forzar el componente React que se va a volver a representar.Defina la interfaz del componente React desplegable asincrónico. En la carpeta src/controls/PropertyPaneAsyncDropdown/components cree un archivo denominado IAsyncDropdownState.ts y escriba el código siguiente:
import { IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown';
export interface IAsyncDropdownState {
loading: boolean;
options: IDropdownOption[];
error: string;
}
La interfaz IAsyncDropdownState
describe el estado del componente React:
loading
determina si el componente está cargando sus opciones en el momento dado.options
contiene todas las opciones disponibles.error
, desde donde se comunica al usuario.Defina el componente React desplegable asincrónico. En la carpeta src/controls/PropertyPaneAsyncDropdown/components, cree un archivo denominado AsyncDropdown.tsx y escriba el siguiente código:
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 clase AsyncDropdown
representa el componente React usado para representar el control de panel de propiedades desplegable asincrónico:
componentDidMount()
o sus propiedades disabled
o stateKey
cambian, y cargan las opciones disponibles mediante una llamada al método loadOptions()
pasado a través de las propiedades.El siguiente paso es definir el control de panel de propiedades personalizado. Este control se usa dentro del elemento web al definir propiedades en el panel de propiedades y se representa mediante el componente React previamente definido.
Defina las propiedades del control de panel de propiedades desplegable asincrónico. Un control de panel de propiedades personalizado tiene dos conjuntos de propiedades.
El primer conjunto de propiedades se expone públicamente y se utiliza para definir la propiedad del elemento web dentro del elemento web. Estas propiedades son propiedades específicas de los componentes, como la etiqueta que se muestra al lado del control, los valores mínimos y máximos de un indicador giratorio, o las opciones disponibles para un desplegable. Cuando se define un control de panel de propiedades personalizado, se debe pasar el tipo que describe estas propiedades como el tipo TProperties
al implementar la interfaz IPropertyPaneField<TProperties>
.
El segundo conjunto de propiedades son propiedades privadas que se utilizan internamente dentro del control de panel de propiedades personalizado. Estas propiedades deben adherirse a las API de SharePoint Framework para que el control personalizado se represente correctamente. Estas propiedades deben implementar la IPropertyPaneCustomFieldProps
interfaz desde el paquete @microsoft/sp-property-pane .
Defina las propiedades públicas del control de panel de propiedades desplegable asincrónico. En la carpeta src/controls/PropertyPaneAsyncDropdown, cree un archivo denominado IPropertyPaneAsyncDropdownProps.ts y escriba el siguiente código:
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;
}
En la interfaz IPropertyPaneAsyncDropdownProps
:
label
: define la etiqueta que aparece junto al desplegable.loadOptions
: define el método al que se llama para cargar las opciones del desplegable disponibles.onPropertyChange
: define un método al que se llama cuando el usuario selecciona un valor en la lista desplegable.selectedKey
: devuelve el valor del desplegable seleccionado.disabled
: especifica si el control está deshabilitado o no.Defina las propiedades internas del control de panel de propiedades desplegable asincrónico. En la carpeta src/controls/PropertyPaneAsyncDropdown, cree un archivo denominado IPropertyPaneAsyncDropdownInternalProps.ts y escriba el siguiente código:
import { IPropertyPaneCustomFieldProps } from '@microsoft/sp-property-pane';
import { IPropertyPaneAsyncDropdownProps } from './IPropertyPaneAsyncDropdownProps';
export interface IPropertyPaneAsyncDropdownInternalProps extends IPropertyPaneAsyncDropdownProps, IPropertyPaneCustomFieldProps {
}
Aunque la interfaz IPropertyPaneAsyncDropdownInternalProps
no define propiedades nuevas, combina las propiedades de la interfaz IPropertyPaneAsyncDropdownProps
definida anteriormente y de la interfaz estándar IPropertyPaneCustomFieldProps
de SharePoint Framework que es necesaria para que un control personalizado se ejecute correctamente.
Defina el control de panel de propiedades desplegable asincrónico. En la carpeta src/controls/PropertyPaneAsyncDropdown, cree un archivo denominado PropertyPaneAsyncDropdown.ts y escriba el siguiente código:
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 clase PropertyPaneAsyncDropdown
implementa la interfaz estándar IPropertyPaneField
de SharePoint Framework mediante la interfaz IPropertyPaneAsyncDropdownProps
como un contrato para sus propiedades públicas que se puede establecer desde el elemento web. La clase contiene las tres propiedades públicas siguientes definidas por la interfaz IPropertyPaneField
:
type
: debe establecerse en PropertyPaneFieldType.Custom
para un control de panel de propiedades personalizado.targetProperty
: se utiliza para especificar el nombre de la propiedad del elemento web que se utilizará con el control.properties
: se utiliza para definir propiedades específicas del control.Observe cómo la propiedad properties
es del tipo de IPropertyPaneAsyncDropdownInternalProps
interno en lugar de la interfaz de IPropertyPaneAsyncDropdownProps
pública implementada por la clase. Esto se hace de forma intencionada para que la propiedad properties
pueda definir el método onRender()
requerido por SharePoint Framework. Si el método onRender()
formaba parte de la interfaz pública IPropertyPaneAsyncDropdownProps
, cuando use el control desplegable asincrónico en el elemento web, tendrá que asignarle un valor en el elemento web, lo cual no es deseable.
La clase PropertyPaneAsyncDropdown
define un método público render()
que se puede usar para volver a dibujar el control. Esto es útil en situaciones tales como cuando haya desplegables en cascada donde el valor establecido en uno determina las opciones disponibles en otro. Si llama al método render()
después de seleccionar un elemento, puede hacer que el desplegable dependiente cargue las opciones disponibles. Para que esto funcione, tiene que hacer que React detecte que el control ha cambiado. Esto se consigue mediante el establecimiento del valor de stateKey
en la fecha actual. Gracias a este truco, cada vez que se llame al método onRender()
el componente no solo se vuelve a representar, sino que también actualiza las opciones disponibles. No olvide implementar el método onDispose()
para desmontar el elemento cada vez cierre el panel de propiedades.
Con el control de panel de propiedades desplegable asincrónico listo, el siguiente paso es usarlo en el elemento web para permitir a los usuarios seleccionar una lista.
Para pasar información sobre las listas disponibles de una manera coherente, defina una interfaz que represente la información sobre una lista. En la carpeta src/webparts/listItems, cree un archivo denominado IListInfo.ts y escriba el siguiente código:
export interface IListInfo {
Id: string;
Title: string;
}
Haga referencia a los tipos necesarios. En la sección superior del archivo src/webparts/listItems/ListItemsWebPart.ts, importe la clase PropertyPaneAsyncDropdown
creada anteriormente. Para ello, agregue lo siguiente:
import { PropertyPaneAsyncDropdown } from '../../controls/PropertyPaneAsyncDropdown/PropertyPaneAsyncDropdown';
Después de ese código, agregue una referencia a la interfaz IDropdownOption
y dos funciones auxiliares necesarias para trabajar con propiedades de elementos web.
import { IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown';
import { update, get } from '@microsoft/sp-lodash-subset';
Agregue un método para cargar las listas disponibles. En la clase ListItemsWebPart
, agregue el siguiente método loadLists()
para cargar las listas disponibles. En este artículo, se usan datos simulados, pero también podría llamar a la API de REST de SharePoint para recuperar la lista de listas disponibles en la web actual. Para simular las opciones de carga desde un servicio externo, el método usa un retraso de dos segundos
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);
});
}
Agregue un método para controlar el cambio del valor del desplegable. En la clase ListItemsWebPart
, agregue un nuevo método denominado 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();
}
Después de seleccionar una lista en el desplegable, debe conservarse el valor seleccionado en las propiedades del elemento web y este debería representarse de nuevo para reflejar la propiedad seleccionada.
Represente la propiedad de elemento web de lista mediante el control de panel de propiedades desplegable asincrónico. En la clase ListItemsWebPart
, cambie el método getPropertyPaneConfiguration()
para usar el control de panel de propiedades desplegable asincrónico para representar la propiedad de elemento web listName
.
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
})
]
}
]
}
]
};
}
// ...
}
En este momento, puede seleccionar una lista mediante el control de panel de propiedades desplegable asincrónico recién creado. Para comprobar que el control funciona como se esperaba, abra la consola y ejecute:
gulp serve
Al compilar elementos web de SharePoint Framework, es posible que necesite implementar una configuración en la que las opciones disponibles dependan de otra opción elegida anteriormente. Un ejemplo común es comenzar dejando que los usuarios elijan una lista y, en esa lista, seleccionar un elemento de lista. La lista de elementos disponibles dependerá de la lista seleccionada. Aquí puede ver cómo implementar un escenario como este mediante el control de panel de propiedades desplegable asincrónico implementado en pasos anteriores.
En el editor de código, abra el archivo src/webparts/listItems/ListItemsWebPart.manifest.json. Agregue una nueva propiedad a la sección properties
denominada item
similar a la siguiente:
{
...
"preconfiguredEntries": [{
...
"properties": {
"description": "List items",
"listName": "",
"item": ""
}
}]
}
Cambie el código de la interfaz IListItemsWebPartProps en el archivo src/webparts/listItems/ListItemsWebPart.ts a:
export interface IListItemsWebPartProps {
description: string;
listName: string;
item: string;
}
Actualice el contenido del archivo src/webparts/listItems/components/IListItemsProps.ts para agregar la propiedad item
:
export interface IListItemsProps {
...
listName: string;
itemName: string;
}
En el archivo src/webparts/listItems/ListItemsWebPart.ts, cambie el código del método render()
para incluir la propiedad 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);
}
// ...
}
En el archivo src/webparts/listItems/loc/mystrings.d.ts cambie la interfaz IListItemsWebPartStrings
para incluir la propiedad ItemFieldLabel
:
declare interface IListItemsWebPartStrings {
...
PropertyPaneDescription: string;
BasicGroupName: string;
ListFieldLabel: string;
ItemFieldLabel: string;
}
En el archivo src/webparts/listItems/loc/en-us.js agregue la definición que falta para la cadena ItemFieldLabel
:
define([], function() {
return {
...
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"ListFieldLabel": "List",
"ItemFieldLabel": "Item"
}
});
En el archivo src/webparts/listItems/components/ListItems.tsx, cambie el método render()
a:
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>
);
}
}
En el archivo src/webparts/listItems/ListItemsWebPart.ts, en la clase ListItemsWebPart
, agregue un nuevo método para cargar los elementos de lista disponibles de la lista seleccionada. Al igual que el método para cargar listas disponibles, usará datos simulados. En función de la lista seleccionada anteriormente, el método loadItems()
devuelve elementos de lista ficticia. Cuando no se haya seleccionado ninguna lista, el método resuelve la premisa sin ningún dato.
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);
});
}
En la clase ListItemsWebPart
, agregue un nuevo método denominado onListItemChange()
. Después de seleccionar un elemento en el desplegable de elementos, el elemento web debería almacenar el nuevo valor en las propiedades del elemento web y volver a representar el elemento web para reflejar los cambios en la interfaz de usuario.
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();
}
En la clase ListItemsWebPart
, agregue una nueva propiedad de clase llamada itemsDropdown
:
export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {
private itemsDropDown: PropertyPaneAsyncDropdown;
// ...
}
Cambie el código del método getPropertyPaneConfiguration()
por:
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 lista desplegable de la propiedad item se inicializa de forma similar al desplegable de la propiedad listName. La única diferencia es que, dado que después de seleccionar una lista el desplegable de elementos tiene que actualizarse, se tiene que asignar una instancia del control a la variable de clase.
Inicialmente, cuando no se selecciona ninguna lista, el desplegable de elementos se deshabilita y se habilita después de que el usuario seleccione una lista. Después de seleccionar una lista, el desplegable de elementos también carga elementos de la lista de ella.
Para implementar esta lógica, extienda el método onListChange()
definido anteriormente a:
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();
}
Después de seleccionar una lista, el elemento seleccionado se restablece, se conserva en propiedades de elementos web y se restablece en el desplegable de elementos. La lista desplegable para seleccionar un elemento se habilita y la lista desplegable se actualiza para cargar sus opciones.
Para comprobar que todo funciona como se esperaba, en la consola ejecute:
gulp serve
Después de agregar el elemento web a la página por primera vez y abrir su panel de propiedades, debería ver los desplegables deshabilitados y cargando sus opciones.
Una vez que se hayan cargado las opciones, se habilita el cuadro de lista desplegable. Como aún no ha seleccionado ninguna lista, el desplegable de elementos permanece deshabilitado.
Después de seleccionar una lista en el desplegable de lista, el desplegable de elementos cargará elementos disponibles en ella.
Una vez que se hayan cargado los elementos disponibles, se habilita el desplegable de elementos.
Después de seleccionar un elemento en el desplegable de elementos, el elemento web se actualiza mostrando el elemento seleccionado en su cuerpo.
Presione CTRL+C en la consola para detener el servidor web local.
Cursos
Módulo
Obtenga información sobre cómo habilitar configuraciones de elementos web con paneles de propiedades en SharePoint Framework.