Skip to main content

Attachment PCF

Overview

The AttachmentControl component is a PowerApps Component Framework (PCF) control designed for handling file uploads. It supports multiple file uploads, drag-and-drop functionality, file previews, and base64 encoding for easy data handling.

Features

  • Supports multiple file uploads

  • Drag-and-drop functionality

  • File type and size validation

  • Base64 conversion for uploaded files

  • Preview support for images, PDFs, and text files

  • File removal functionality


Code Breakdown

Importing Dependencies

import { IInputs, IOutputs } from "./generated/ManifestTypes";

The component imports IInputs and IOutputs from the generated manifest file to define the control's input and output types.

Component Definition

export class AttachmentControl implements ComponentFramework.StandardControl<IInputs, IOutputs> {

Defines the AttachmentControl class, implementing the StandardControl interface from PCF.

Class Variables

private container: HTMLDivElement;
private fileInput: HTMLInputElement;
private previewContainer: HTMLDivElement;
private notifyOutputChanged: () => void;
private fileBase64List: { name: string; data: string }[] = []; // List of uploaded files (name + base64)

private readonly maxFileSizeMB: number = 5;
private readonly acceptedFileTypes: string[] = ["image/", "application/pdf", "text/"];
  • container: Holds the UI elements.

  • fileInput: Hidden file input for selecting files manually.

  • previewContainer: Displays uploaded file previews.

  • notifyOutputChanged: Callback function to notify PowerApps about data updates.

  • fileBase64List: Stores uploaded files with their names and base64-encoded content.

  • maxFileSizeMB: Defines the maximum allowed file size (5MB).

  • acceptedFileTypes: Specifies allowed file types (images, PDFs, and text files).

init Method

public init(
    context: ComponentFramework.Context<IInputs>,
    notifyOutputChanged: () => void,
    state: ComponentFramework.Dictionary,
    container: HTMLDivElement
): void {
    this.container = container;
    this.notifyOutputChanged = notifyOutputChanged;
    this.createUI();
}
  • Initializes the component.

  • Stores the container and notifyOutputChanged reference.

  • Calls createUI to render UI elements.

UI Creation

File Input (Hidden)

this.fileInput = document.createElement("input");
this.fileInput.type = "file";
this.fileInput.accept = this.acceptedFileTypes.join(",");
this.fileInput.style.display = "none";
this.fileInput.multiple = true;
this.fileInput.onchange = this.handleFileUpload.bind(this);
  • Creates a hidden <input> element for file selection.

  • Supports multiple files.

  • Triggers handleFileUpload when files are selected.

Upload Icon

const uploadIcon = this.createUploadIcon();
uploadIcon.onclick = () => this.fileInput.click();
  • Creates an upload button that triggers the file input on click.

Drag-and-Drop Area

const dragDropArea = this.createDragDropArea();
  • Initializes the drag-and-drop file upload area.

Preview Container

this.previewContainer = document.createElement("div");
this.previewContainer.style.border = "1px solid #ddd";
this.previewContainer.style.padding = "10px";
this.previewContainer.style.marginTop = "10px";
this.previewContainer.textContent = "No files uploaded.";
  • Creates a container to display uploaded files.

Handling File Uploads

handleFileUpload

private handleFileUpload(event: Event): void {
    const files = (event.target as HTMLInputElement).files;
    if (files) {
        Array.from(files).forEach((file) => this.processFile(file));
    }
}
  • Retrieves selected files and processes each one.

processFile

private processFile(file: File): void {
    if (!this.validateFile(file)) {
        return;
    }

    const reader = new FileReader();
    reader.onload = () => {
        const fileData = reader.result as string;
        this.fileBase64List.push({ name: file.name, data: fileData });
        this.notifyOutputChanged();
        this.displayPreviews();
    };
    reader.readAsDataURL(file);
}
  • Validates file type and size.

  • Reads the file and converts it to base64.

  • Adds file to fileBase64List.

