Thursday, December 19, 2024

Example of Advanced UI customization in PowerApps, using custom HTML, CSS, and JavaScript

PowerApps Canvas Apps Customization

PowerApps Canvas Apps allow limited customization directly with HTML, CSS, and JavaScript. However, you can use HTML Text Controls, integrate PowerApps Portals for advanced customization, or use Power Automate with Azure Functions for JavaScript-like logic. Here's an example of advanced UI customization using HTML web resources in a PowerApps Canvas App:

Scenario

Create a responsive and visually appealing data table with Search/Filtering Functionality using advanced HTML and CSS styling embedded in a PowerApps Canvas App.

Steps to Implement

1. Design Your HTML/CSS Web Resource

Create an HTML file with embedded CSS for a styled table. Save it as a web resource in your Dataverse environment.

Example HTML (HTML File):

<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
    body {
      font-family: Arial, sans-serif;
      margin: 0;
      padding: 0;
    }

    .custom-table-container {
      margin: 20px;
      overflow-x: auto; /* Enables horizontal scrolling on smaller screens */
    }

    .search-container {
      margin: 10px 20px;
      text-align: right;
    }

    .search-input {
      width: 100%;
      max-width: 300px;
      padding: 10px;
      border: 1px solid #ddd;
      border-radius: 5px;
      font-size: 16px;
    }

    .custom-table {
      width: 100%;
      border-collapse: collapse;
      margin: 20px 0;
    }

    .custom-table th,
    .custom-table td {
      border: 1px solid #ddd;
      padding: 10px;
      text-align: left;
    }

    .custom-table th {
      background-color: #0078D7;
      color: white;
    }

    .custom-table tr:nth-child(even) {
      background-color: #f2f2f2;
    }

    .custom-table tr:hover {
      background-color: #ddd;
    }

    /* Responsive Styles */
    @media (max-width: 768px) {
      .custom-table th,
      .custom-table td {
        font-size: 14px;
        padding: 8px;
      }
    }

    @media (max-width: 480px) {
      .custom-table th,
      .custom-table td {
        font-size: 12px;
        padding: 6px;
      }

      .custom-table-container {
        margin: 10px;
      }
    }

    @media (max-width: 320px) {
      .custom-table th,
      .custom-table td {
        font-size: 10px;
        padding: 4px;
      }
    }
  </style>
</head>
<body>
  <div class="search-container">
    <input
      type="text"
      id="searchInput"
      class="search-input"
      placeholder="Search the table..."
      onkeyup="filterTable()"
    />
  </div>

  <div class="custom-table-container">
    <table class="custom-table" id="dataTable">
      <thead>
        <tr>
          <th>ID</th>
          <th>Name</th>
          <th>Value</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>1</td>
          <td>John Doe</td>
          <td>100</td>
        </tr>
        <tr>
          <td>2</td>
          <td>Jane Smith</td>
          <td>200</td>
        </tr>
        <tr>
          <td>3</td>
          <td>Sam Wilson</td>
          <td>150</td>
        </tr>
        <tr>
          <td>4</td>
          <td>Sara Connor</td>
          <td>180</td>
        </tr>
      </tbody>
    </table>
  </div>

  <script>
    function filterTable() {
      // Get the input field and its value
      const input = document.getElementById("searchInput");
      const filter = input.value.toUpperCase();

      // Get the table and rows
      const table = document.getElementById("dataTable");
      const rows = table.getElementsByTagName("tr");

      // Loop through all rows (skip the header row)
      for (let i = 1; i < rows.length; i++) {
        const row = rows[i];
        let isVisible = false;

        // Check each cell in the row
        const cells = row.getElementsByTagName("td");
        for (let j = 0; j < cells.length; j++) {
          const cell = cells[j];
          if (cell) {
            const text = cell.textContent || cell.innerText;
            if (text.toUpperCase().indexOf(filter) > -1) {
              isVisible = true;
              break;
            }
          }
        }

        // Show or hide the row based on the match
        row.style.display = isVisible ? "" : "none";
      }
    }
  </script>
</body>
</html>

2. Add a JavaScript File for Dynamic Data

Create a JavaScript file that injects data dynamically into the table.


function populateTable(data) {
  const tableBody = document.getElementById("data-table").querySelector("tbody");
  tableBody.innerHTML = ""; // Clear existing rows

  data.forEach(row => {
    const tr = document.createElement("tr");
    Object.values(row).forEach(value => {
      const td = document.createElement("td");
      td.textContent = value;
      tr.appendChild(td);
    });
    tableBody.appendChild(tr);
  });
}

3. Host the HTML/JS Resources

  • Upload the HTML and JavaScript files as web resources in Dataverse.
  • Copy the URLs of the hosted files.

4. Embed HTML in PowerApps

  1. Add an HTML Text Control in your Canvas App.

  2. Embed the URL of your hosted HTML file inside the control.

    Example for the HTMLText property:

    "<iframe src='https://<your-hosted-html-file-url>' width='100%' height='400px' frameborder='0'></iframe>"

5. Pass Data from PowerApps to HTML

To dynamically populate the table:

  1. Add a Power Automate Flow or use an API to pass the data to your web resource.
  2. For example, use the following pattern in your Canvas App:

    Set(dataPayload, JSON(DataSource));
    HtmlTextControl.HtmlText = 
        "<script>" & "populateTable(" & dataPayload & ");" & "</script>";

Key Features

  • Table columns dynamically.
  • Case-insensitive search.
  • Responsive layout for both the search bar and table.

Thanks for visiting!

No comments:

Post a Comment

Power Automate Optimization: Filter Rows vs Trigger Conditions - When and Why to Use Each

Filter Rows vs Trigger Conditions in Power Automate Filter Rows vs Trigger Conditions in Power Automate Why your flow...