Tipos de géneros de libros - Conexión con SharePoint online

Hola a todo@s, continuando con la serie de entradas en el blog La librería, en esta entrada se pretende enseñar como se conecta el componente SPfx con los servicios de SharePoint online, para realizar consultas sobre la lista de tipos de géneros de libros.

Hasta ahora, la información que se mostraba a los usuarios en el componente SPfx, venia de la implementación de un Mosk o emulador. Ahora se va a realizar los mecanismos que establecen una conexión directa a los servicios REST de SharePoint online.

Como se desea que el componente SPfx, conviva con ambas formas en la obtención de datos, se ha de desarrollar una arquitectura que permita este tipo de convivencia, pero que al usuario final sea idéntica.

Dentro de la variedad de patrones de diseño que se pueden realizar, en este ejercicio se ha elegido el patrón Inyección de dependencias, que consiste en delegar un tipo de tareas de un componente principal en otros componentes secundarios. Para este ejercicio se van a delegar las funciones como la obtención o la creación de tipos de géneros de libros en un componente secundario.

Además, se le va a aplicar a este componente secundario el patrón de diseño Factoría abstracta, que consiste en que componentes con funcionalidades similares, compartan los mismos métodos, pero la implementación por parte de cada componente sea totalmente distinta.

Un ejemplo fácil de entender de este patrón son los procesos de mandar un SMS o un Email. Ambos comparten en común la función Enviar, pero la implementación de enviar la información es distinta para cada patrón, ya que uno usa componentes de SMTP para enviar correos electrónicos y el otro componente usar componentes de SMS para mandar mensajes a los móviles.

El objetivo que se persigue enseñar en esta entrada son los siguientes:

  • Patrón de diseño Factoría abstracta.

  • Patrón de diseño Inyección de dependencias.

  • Aplicar nuevos conceptos con lo desarrollado hasta la actualidad.

  • Conexión a la lista de tipo de géneros de libros en SharePoint online.

Patrón de diseño Factoría abstracta

Para la realización de un patrón Factoría abstracta, es necesario crear una serie de componentes y objetos que nos permita disponer de métodos comunes, pero con implementaciones diferentes.

A continuación, se van a ir explicando cada componente necesario para realizar este patrón de diseño.

Definición del interfaz IWebApiCalls

Para comenzar el patrón de diseño Factoria abstracta, se va a definir una clase de tipo interfaz en el que se van a definir los métodos públicos que van a compartir los componentes implicados con funciones similares.

Como las tareas de los componentes es la de realizar llamadas a los servicios REST de SharePoint online, la definición del interfaz se ha llamado IWebApiCalls y su fichero es IWebApiCalls.tsx.

He de informar que se han definido más métodos de los necesarios en esta entrada, ya que se implementarán en futuras entradas de la serie La librería.

import { IItemGenre } from './../Entities/IItemGenre';
import { IListItemsGenre } from './../Entities/IListItemsGenre';
/**
* IWebApiCalls interface contains the definitions of the methods to be used in calls to the Web API services
*/
export interface IWebApiCalls {
    /**
    * Get the all item of repository
    */
    getRepositoryGenres(): Promise<IListItemsGenre>;

    /**
    * Get item of repository by id
    * @param id
    */
    getRepositoryGenreById(id: number): Promise<IItemGenre>;

    /**
    * Ask if there is already a genre with this title in the repository
    * @param title
    */
    existGenreInRepository(title: string): Promise<boolean>;

    /**
    * Create a new gender in the repository
    * @param newItem
    */
    addRepositoryGenres(newItem: IItemGenre): Promise<IListItemsGenre>;

    /**
    * Update a gender in the repository
    * @param UpdateItem
    */
    updateRepositoryGenres(updateItem: IItemGenre): Promise<IListItemsGenre>;

    /**
    * Delete a gender in the repository
    * @param id
    */
    deleteRepositoryGenres(id: number): Promise<IListItemsGenre>;
}