  • Updates the UI.

File Validation

private validateFile(file: File): boolean {
    const maxSizeBytes = this.maxFileSizeMB * 1024 * 1024;
    if (file.size > maxSizeBytes) {
        alert(`File "${file.name}" exceeds the ${this.maxFileSizeMB} MB size limit.`);
        return false;
    }

    if (!this.acceptedFileTypes.some((type) => file.type.startsWith(type))) {
        alert(`Unsupported file type for "${file.name}".`);
        return false;
    }
    return true;
}
  • Ensures the file does not exceed the size limit.

  • Checks that the file type is supported.

Displaying Previews

private displayPreviews(): void {
    this.previewContainer.innerHTML = "";

    if (this.fileBase64List.length === 0) {
        this.previewContainer.textContent = "No files uploaded.";
        return;
    }

    this.fileBase64List.forEach((file, index) => {
        const fileContainer = document.createElement("div");
        fileContainer.style.marginBottom = "10px";

        const fileLabel = document.createElement("p");
        fileLabel.textContent = `File ${index + 1}: ${file.name}`;
        fileContainer.appendChild(fileLabel);

        if (file.data.startsWith("data:image/")) {
            const img = document.createElement("img");
            img.src = file.data;
            img.style.maxWidth = "100%";
            fileContainer.appendChild(img);
        }
        this.previewContainer.appendChild(fileContainer);
    });
}
  • Clears previous previews.

  • Displays uploaded files with appropriate previews (images, text, PDF previews).

Removing Files

private removeFile(index: number): void {
    this.fileBase64List.splice(index, 1);
    this.notifyOutputChanged();
    this.displayPreviews();
}
  • Removes a file from the list.

  • Updates the UI.

Output Handling

public getOutputs(): IOutputs {
    return { uploadedFile: JSON.stringify(this.fileBase64List) };
}
  • Returns the list of uploaded files as a JSON string.

Cleanup

public destroy(): void {
    // Cleanup if necessary
}
  • Placeholder for cleanup logic.

I have attached Images  of Pcf Control

Conclusion

This AttachmentControl PCF component provides a robust file upload solution with UI enhancements, validation, and base64 conversion. It is well-suited for PowerApps applications requiring file handling capabilities.

Comments

Popular posts from this blog

Contacts View PCF Control

  1. Overview The ContactsControl component is a custom PowerApps control that displays a searchable and sortable table of contact records. It provides an interactive UI for filtering and selecting records. 2. Functionalities Search Feature: Allows users to filter records by entering text. Sorting: Clickable column headers enable ascending/descending sorting. Record Selection: Users can select a record to trigger a modal alert. Dynamic Rendering: Updates view dynamically based on search and sort input. Custom Styling: Uses external CSS for styling. 3. Component Structure Main Container ( HTMLDivElement ) : Holds the search bar and table. Search Input ( HTMLInputElement ) : Enables real-time search. Table ( HTMLTableElement ) : Displays the records with sortable headers. Modal Alert ( HTMLDivElement ) : Displays selected record details. 4. Implementation Details 4.1 Initialization ( init Method) Sets up the main container. Loads external styles. Creates...

Trigger JavaScript on Click of Button PCF Control

  Overview The TriggerJavascript control is a custom PCF (PowerApps Component Framework) control that renders a button with customizable label, icon, and on-click script execution. The control allows users to dynamically trigger JavaScript code upon clicking the button. Dependencies IInputs, IOutputs from ./generated/ManifestTypes (Auto-generated types from PowerApps) CSS styling from ./CSS/TriggerJavascript.css Class: TriggerJavascript This class implements ComponentFramework.StandardControl<IInputs, IOutputs> and manages rendering a button inside a container, dynamically executing JavaScript code on button click. Properties Private Properties _container: HTMLDivElement - A reference to the container element where the button will be rendered. Methods constructor() Initializes a new instance of the TriggerJavascript control. init(context: ComponentFramework.Context<IInputs>, notifyOutputChanged: () => void, state: ComponentFramework.Dictionary, container: HTMLD...