Introduzione alla creazione di un componente di codice

Completato

Power Apps fornisce numerose funzionalità predefinite per la creazione di app, tuttavia a volte è necessario creare esperienze utente personalizzate per gestire esigenze specifiche quali la sostituzione di un valore percentuale con un misuratore, il rendering di un codice a barre invece di un ID o la sostituzione dei controlli esistenti con controlli dotati di più funzionalità, come una visualizzazione a griglia con trascinamento della selezione. È inoltre possibile includere i componenti già creati in altri framework Web, come React o Angular, in Power Apps Component Framework.

La creazione di questi componenti consente di usare l'intero ecosistema moderno di sviluppo Web, ovvero le librerie, i framework e altri strumenti con cui probabilmente si ha già familiarità e di includere queste capacità in un formato che permetta ai creatori di sviluppare app con il codice, come se si trattasse di una parte predefinita della piattaforma.

I componenti personalizzati di Power Apps sono spesso indicati come componenti di codice perché è necessario codice personalizzato per crearli. Sono costituiti da tre elementi: un manifesto, un'implementazione e le risorse.

Nell'esercizio seguente si creerà un componente di codice personalizzato per gestire uno scenario per l'azienda. L'azienda desidera che alcuni campi del modulo nell'applicazione siano di sola lettura finché l'utente non inserisce manualmente una modifica sul valore dei dati. Il team ha rilevato che nessuno dei controlli predefiniti è adatto a questo scopo, quindi ha chiesto di creare un componente di codice personalizzato.

Per rispondere a questa esigenza, si creerà un componente personalizzato di campo modificabile simile all'immagine seguente. Il valore sarà di sola lettura finché l'utente non selezionerà Modifica.

Screenshot del componente di codice personalizzato

Questo componente attenderà le modifiche provenienti dall'app host e consentirà all'utente di apportare modifiche che verranno quindi inviate all'app host. Per creare questo componente, attenersi alla procedura descritta di seguito.

Installazione di Power Platform CLI

Per preparare il computer alla creazione di componenti di codice, effettuare i seguenti passaggi:

  1. Installare Node.js (fornito con npm). È consigliabile usare una versione LTS (supporto a lungo termine), ad esempio quella disponibile qui. Si consiglia di verificare di non avere già installato Node/NPM. Per farlo, andare al prompt dei comandi e digitare quanto segue:

    // Launch a standard command prompt and type both of the following
    
    npm --version
    Node --version
    

    Se viene visualizzato un errore durante l'esecuzione di questi comandi, sarà necessario installare Node.js usando i collegamenti riportati in precedenza.

    Un'installazione corretta di Node restituirà i numeri di versione nella finestra dei comandi quando si immettono i comandi sopra come mostrato di seguito:

    // If installed properly you will see something like the output below. The version numbers may be slightly different based on the version installed.
    
    C:\npm --version
    10.5.0
    
    C:\Node --version
    v20.12.2
    
  2. Installare Visual Studio Code.

  3. Installare l'estensione Power Platform Tools. Assicurarsi di aver completato l'installazione di Visual Studio Code prima di installare Power Platform Tools.

    Power Platform Tools non permetteranno l'esecuzione di comandi CLI per Power Platform in un prompt dei comandi al di fuori di Visual Studio Code. Si consiglia di installare anche CLI MSI per PowerPlatform.

    Per installare la CLI a livello di Windows, seguire queste istruzioni. È possibile installare contemporaneamente la CLI e l'estensione Power Platform Tools.

Creazione di un nuovo progetto di componente

Prima di avviare la creazione dei componenti, verificare che i componenti installati elencati in precedenza funzionino correttamente. I comandi NPM e CLI funzioneranno da una finestra di terminale in Visual Studio Code. In caso di problemi con la corretta esecuzione da VS Code, è possibile scegliere di eseguire i comandi del terminale forniti nei passaggi seguenti in un prompt dei comandi se è stata installata la CLI per Power Platform.