De la definición del interfaz, hay que destacar los siguientes aspectos:

  • Utiliza las entidades IListItemsGenre y IItemGenre definidas anteriormente en otras entradas de la serie La librería.

  • Todos los métodos definidos devuelven la información bajo el objeto Promise.

    Como ahora se va a trabajar con los servicios que ofrece SharePoint online, hay que informar que la utilización de estos servicios se realizan de forma asíncrona.

    El objeto Promise es el mecanismo que se dispone para saber cuándo ha finalizado el servicio solicitado a SharePoint online y continuar con la lógica de negocio establecida.

    En el siguiente enlace Carreras de camellos (próximamente) os dejo una entrada en el que se explica como funciona el objeto Promise a través de clásico de las ferias españolas, la carrera de camellos, pero digitalmente.

Definición de la clase abstracta WebApiCallsAbstract

Una clase abstracta, es una clase que no se puede instanciar, pero en la que se pueden definir funciones y propiedades que se implementaran en el siguiente nivel del patrón de diseño Factoría Abstracta.

La clase abstracta se ha definido como WebApiCallsAbstract e implementa el interfaz IWebApiCalls. Esta clase está definida en el fichero WebApiCallsAbstract.tsx.

En la clase se han implementado las funciones públicas requeridas por el interfaz IWebApiCalls, pero como no se puede instanciar objetos de este tipo de clase, se han creado definiciones de funciones que deberán se implementas por las clases que hereden o se extiendan de la clase WebApiCallsAbstract.

import { IWebApiCalls } from "./IWebApiCalls";
import { IItemGenre } from './../Entities/IItemGenre';
import { IListItemsGenre } from './../Entities/IListItemsGenre';

/**
 * WebApiCallsAbstract
 */
export abstract class WebApiCallsAbstract implements IWebApiCalls {
    public getRepositoryGenres(): Promise<IListItemsGenre> {
        return this.getRepositoryGenresImplementation();
    }
    public getRepositoryGenreById(id: number): Promise<IItemGenre> {
        return this.getRepositoryGenreByIdImplementation(id);
    }
    public existGenreInRepository(title: string): Promise<boolean> {
        return this.existGenreInRepositoryImplementation(title);
    }
    public addRepositoryGenres(newItem: IItemGenre): Promise<IListItemsGenre> {
        return this.addRepositoryGenresImplementation(newItem);
    }
    public updateRepositoryGenres(updateItem: IItemGenre): Promise<IListItemsGenre> {
        return this.updateRepositoryGenresImplementation(updateItem);
    }
    public deleteRepositoryGenres(id: number): Promise<IListItemsGenre> {
        return this.deleteRepositoryGenresImplementation(id);
    }

    protected abstract getRepositoryGenresImplementation(): Promise<IListItemsGenre>;
    protected abstract getRepositoryGenreByIdImplementation(id: number): Promise<IItemGenre>;
    protected abstract addRepositoryGenresImplementation(newItem: IItemGenre): Promise<IListItemsGenre>;
    protected abstract existGenreInRepositoryImplementation(title: string): Promise<boolean>;
    protected abstract updateRepositoryGenresImplementation(updateItem: IItemGenre): Promise<IListItemsGenre>;
    protected abstract deleteRepositoryGenresImplementation(id: number): Promise<IListItemsGenre>;
}

Definición de la clase abstracta WebApiCalls

Esta clase abstracta es la clase que se va a usar como base o punto de salida para crear los componentes u objetos finales que disponen de mismas funciones pero que se implementa de forma distinta.

La clase abstracta se ha definido como WebApiCalls y se extiende de la clase abstracta WebApiCallsAbstract. Esta clase está definida en el fichero WebApiCalls.tsx.

Igual que en el anterior apartado, en la clase se han implementado las funciones públicas requeridas por la extensión WebApiCallsAbstract, pero como no se puede instanciar objetos de este tipo de clase, se han creado definiciones de funciones que deberán se implementas por las clases que hereden o se extiendan de la clase WebApiCalls.

Hay que informar que, en esta clase, se pueden definir o implementar aquellas funciones privadas que tengan en común los componentes que se extiendan de esta clase.

