Introdução à criação de um componente de código
O Power Apps fornece inúmeras funcionalidades integradas para que os criadores de aplicativos criem seus aplicativos, mas, às vezes, você precisará criar experiências de usuário personalizadas para atender a seus requisitos exclusivos. Os exemplos podem ser a substituição de um valor percentual por um medidor, a renderização de um código de barras em vez de uma ID ou a substituição de controles existentes por outros com mais funcionalidades, como uma exibição de grade do tipo "arrastar e soltar". Você também pode envolver o Power Apps component framework em torno de componentes existentes escritos em outras estruturas da Web, como React ou Angular.
A criação desses componentes permite usar toda a amplitude do ecossistema moderno de desenvolvimento para a Web: as bibliotecas, as estruturas e outras ferramentas que podem ser familiares, e reunir esses recursos em um formato que permita aos criadores de aplicativos criar aplicativos usando o seu código como se fosse parte da plataforma.
Observação
Outros componentes de exemplo, inclusive aqueles que usam Angular ou React, estão disponíveis.
Os componentes personalizados do Power Apps são frequentemente chamados de componentes de código, pois exigem código personalizado para criá-los. Consistem em três elementos: um manifesto, uma implementação e recursos.
No exercício a seguir, você criará um componente de código personalizado para lidar com um cenário para sua empresa. Sua empresa gostaria que alguns campos do formulário do aplicativo fossem somente leitura até que o usuário iniciasse manualmente uma edição no valor dos dados. A equipe identificou que nenhum dos controles integrados funcionará, então, solicitaram que você criasse um componente de código personalizado.
Para resolver esse requisito, você criará um componente personalizado de campo editável semelhante à imagem a seguir. O valor será somente leitura até que o usuário selecione editar.
Este componente escutará as alterações provenientes do aplicativo host e permitirá ao usuário fazer alterações que são enviadas por push para o aplicativo host. As etapas a seguir ajudarão você a criar esse componente.
Instalar o Power Platform CLI
Para preparar seu computador para compilar componentes de código, execute estas etapas:
Instale o Node.js (fornecido com o npm). Recomendamos que você use uma versão de LTS (Suporte de Longo Prazo) como esta localizada aqui. Convém verificar se o Node/NPM já não está instalado. Você pode fazer isso acessando um prompt de comando e digitando o seguinte:
// Launch a standard command prompt and type both of the following npm --version Node --version
Se receber um erro ao executar esses comandos, você precisará instalar o Node.js usando os links acima.
Uma instalação bem-sucedida do nó retornará os números de versão na janela de comando quando você inserir os comandos acima, conforme visto abaixo:
// 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
Instalar o Visual Studio Code.
Instale a extensão Power Platform Tools. Verifique se você concluiu a instalação do Visual Studio Code antes de instalar o Power Platform Tools.
O Power Platform Tools não permitirá que você execute comandos da CLI para o Power Platform em um prompt de comando fora do Visual Studio Code. É recomendável instalar também a CLI MSI para PowerPlatform.
Para instalar a CLI no nível do Windows, siga estas instruções. Você pode ter a CLI e a extensão Power Platform Tools instaladas simultaneamente.
Criar um novo projeto de componente
Antes de iniciar a compilação dos componentes, verifique se os componentes instalados listados acima estão funcionando corretamente. Os comandos NPM e CLI funcionarão em uma Janela de Terminal no Visual Studio Code. Se tiver problemas para executá-los corretamente no VS Code, você poderá optar por executar os comandos do Terminal fornecidos nas etapas abaixo em um Prompt de Comando, se tiver instalado a CLI para o Power Platform.
No Visual Studio Code, navegue até Terminal > Novo Terminal (ou pressione CTRL+SHFT+`). Na janela Terminal no VS Code, repita as instruções de versão do npm e do Node. Se tudo retornar números de versão adequados, você poderá prosseguir com a criação da solução.
// 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
Agora que você está pronto para criar um novo projeto de componente, siga estas etapas para começar:
Crie um diretório no qual você criará seu componente. Neste exemplo, você colocará o componente em C:\source\Editable-pcf. Para criar seu próprio diretório, você usará o Visual Studio Code. Como alternativa, você poderá criar as pastas usando o prompt de comando, se tiver problemas com o uso do Terminal do VS Code.
Inicie o Visual Studio Code.
Selecione Terminal e, depois, Novo Terminal.
Por padrão, sua sessão do Terminal será a última pasta que você usou. Isso será ilustrado na área do prompt de comando de TERMINAL, conforme ilustrado abaixo:
//Note Your PS will not list exactly what is seen below, but will be specific to your starting path. PS C:\Users\Name\Folder
Mude o diretório para um local em que você deseja criar essa solução. Você pode usar o comando CD para navegar até um local apropriado.
Observação
Lembre-se de que a pasta em que você executa o NPM ou outros comandos é importante. Sempre verifique se você está na pasta Projects antes de executar comandos de compilação. Se isso não for feito, a compilação poderá ser corrompida, e poderá haver problemas na produção de resultados ideais.
Para criar uma nova pasta no local padrão, use md (make directory), conforme mostrado abaixo na Janela do Terminal do VS Code.
md source cd source
Isso criará um diretório chamado source e levará você a esse diretório usando o comando cd (change directory).
No diretório source criado, crie um diretório chamado editable-pcf. Esse será o diretório PROJECT em que todos os arquivos do projeto serão armazenados. Também mudaremos o diretório para nosso novo diretório Project.
md editable-pcf cd editable-pcf
Inicialize o projeto de componente usando a Power Platform CLI com o seguinte comando:
pac pcf init --namespace SampleNamespace --name EditablePCF --template field
A imagem a seguir mostra um exemplo da saída que deve ser exibida.
Cuidado
Se o comando PAC PCF INIT não for executado em uma janela de terminal no VS Code e você tiver instalado a Power Platform CLI, poderá optar por executar um prompt de comando e CD em seu diretório editable-pcf. Quando estiver lá, você poderá inserir o comando no Prompt de Comando, e ele funcionará corretamente. Você deverá ver a mesma saída listada acima.
Instale as ferramentas de compilação de projeto usando o comando
npm install
. Alguns avisos podem ser exibidos; no entanto, você pode ignorá-los. Verifique se você está no diretório PROJECT antes de emitir esse comando.npm install
Cuidado
Se a instalação do npm não for executada em uma janela de terminal no VS Code e você tiver instalado a Power Platform CLI, poderá optar por executar um prompt de comando e CD em seu diretório editable-pcf. Quando estiver lá, você poderá inserir o comando no Prompt de Comando, e ele funcionará corretamente.
Você pode verificar se tudo está funcionando executando um comando DIR na Janela do Terminal no VS Code ou no Prompt de Comando, se tiver optado por criar fora do Visual Studio Code. Você deverá ver uma série de arquivos e pastas em seu diretório editable-pcf. Esse é o projeto que você criou nas etapas acima e que compilaremos usando o VS Code.
Execute o comando abaixo para abrir o projeto no Visual Studio Code ou se estiver usando um prompt de comando na janela do prompt de comando. Isso deve iniciar seu projeto criado no VS Code.
code -a .
O conteúdo do projeto deve ser semelhante à imagem abaixo.
Atualizar o manifesto do componente de código
Atualize o arquivo de manifesto para representar seu controle com precisão.
Expanda a pasta Editable-pcf e abra o arquivo ControlManifest.Input.xml.
Altere a versão para 1.0.0 e description-key para Editar o nome do projeto.
Localize o nó property.
Altere name value para Nome, display-name-key para Nome e description-key para Um nome.
Localize o nó resources.
Inclua uma referência a um arquivo CSS chamado editable-pcf.css que você criará nas etapas abaixo.
<css path="css/EditablePCF.css" order="1" />
Salve suas alterações selecionando Arquivo e Salvar ou pressione CTRL+S para salvar o arquivo.
Adicionar estilo ao seu componente de código
Para adicionar estilo ao seu componente de código, siga estas etapas:
Verifique se você ainda tem o arquivo ControlManifest.Input.xml selecionado e selecione Nova Pasta.
Nomeie a nova pasta como css.
Selecione a pasta css que você criou e, depois, Novo Arquivo.
Nomeie o novo arquivo como EditablePCF.css (ou o nome que você deu ao arquivo css na Etapa 6 acima).
Abra o novo arquivo EditablePCF.css que você criou e cole o trecho de CSS a seguir. Esse é o nome de referência do Recurso que você usou anteriormente quando adicionou o código do caminho css ao arquivo de manifesto.
.SampleNamespace\.HelloPCF { font-size: 1.5em; }
Agora, o conteúdo do arquivo CSS deve ser semelhante à imagem abaixo.
Selecione Arquivo e Salvar ou pressione CTRL+S para salvar o arquivo.
Compilar seu componente de código
Antes de poder implementar a lógica do componente, você precisará compilar seu componente. Isso garante que os tipos corretos de TypeScript sejam gerados para corresponder às propriedades do documento ControlManifest.xml.
Volte para o terminal no VS Code e crie seu projeto usando o comando a seguir. Se, por algum motivo, você tiver problemas ao usar o Terminal no Visual Studio Code, poderá navegar até a pasta usando o prompt de comando e executar o comando nela.
Cuidado
Verifique se você está na pasta PROJECT em seu terminal antes de emitir esse comando.
npm run build
O componente é compilado no diretório out/controls/EditablePCF. Os artefatos de compilação incluem:
pasta css
bundle.js: código-fonte do componente agrupado
ControlManifest.xml: arquivo de manifesto do componente real que é carregado para a organização do Microsoft Dataverse
Aviso
O erro mais comum geralmente recebido aqui é um erro de digitação no nome do arquivo CSS que você criou anteriormente. Se isso acontecer, simplesmente renomeie os arquivos de maneira adequada e execute novamente o comando npm run build até que ele seja executado até a conclusão sem erros. Verifique sua seção RECURSO no arquivo COntrolManifest.Input.xml com o arquivo criado na pasta CSS. Eles devem ser 100% correspondentes.
Implementar a lógica do seu componente de código
Para implementar a lógica do componente de código, siga estas etapas quando a compilação for concluída após as etapas acima. No Visual Studio Code, no EXPLORER, procure um arquivo chamado index.ts. É aí que começaremos a escrever o código do componente.
Abra o arquivo index.ts no Visual Studio Code.
Acima do método constructor, insira as seguintes variáveis particulares:
// 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;
Localize o método init público e substitua-o pelo método abaixo.
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); } }
Aviso
Você pode notar que o EventListener de buttonClick está sublinhado em vermelho. Não se preocupe: criaremos o método para esse evento abaixo. Se você vir outras seções em vermelho, verifique se tudo foi copiado ou inserido corretamente.
Adicione o método de manipulador de seleção de botão. Adicione o método a seguir abaixo do método 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"; }
Localize o método updateView e substitua-o pelo método abaixo.
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}`; }
Localize o getOutputs que será substituído pelo método abaixo.
public getOutputs(): IOutputs { return { // If our name variable is null, return undefined instead Name: this.name ?? undefined }; }
Localize o método destroy e substitua-o pelo método abaixo.
public destroy() { // Remove the event listener we created in init this.container.querySelector("button")!.removeEventListener("click", this.buttonClick); }
Seu Index.ts final agora deve ser semelhante ao código abaixo:
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); } }
Recompilar e executar o componente de código
Para recompilar e executar o componente de código, siga estas etapas:
Agora que a lógica do componente está implementada, volte ao terminal e recrie-o usando o comando abaixo. Você pode executar isso diretamente no VS Code ou por meio do prompt de comando, desde que navegue primeiro até a pasta editable-pcf.
npm run build
A compilação deve ser bem-sucedida.
Execute o componente no agente de teste do Node executando o comando abaixo. Se ainda não tiver feito isso, você deverá iniciar um navegador com o componente recém-criado exibido.
npm start
Observação
Você também pode habilitar o modo de inspeção para garantir que qualquer alteração nos ativos a seguir seja feita automaticamente sem ter que reiniciar o agente de teste usando o comando
npm start watch
.Arquivo index.ts.
Arquivo ControlManifest.Input.xml
Bibliotecas importadas em index.ts
Todos os recursos listados no arquivo de manifesto
Uma nova janela do navegador deve carregar o Agente de teste. (A janela deve ser aberta automaticamente, mas você também pode fazer referência ao endereço encontrado na janela de comando.)
Selecione Editar.
Entre no Projeto Um e selecione Salvar.
Você pode alterar o tamanho do contêiner.
Agora o agente de teste deve ser semelhante à imagem abaixo.
Feche a janela do navegador do agente de teste.
Volte para o terminal ou prompt de comando (se você não estiver usando o VS Code Terminal) e pare o observador mantendo pressionadas as teclas [CONTROL] + C.
Digite Y e [ENTER].