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

Comparison: Using Workflows vs. JavaScript vs. Plugins in Dynamics CRM?

  There are three ways to automate actions in Microsoft Dynamics CRM: workflows, JavaScript, or plugins. In this blog we will discuss the difference between them and how to choose which option is appropriate for your task. Workflows  can perform tasks such as updating data or sending email. They are triggered by saving records, creating records, or changing specific fields on a form, and once triggered, they run on their own in the background. As you can see in the example of  How to Assign a Territory to a Lead in Dynamics CRM , you can even look up data in another entity. JavaScript  runs on the screen while the user is using a form. JavaScript is triggered by events within the page, updating a field or saving, and it is commonly used to hide or show different fields on the forms. You can also, for instance,  Populate a CRM 2011 Lookup or PartyList Field Using JavaScript  by having a lookup automatically linked to the record based on what is entered in an...

Task Activity Timeline

  1. Overview The PCF Calendar Control is a custom PowerApps component that displays activities in a calendar-like view. It supports multiple views (monthly, weekly, yearly, daily), allows users to expand/collapse records for each date, and provides a scrollable interface for better usability. The control is built using TypeScript and CSS, adhering to best practices for type safety and maintainability. 2. Features View Modes: Monthly View : Groups activities by month. Weekly View : Groups activities by week. Yearly View : Groups activities by year. Daily View : Displays activities for individual days. Expand/Collapse Functionality: Users can click on a date to expand or collapse its associated records. Smooth animations enhance the user experience. Scrollable Container: A scrollable container ensures that large datasets are manageable. Responsive Design: The control adjusts its layout for smaller screens. Type Safety: The code uses TypeScript interfaces to avoid the use of any and...

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...