import { WebApiCallsAbstract } from './WebApiCallsAbstract';
import { IItemGenre } from './../Entities/IItemGenre';
import { IListItemsGenre } from './../Entities/IListItemsGenre';

/**
 * WebApiCalls
 */
export abstract class WebApiCalls extends WebApiCallsAbstract {
    protected getRepositoryGenresImplementation(): Promise<IListItemsGenre> {
        return this.executeGetRepositoryGenres();
    }

    protected getRepositoryGenreByIdImplementation(id: number): Promise<IItemGenre> {
        return this.executeGetRepositoryGenreById(id);
    }

    protected addRepositoryGenresImplementation(newItem: IItemGenre): Promise<IListItemsGenre> {
        return this.executeAddRepositoryGenres(newItem);
    }

    protected existGenreInRepositoryImplementation(title: string): Promise<boolean> {
        return this.executeExistGenreInRepository(title);
    }

    protected updateRepositoryGenresImplementation(updateItem: IItemGenre): Promise<IListItemsGenre> {
        return this.executeUpdateRepositoryGenres(updateItem);
    }

    protected deleteRepositoryGenresImplementation(id: number): Promise<IListItemsGenre> {
        return this.executeDeleteRepositoryGenres(id);
    }

    protected abstract executeGetRepositoryGenres(): Promise<IListItemsGenre>;
    protected abstract executeGetRepositoryGenreById(id: number): Promise<IItemGenre>;
    protected abstract executeAddRepositoryGenres(newItem: IItemGenre): Promise<IListItemsGenre>;
    protected abstract executeExistGenreInRepository(title: string): Promise<boolean>;
    protected abstract executeUpdateRepositoryGenres(updateItem: IItemGenre): Promise<IListItemsGenre>;
    protected abstract executeDeleteRepositoryGenres(id: number): Promise<IListItemsGenre>;
}

Definición de la clase MockWebApiCalls

La clase MockWebApiCalls ya se definió anteriormente como una clase estática. En este punto se va a redefinir la clase para que forme parte del patrón de diseño Factoría Abstracta, como uno de los últimos estabones de la arquitectura que se pretende realizar.

La funcionalidad de esta clase es la de albergar todas las funcionalidades de la gestión de los tipos de géneros de libros, pero como un Mock.

import { WebApiCalls } from './WebApiCalls';
import { IItemGenre } from './../Entities/IItemGenre';
import { IListItemsGenre } from './../Entities/IListItemsGenre';

/**
 * 
 */
export class MockWebApiCalls extends WebApiCalls {

    private listTypesOfBookGenres: IItemGenre[] = [];

    protected executeGetRepositoryGenres(): Promise<IListItemsGenre> {
        const ListGenres = ["Terror", "Romantics", "Thriller", "Fantastic", "Youth", "Historical", "Adventure", "Futurists"];
        let randomItem = this.getRandomInt(3, ListGenres.length);
        let list = null;
        let i = 0;
        list = [];
        while (i < randomItem) {
            let valueGenre = ListGenres[this.getRandomInt(0, ListGenres.length - 1)];
            if (list.findIndex((g: { Title: string; }) => g.Title === valueGenre) === -1) {
                i++;
                let newItem: IItemGenre = { Id: i, Title: valueGenre };
                list.push(newItem);
            }
        }
        this.listTypesOfBookGenres = list;
        return Promise.resolve(this.sortElements());
    }

    protected executeGetRepositoryGenreById(id: number): Promise<IItemGenre> {
        throw new Error("Method not implemented.");
    }
    protected executeAddRepositoryGenres(newItem: IItemGenre): Promise<IListItemsGenre> {
        throw new Error("Method not implemented.");
    }
    protected executeExistGenreInRepository(title: string): Promise<boolean> {
        throw new Error("Method not implemented.");
    }
    protected executeUpdateRepositoryGenres(updateItem: IItemGenre): Promise<IListItemsGenre> {
        throw new Error("Method not implemented.");
    }
    protected executeDeleteRepositoryGenres(id: number): Promise<IListItemsGenre> {
        throw new Error("Method not implemented.");
    }