In Visual Studio Code, selezionare Terminale > Nuovo terminale (oppure premere CTRL+MAIUSC+`). Nella finestra di terminale in VS Code, ripetere le istruzioni npm e Node version. Se vengono restituiti i numeri di versione corretti, è possibile procedere alla creazione della soluzione.

// Test installs from Steps 1-3 listed above

// This will verify NPM installation
C:\npm --version
10.5.0

// This will verify Node installation
C:\Node --version
v20.12.2

// This will launch Visual Studio Code from the command line.
C:\Code

Ora che si è pronti per creare un nuovo progetto di componente, seguire questi passaggi per iniziare:

Creare una directory in cui sviluppare il componente. In questo esempio si inserirà il componente in C:\source\Editable-pcf. Per creare la propria directory, usare Visual Studio Code. In alternativa, è possibile creare le cartelle usando il prompt dei comandi in caso di problemi con l'utilizzo del terminale VS Code.

  1. Avviare Visual Studio Code.

  2. Selezionare Nuovo terminale dal menu Terminale.

    Screenshot che mostra la selezione del nuovo terminale in Visual Studio Code.

  3. La sessione di terminale verrà impostata automaticamente sull'ultima cartella usata. Ciò verrà illustrato nell'area del prompt dei comandi TERMINAL come illustrato di seguito:

    //Note Your PS will not list exactly what is seen below, but will be specific to your starting path.
    
    PS C:\Users\Name\Folder
    

    Modificare la directory impostando il percorso in cui si desidera creare questa soluzione. È possibile usare il comando CD per spostarsi in un percorso appropriato.

    Nota

    Tenere presente che la cartella in cui si esegue NPM o altri comandi è importante. Assicurarsi sempre di essere nella cartella Projects prima di eseguire i comandi di compilazione. In caso contrario, la compilazione può risultare danneggiata e rendere difficile ottenere risultati ottimali.

    Per creare una nuova cartella nel percorso predefinito, usare md (make directory) come mostrato di seguito nella finestra di terminale VS Code.

    md source
    cd source
    

    Verrà creata una directory denominata source alla quale si potrà accedere mediante il comando cd (change directory).

  4. A partire dalla directory source creata, creare una directory denominata editable-pcf. Questa sarà la directory PROJECT in cui verranno archiviati tutti i file di progetto. Si procederà quindi a modificare la directory impostando la directory Project.

    md editable-pcf
    cd editable-pcf
    

    Screenshot che mostra il terminale con i comandi per creare e cambiare la directory.

  5. Inizializzare il progetto del componente usando l'interfaccia della riga di comando di Power Platform con il seguente comando:

    pac pcf init --namespace SampleNamespace --name EditablePCF --template field
    

    L'immagine seguente mostra un esempio dell'output che deve essere visualizzato.

    Screenshot che mostra il terminale con il comando pcf init.

    Attenzione

    Se il comando PAC PCF INIT non verrà eseguito in una finestra di terminale in VS Code e la CLI di Power Platform è installata, è possibile scegliere di eseguire un prompt dei comandi e il comando CD per passare alla directory editable-pcf. Una volta avuto accesso alla directory, è possibile immettere il comando nel prompt dei comandi e questo funzionerà correttamente. L'output dovrebbe essere uguale a quello elencato sopra.

  6. Installare gli strumenti di compilazione del progetto usando il comando npm install. Potrebbero essere visualizzati alcuni avvisi che è possibile ignorare. Assicurarsi di essere nella directory PROJECT prima di eseguire questo comando.

    npm install
    

    Attenzione

    Se il comando npm install non verrà eseguito in una finestra di terminale in VS Code e la CLI di Power Platform è installata, è possibile scegliere di eseguire un prompt dei comandi e il comando CD per passare alla directory editable-pcf . Una volta avuto accesso alla directory, è possibile immettere il comando nel prompt dei comandi e questo funzionerà correttamente.

    È possibile verificare che tutto funzioni eseguendo un comando DIR nella finestra di terminale in VS Code o nel prompt dei comandi se si è scelto di eseguire la compilazione al di fuori di Visual Studio Code. Nella directory editable-pcf dovrebbe essere visualizzata una serie di file e cartelle. Questo è il progetto creato nei passaggi precedenti di cui eseguiremo la compilazione mediante VS Code.

  7. Eseguire il comando seguente per aprire il progetto Visual Studio Code o, se si sta usando un prompt dei comandi, nella finestra del prompt dei comandi. Il progetto creato in VS Code dovrebbe così avviarsi.

    code -a .
    
  8. Il contenuto del progetto dovrebbe essere simile a quello nell'immagine riportata di seguito.

    Screenshot che mostra i file di progetto.

Aggiornamento del manifesto del componente di codice

Aggiornare il file manifesto in modo che corrisponda esattamente al controllo.

  1. Espandere la cartella EditablePCF e aprire il file ControlManifest.Input.xml.

    Screenshot che mostra il file XML di input del manifesto del controllo.

  2. Cambiare la versione in 1.0.0 e description-key in Nome progetto modifiche.

    Screenshot che mostra le modifiche apportate al controllo.

  3. Individuare il nodo proprietà.

  4. Cambiare il valore del nome impostandolo su Name, la chiave del nome visualizzato impostandola su Name e la chiave di descrizione impostandola su A name.

    Screenshot che mostra le modifiche apportate al nodo property.

  5. Individuare il nodo risorse.

  6. Includere un riferimento a un file CSS denominato editable-pcf.css che si creerà nei passaggi di seguito.

    <css path="css/EditablePCF.css" order="1" />
    

    Screenshot che mostra le modifiche apportate al nodo risorse.

  7. Salvare le modifiche selezionando File e poi Salva oppure premere CTRL+S per salvare il file.

Aggiunta di stili al componente di codice

Per aggiungere stili al componente di codice, effettuare i seguenti passaggi:

  1. Assicurarsi che il file ControlManifest.Input.xml sia ancora selezionato, quindi selezionare Nuova cartella.

    Screenshot che mostra il pulsante Nuova cartella.

  2. Assegnare alla nuova cartella il nome css.

  3. Selezionare la cartella css creata e quindi Nuovo file.

  4. Assegnare al nuovo file il nome EditablePCF.css (o come altrimenti è stato denominato il file css nel passaggio 6 precedente).

  5. Aprire il nuovo file EditablePCF.css creato e incollare il seguente frammento CSS. Questo è il nome di riferimento della risorsa usato in precedenza quando si è aggiunto il codice del percorso CSS al file manifesto.

    .SampleNamespace\.HelloPCF {
          font-size: 1.5em;
        }
    
  6. Il contenuto del file CSS dovrebbe essere simile a quello mostrato nell'immagine riportata di seguito.

    Screenshot che mostra il contenuto del file CSS.

  7. Selezionare File e poi Salva oppure CTRL+S per salvare il file.

Compilazione del componente di codice

Prima di implementare la logica del componente, è necessario eseguire una compilazione per il componente. In questo modo si garantisce che vengano generati i tipi TypeScript corretti, corrispondenti alle proprietà nel documento ControlManifest.xml.

Tornare al terminale in VS Code e compilare il progetto usando il comando seguente. Se per qualsiasi motivo si riscontrano dei problemi nell'uso del terminale in Visual Studio Code è possibile accedere alla cartella usando il prompt dei comandi ed eseguendo il comando da lì.

Attenzione

Assicurarsi di essere nella cartella PROJECT del terminale prima di eseguire questo comando.

npm run build

Il componente viene compilato nella directory out/controls/EditablePCF. Gli artefatti di compilazione includono:

  • Cartella css

  • bundle.js: il codice sorgente del componente aggregato

  • ControlManifest.xml: il file manifesto effettivo del componente che viene caricato nell'organizzazione Microsoft Dataverse

    Screenshot che mostra il contenuto della cartella out.

Avviso

L'errore più comune che di solito si riceve qui è un errore di battitura nel nome del file CSS creato in precedenza. Se si verifica questo problema, è sufficiente rinominare i file di conseguenza ed eseguire nuovamente il comando npm run build fino al completamento senza errori. Controllare la sezione RESOURCE nel file COntrolManifest.Input.xml a fronte del file creato nella cartella CSS. Devono corrispondere al 100%.

Implementazione della logica del componente di codice

Per implementare la logica del componente di codice, seguire questi passaggi una volta completata la compilazione dai passaggi precedenti. In Visual Studio Code, in EXPLORER cercare un file denominato index.ts. È qui che inizieremo a scrivere il codice per il nostro componente.

  1. Aprire il file index.ts in Visual Studio Code.

  2. Sopra il metodo constructor inserire le seguenti variabili private:

    // The PCF context object\
    private context: ComponentFramework.Context<IInputs>;
    // The wrapper div element for the component\
    private container: HTMLDivElement;
    // The callback function to call whenever your code has made a change to a bound or output property\
    private notifyOutputChanged: () => void;
    // Flag to track if the component is in edit mode or not\
    private isEditMode: boolean;
    // Tracking variable for the name property\
    private name: string | null;
    
  3. Individuare il metodo public init e sostituirlo con il metodo seguente.

    public init(context: ComponentFramework.Context<IInputs>, notifyOutputChanged: () => void, state: ComponentFramework.Dictionary, container: HTMLDivElement) {
    
        // Track all the things
        this.context = context;
        this.notifyOutputChanged = notifyOutputChanged;
        this.container = container;
        this.isEditMode = false;
    
        // Create the span element to hold the project name
        const message = document.createElement("span");
        message.innerText = `Project name ${this.isEditMode ? "" :context.parameters.Name.raw}`;
    
        // Create the textbox to edit the name
        const text = document.createElement("input");
        text.type = "text";
        text.style.display = this.isEditMode ? "block" : "none";
    
        if (context.parameters.Name.raw) {
            text.value = context.parameters.Name.raw;
            // Wrap the two above elements in a div to box out the content
            const messageContainer = document.createElement("div");
            messageContainer.appendChild(message);
            messageContainer.appendChild(text);
    
            // Create the button element to switch between edit and read modes
    
            const button = document.createElement("button");
            button.textContent = this.isEditMode ? "Save" : "Edit";
            button.addEventListener("click", () => { this.buttonClick(); });
    
            // Add the message container and button to the overall control container
            this.container.appendChild(messageContainer);
            this.container.appendChild(button);
        }
    
    }
    

    Avviso

    Si potrebbe notare che EventListener per buttonClick è sottolineato in rosso. Non c'è motivo di preoccuparsi, si creerà il metodo per quell'evento di seguito. Se si notano altre sezioni in rosso, verificare che tutto sia stato copiato o inserito correttamente.

  4. Aggiungere il metodo del gestore selezioni pulsante. Aggiungere il metodo riportato di seguito al metodo init.

    public buttonClick() {
        // Get our controls via DOM queries
        const text = this.container.querySelector("input")!;
        const message = this.container.querySelector("span")!;
        const button = this.container.querySelector("button")!;
    
        // If not in edit mode, copy the current name value to the textbox
        if (!this.isEditMode) {
            text.value = this.name ?? "";
        } 
        else if (text.value != this.name) {
            // if in edit mode, copy the textbox value to name and call the notify callback
            this.name = text.value;
            this.notifyOutputChanged();
        }
    
        // flip the mode flag
        this.isEditMode = !this.isEditMode;
    
        // Set up the new output based on changes
        message.innerText = `Project name ${this.isEditMode ? "" : this.name}`;
        text.style.display = this.isEditMode ? "inline" : "none";
        text.value = this.name ?? "";
        button.textContent = this.isEditMode ? "Save" : "Edit";
    }
    
  5. Individuare il metodo updateView e sostituirlo con il metodo riportato di seguito.

    public updateView(context: ComponentFramework.Context<IInputs>): void {
    
    // Checks for updates coming in from outside
    
    this.name = context.parameters.Name.raw;
    const message = this.container.querySelector("span")!;
    message.innerText = `Project name ${this.name}`;
    }
    
  6. Individuare il metodo getOutputs e sostituirlo con il metodo riportato di seguito.

    public getOutputs(): IOutputs {
    return {
    // If our name variable is null, return undefined instead
    Name: this.name ?? undefined
    };
    }
    
  7. Individuare il metodo destroy e sostituirlo con il metodo riportato di seguito.

    public destroy() {
    // Remove the event listener we created in init
    this.container.querySelector("button")!.removeEventListener("click", this.buttonClick);
    }
    
  8. Index.ts finale dovrebbe avere un aspetto simile al codice di seguito:

    import { IInputs, IOutputs } from "./generated/ManifestTypes";
    
    export class EditablePCF implements ComponentFramework.StandardControl<IInputs, IOutputs> {
    
        /**
        * Empty constructor.
        */
    
        // The PCF context object\
        private context: ComponentFramework.Context<IInputs>;
        // The wrapper div element for the component\
        private container: HTMLDivElement;
        // The callback function to call whenever your code has made a change to a bound or output property\
        private notifyOutputChanged: () => void;
        // Flag to track if the component is in edit mode or not\
        private isEditMode: boolean;
        // Tracking variable for the name property\
        private name: string | null;
    
        constructor()
        {
    
        }
    
        /**
        * Used to initialize the control instance. Controls can kick off remote server calls and other initialization actions here.
        * Data-set values are not initialized here, use updateView.
        * @param context The entire property bag available to control via Context Object; It contains values as set up by the customizer mapped to property names defined in the manifest, as well as utility functions.
        * @param notifyOutputChanged A callback method to alert the framework that the control has new outputs ready to be retrieved asynchronously.
        * @param state A piece of data that persists in one session for a single user. Can be set at any point in a controls life cycle by calling 'setControlState' in the Mode interface.
        * @param container If a control is marked control-type='standard', it will receive an empty div element within which it can render its content.
        */
        public init(context: ComponentFramework.Context<IInputs>, notifyOutputChanged: () => void, state: ComponentFramework.Dictionary, container: HTMLDivElement) {
    
            // Track all the things
            this.context = context;
            this.notifyOutputChanged = notifyOutputChanged;
            this.container = container;
            this.isEditMode = false;
    
            // Create the span element to hold the project name
    
            const message = document.createElement("span");
            message.innerText = `Project name ${this.isEditMode ? "" :context.parameters.Name.raw}`;
    
            // Create the textbox to edit the name
            const text = document.createElement("input");
            text.type = "text";
            text.style.display = this.isEditMode ? "block" : "none";
    
            if (context.parameters.Name.raw) {
                text.value = context.parameters.Name.raw;
                // Wrap the two above elements in a div to box out the content
                const messageContainer = document.createElement("div");
                messageContainer.appendChild(message);
                messageContainer.appendChild(text);
    
                // Create the button element to switch between edit and read modes
    
                const button = document.createElement("button");
                button.textContent = this.isEditMode ? "Save" : "Edit";
                button.addEventListener("click", () => { this.buttonClick(); });
    
                // Add the message container and button to the overall control container
                this.container.appendChild(messageContainer);
                this.container.appendChild(button);
            }
    
        }
    
        public buttonClick() {
            // Get our controls via DOM queries
    
            const text = this.container.querySelector("input")!;
            const message = this.container.querySelector("span")!;
            const button = this.container.querySelector("button")!;
    
            // If not in edit mode, copy the current name value to the textbox
    
            if (!this.isEditMode) {
                text.value = this.name ?? "";
            } 
            else if (text.value != this.name) {
    
                // if in edit mode, copy the textbox value to name and call the notify callback
                this.name = text.value;
                this.notifyOutputChanged();
            }
    
            // flip the mode flag
            this.isEditMode = !this.isEditMode;
    
            // Set up the new output based on changes
            message.innerText = `Project name ${this.isEditMode ? "" : this.name}`;
            text.style.display = this.isEditMode ? "inline" : "none";
            text.value = this.name ?? "";
            button.textContent = this.isEditMode ? "Save" : "Edit";
        }
    
        /**
        * Called when any value in the property bag has changed. This includes field values, data-sets, global values such as container height and width, offline status, control metadata values such as label, visible, etc.
        * @param context The entire property bag available to control via Context Object; It contains values as set up by the customizer mapped to names defined in the manifest, as well as utility functions
        */
        public updateView(context: ComponentFramework.Context<IInputs>): void {
    
            // Checks for updates coming in from outside
            this.name = context.parameters.Name.raw;
            const message = this.container.querySelector("span")!;
            message.innerText = `Project name ${this.name}`;
        }
    
        /**
        * It is called by the framework prior to a control receiving new data.
        * @returns an object based on nomenclature defined in manifest, expecting object[s] for property marked as "bound" or "output"
        */
        public getOutputs(): IOutputs {
            return {
            // If our name variable is null, return undefined instead
            Name: this.name ?? undefined
            };
        }
    
        /**
        * Called when the control is to be removed from the DOM tree. Controls should use this call for cleanup.
        * i.e. cancelling any pending remote calls, removing listeners, etc.
        */
        public destroy() {
            // Remove the event listener we created in init
            this.container.querySelector("button")!.removeEventListener("click", this.buttonClick);
        }
    }
    

Ricompilazione ed esecuzione del componente di codice

Per ricompilare ed eseguire il componente di codice, effettuare i seguenti passaggi:

  1. Ora che la logica del componente è implementata, tornare al terminale e ricompilarlo usando il comando riportato di seguito. È possibile eseguirlo direttamente in VS Code o tramite il prompt dei comandi purché si acceda prima alla cartella editable-pcf.

    npm run build
    
  2. La build dovrebbe venire completata correttamente.

    Screenshot che mostra il risultato della compilazione.

  3. Eseguire il componente nel test harness di Node usando il comando riportato di seguito. Se questa operazione non è già stata eseguita manualmente in precedenza, si dovrebbe avviare un browser con visualizzato il componente appena creato.

    npm start
    

    Nota

    È inoltre possibile abilitare la modalità di controllo per assicurarsi che le modifiche alle risorse seguenti vengano apportate automaticamente senza dover riavviare il test harness con il comando npm start watch.

    • File index.ts

    • File ControlManifest.Input.xml

    • Raccolte importate in index.ts

    • Tutte le risorse elencate nel file manifesto

  4. Una nuova finestra del browser dovrebbe caricare il test harness, (la finestra dovrebbe aprirsi automaticamente, ma è possibile fare riferimento anche all'indirizzo presente nella finestra di comando).

  5. Selezionare Modifica.

    Screenshot che mostra il pulsante Modifica nel test harness.

  6. Immettere Progetto uno e selezionare Salva.

  7. È possibile modificare le dimensioni del contenitore.

  8. Il test harness deve essere simile a quello mostrato nell'immagine riportata di seguito.

    Screenshot che mostra il controllo all'interno del test harness.

  9. Chiudere la finestra del browser del test harness.

  10. Tornare al terminale o al prompt dei comandi (se non si sta usando il terminale VS Code) e arrestare il watcher tenendo premuto [CONTROL] + C.

  11. Digitare Y, quindi premere [INVIO].