    private getRandomInt(min: number, max: number) {
        return Math.floor(Math.random() * (max - min)) + min;
    }

    private sortElements(): IListItemsGenre {
        let result: IListItemsGenre = { value: this.listTypesOfBookGenres.sort((a, b) => a.Title.localeCompare(b.Title)) };
        return result;
    }
}

De la nueva definición de la clase MockWebApiCalls hay que destacar los siguientes aspectos:

  • Se ha definido una variable listTypesOfBookGenres que va a emular al repositorio que hay en SharePoint, ya que en el futuro hay que realizar operaciones como alta, baja y modificaciones.

  • El método GetRepositoryGenres se ha remplazado por el método executeGetRepositoryGenres, que es el que se va a encargar de generar los datos de muestra en el Mock.

    Cuando se usa el objeto MockWebApiCalls en el componente React ManagerTypesOfBookGenres, se va a seguir llamando al método público GetRepositoryGenres, pero la ejecutarse el código se realizará en el método executeGetRepositoryGenres. Esto es la magia del patrón de diseño Factoría Abstracta.

  • Los métodos privados getRandomInt y sortElements siguen cumpliendo su funcionalidad inicial, pero se han adaptados a la nueva definición de la clase.

Definición de la clase SPfxWebApiCalls

La clase SPfxWebApiCalls es la clase destinada comunicarse con los servicios REST de SharePoint online para la gestión de los tipos de géneros de libros.

Hay que informar que por ahora se va a definir la clase, y más adelante en la entrada se explicará cómo realizar las comunicaciones con SharePoint online.

import { WebApiCalls } from './WebApiCalls';
import { IItemGenre } from './../Entities/IItemGenre';
import { IListItemsGenre } from './../Entities/IListItemsGenre';

export class SPfxWebApiCalls extends WebApiCalls {

    protected executeGetRepositoryGenres(): Promise<IListItemsGenre> {
        throw new Error("Method not implemented.");
    }
    protected executeGetRepositoryGenreById(id: number): Promise<IItemGenre> {
        throw new Error("Method not implemented.");
    }
    protected executeAddRepositoryGenres(newItem: IItemGenre): Promise<IListItemsGenre> {
        throw new Error("Method not implemented.");
    }
    protected executeExistGenreInRepository(title: string): Promise<boolean> {
        throw new Error("Method not implemented.");
    }
    protected executeUpdateRepositoryGenres(updateItem: IItemGenre): Promise<IListItemsGenre> {
        throw new Error("Method not implemented.");
    }
    protected executeDeleteRepositoryGenres(id: number): Promise<IListItemsGenre> {
        throw new Error("Method not implemented.");
    }
}

Patrón de diseño Inyección de dependencias

He de informar que en realidad el patrón de diseño Inyección de dependencias, ya se había implementado con anterioridad en este ejercicio de los tipos de géneros de libros, cuando se definió la clase estática MockWebApiCalls. Ya que el componente React ManagerTypesOfBookGenres que se encarga de la lógica de negocio del componente SPfx, delegó la funcionalidad de obtención y gestión de los datos en manos de la clase MockWebApiCalls.

Hay que tener en cuenta que el concepto de una programación con inyección de dependencias no es más que en el momento de instanciar una clase o llamar a un método, pasarte un componente que realizar otra tarea diferente de la clase instanciada o la funciones ejecutada.

El ejemplo más fácil de entender en SharePoint es cuando a una clase o función destinada a realizar operativas sobre un repositorio de una lista, se le pasa un componente destinado a registrar en los logs de SharePoint, cualquier error producido durante la ejecución de un método.

Aplicar nuevos conceptos con lo desarrollado hasta la actualidad

Una vez implementado estos cambios de arquitectura en el componente SPfx, es necesario realizar unas ligeras modificaciones en el componente React ManagerTypesOfBookGenres para que todo siga funcionando igual que antes.

Módulos importados

Para poder aplicar los nuevos conceptos sobre los ya se dispone, hay que agregar los siguientes modulo.

// Import custom components and classes
import { IWebApiCalls } from "./../WebApi/IWebApiCalls";
import { SPfxWebApiCalls } from "./../WebApi/SPfxWebApiCalls";
import { IListItemsGenre } from './../Entities/IListItemsGenre';

// Import other components
import { Environment, EnvironmentType } from '@microsoft/sp-core-library';

El módulo @microsoft/sp-core-library nos va a permitir saber si en el momento de ejecutar el componente SPfx, si se está ejecutando en modo Local o si se está ejecutando en un entorno SharePoint online.

Método componentWillMount

Antes y ahora se van a continuar obtener los datos iniciales del componente SPfx en el método componentWillMount. Lo que pasa es que hay que realizar una serie de ajustes para funcionar con la nueva arquitectura.

public componentWillMount() {
    console.warn("componentWillMount - ManagerTypesOfBookGenres");
    let auxClassWebApiCalls: IWebApiCalls = null;
    if (Environment.type === EnvironmentType.Local) {
      auxClassWebApiCalls = new MockWebApiCalls();
    }
    else if (Environment.type == EnvironmentType.SharePoint ||
      Environment.type == EnvironmentType.ClassicSharePoint) {
      auxClassWebApiCalls = new SPfxWebApiCalls();
    }
    auxClassWebApiCalls.getRepositoryGenres().then((_response: IListItemsGenre) => {
      let auxOptimizedProcesses = this.state.optimizedProcesses;
      auxOptimizedProcesses.renderedItems = _response.value;
      this.setState({
        classWebApiCalls: auxClassWebApiCalls,
        optimizedProcesses: auxOptimizedProcesses
      });
    });

Antes era muy fácil, ya que se llamaba al método getRepositoryGenres y se guardaba la información en el componente state. Ahora se realizan más operativas, pero con la misma esencia que la versión anterior.

  1. Se ha definido un objeto del interfaz IWebApiCalls.

  2. Con el componente Environment se va a saber si la ejecución del componente SPfx, está sobre un entorno de SharePoint online, o por lo contrario se está ejecutando en el entorno de desarrollo.

    • En entorno local se crea el objeto de la clase MockWebApiCalls.

    • En entorno de SharePoint online se crea el objeto de la clase SPfxWebApiCalls.

  3. Como ambos objetos heredan el interfaz IWebApiCalls, ambos tienen el método público getRepositoryGenres, por lo que no hay que hacer distinción a la hora de invocar métodos, dependiendo del entorno de ejecución.

    Otra cosa es como se implemente los métodos para cada tipo de objeto, pero la función es la misma, la de obtener los datos del repositorio.

  4. Como se comentó anteriormente, ahora los métodos se van a ejecutar de forma asíncrona y la forma de saber cuando continuar con el proceso que se estaba ejecutando antes, una vez que el servicio de SharePoint online devuelve los datos, es a través del comando then.

    Dentro del comando then, lo que se hace es almacenar en el componente state, los resultados de la función getRepositoryGenres y el objeto definido que usa el interfaz IWebApiCalls.

Componente state

Con la nueva arquitectura establecida y lógica de negocio que se necesita para seguir mostrando la información como antes, también se ha visto afectada en menor medida el componente state del componente React ManagerTypesOfBookGenres.

constructor(props: any) {
    super(props);
    this.state = {
      classWebApiCalls: null,
      showPanel: false,
      panelNew: true,
      selectItem: null,
      optimizedProcesses: {
        renderedItems: []
      }
    };
    this._onItemInvoked = this._onItemInvoked.bind(this);
    this._onClickNewGenre = this._onClickNewGenre.bind(this);
    this._closePanel = this._closePanel.bind(this);
  }

Hay que destacar los siguientes aspectos del componente state:

  • La propiedad listItemsGenres se ha sustituido por la propiedad classWebApiCalls, ya que antes se almacenaban los resultados y ahora se va a almacenar el objeto de tipo IWebApiCalls que es el encargado de realizar la gestión con el repositorio de datos ya sea en local o conectándose con SharePoint online.

  • La propiedad optimizedProcesses que contendrá información de elementos que no varían mucho y de esta forma optimizar los procesos del componente SPfx. Hay que tener en cuenta que las acciones que se van a realizar en el componente SPfx son bajo demanda y no tiene que estar consultando en todo momento a SharePoint si hay información nuevos.

Método render

Al cambiar la propiedad listItemsGenres del componente state, se ha tenido que actualizar en el método render la forma de alimentar el control DetailsList de Office UI Fabric en la propiedad Items.

La configuración del control DetailsList quedará de la siguiente forma:

<DetailsList items={this.state.optimizedProcesses.renderedItems}
    columns={_columns}
    setKey="set"
    layoutMode={DetailsListLayoutMode.justified}
    onItemInvoked={this._onItemInvoked} />

Conectarse a la lista de tipo de géneros de libros

Con el componente SPfx comportándose como antes, pero aplicada la nueva arquitectura de componentes, se va a proceder a realizar la primera conectividad con los servicios REST de SharePoint online, para obtener el listado de tipos de géneros de libros que hay en la lista Genre de la colección de sitios.

Contextos de SharePoint online

Para poder realizar operativas con SharePoint online, es necesario disponer de los contextos spHttpClient y pageContext.

He de recordar que al definir el componente SPfx, se selección la opción React ante la pregunta Which framework would you like to use?. Al seleccionar esta opción, la forma con la que hay que acceder a estos contextos es diferente a los ejemplos que ofrece Microsoft.

He aquí los pasos que hay que realizar para disponer de esos contextos:

  1. Acceder a la definición de los props del componente React principal del componente SPfx. En este ejercicio el fichero es IManagerTypesOfBookGenresProps.ts.

  2. Definir en el interfaz las propiedades que se necesitan con su tipo de clase.

    import { SPHttpClient } from '@microsoft/sp-http';
    import { PageContext } from '@microsoft/sp-page-context';
    export interface IManagerTypesOfBookGenresProps {
        spHttpClient: SPHttpClient;
        pageContext: PageContext;
    }
    
  3. Acceder al componente de definición del WebPart, que en este ejercicio es el fichero ManagerTypesOfBookGenresWebPart.ts.

  4. En el método render se proporciona los contextos spHttpClient y pageContext al componente props de componente React principal.

    public render(): void {
        const element: React.ReactElement<IManagerTypesOfBookGenresProps> = React.createElement(
          ManagerTypesOfBookGenres,
          {
            spHttpClient: this.context.spHttpClient,
            pageContext: this.context.pageContext
          }
        );
    
        ReactDom.render(element, this.domElement);
    }
    

Con estos sencillos pasos, ya dispone de los elementos esenciales para implementar los métodos para conectarse con SharePoint online.

Configurar la clase SPfxWebApiCalls

Como se comentó anteriormente, la clase SPfxWebApiCalls es la encargada de realizar las comunicaciones con los servicios REST de SharePoint online. Por ello, es necesario realizar los ajustes pertinentes pasa su cometido:

  • Se ha implementado el constructor de la clase con dos parámetros de entrada, relacionados con los contextos spHttpClient y pageContext.

  • Estos parámetros se van a almacenar en variables globales de la clase, para su utilización en las comunicaciones con los servicios de SharePoint online.

  • Se implementa el método executeGetRepositoryGenres de la clase, para realizar la consulta sobre la lista Genre y obtener todos los tipos de géneros de libros.

    A la hora de implementar el método de obtención de tipos de géneros de libros, hay que recordar los siguientes aspectos:

    • Hay que saber dónde está la ubicado el repositorio de datos.

    • En las consultas REST de SharePoint a las listas, se realizan a través del título de la lista.

      En este ejercicio se ha dejado en el fichero de constantes, el titulo de la lista, para poder reutilizarlo tantas veces como sea necesario y para facilitar las políticas del cambio, por si el título de la lista cambiará en el futuro.

import { WebApiCalls } from './WebApiCalls';
import { IItemGenre } from './../Entities/IItemGenre';
import { IListItemsGenre } from './../Entities/IListItemsGenre';
import { Constants } from "../Constants";
import { SPHttpClient } from '@microsoft/sp-http';
import { PageContext } from '@microsoft/sp-page-context';

export class SPfxWebApiCalls extends WebApiCalls {

    private _spHttpClient: SPHttpClient;
    private _pageContext: PageContext;

    constructor(spHttpClient: SPHttpClient, pageContext: PageContext) {
        super();
        this._spHttpClient = spHttpClient;
        this._pageContext = pageContext;
    }

    protected async executeGetRepositoryGenres(): Promise<IListItemsGenre> {
        let requestUrl = this._pageContext.site.absoluteUrl.concat("/_api/web/Lists/GetByTitle('", Constants.Lists.ByName.Genres, "')/items?$select=Id,Title&$orderby=Title asc");
        const response = await this._spHttpClient.get(requestUrl, SPHttpClient.configurations.v1);
        return (response.status === 200 ? response.json() : null);
    }

    protected executeGetRepositoryGenreById(id: number): Promise<IItemGenre> {
        throw new Error("Method not implemented.");
    }

    protected executeAddRepositoryGenres(newItem: IItemGenre): Promise<IListItemsGenre> {
        throw new Error("Method not implemented.");
    }

    protected executeExistGenreInRepository(title: string): Promise<boolean> {
        throw new Error("Method not implemented.");
    }

    protected executeUpdateRepositoryGenres(updateItem: IItemGenre): Promise<IListItemsGenre> {
        throw new Error("Method not implemented.");
    }

    protected executeDeleteRepositoryGenres(id: number): Promise<IListItemsGenre> {
        throw new Error("Method not implemented.");
    }
}

Definición de constantes

Con la incorporación de la constante del título de lista al fichero Constants.tsx su definición queda de la siguiente manera:

export const Constants = {
    ControlId: {
        FieldTitle: "Title"
    },
    Lists: {
        ByName: {
            Genres: "Genres"
        }
    }
};

Método componentWillMount

Debido a las modificaciones realizadas en la clase SPfxWebApiCalls, en el método componentWillMount del componente React ManagerTypesOfBookGenres, hay que agregar los parámetros de los contextos que se necesitan para establecer las comunicaciones con los servicios de SharePoint online, al instanciar el objeto.

El código para instanciar un objeto de la clase SPfxWebApiCalls quedaría de la siguiente forma:

auxClassWebApiCalls = new SPfxWebApiCalls(this.props.spHttpClient, this.props.pageContext);

Ejecutar componente SPfx en SharePoint online

Hasta ahora cuando se ejecutaba el componente SPfx, siempre se realizada bajo un entorno de desarrollo que ofrece Gulp, pero fuera de los dominios de SharePoint online.

Ejemplo de la obtención de tipos de géneros de libros a través del Mock

Ahora que se ha implementado los mecanismos para comunicarse con los servicios de SharePoint online, ya se puede comprobar el comportamiento implementado en el componente SPfx, sobre las colecciones de sitios de desarrollo y producción del tenant.

La forma de comprobar los desarrollado hasta ahora, es la misma, pero cambiando la url donde se ubicará el componente SPfx.

https://[Tenant de SharePoint]/[Colección de sitios]/(Sub sitio web)/_layouts/15/workbench.aspx

En la colección de sitios de desarrollo, en la lista de tipo de géneros de libros, no disponen en este momento de ningún elemento definido, por eso en la imagen que se proporciona de ejemplo, no se muestra ningún elemento.

Obtención de los tipos de géneros de libros desde SharePoint online de desarrollo

En cambio, en la colección de sitios de producción, si que hay elementos definidos en la lista de tipos de géneros de libros, ya que, en anteriores entradas del blog, se ejecutó un script que aprovisionaba este repositorio.

Obtención de los tipos de géneros de libros desde SharePoint online de producción

Entradas populares de este blog

Cargar archivos desde PowerApps a bibliotecas de SharePoint

Menús desplegables relacionados en SharePoint Online

Gestionar excepciones en Power Automate