3.0.4063 • Published 10 months ago

powerpagestoolkit v3.0.4063

Weekly downloads
-
License
AGPL-3.0-only
Repository
github
Last release
10 months ago

PowerPages Tool Kit

A TypeScript/JavaScript utility package for seamless DOM manipulation and DataVerse API interactions in PowerPages applications. This toolkit provides robust DOM element management and standardized DataVerse CRUD operations with full TypeScript support.

Features

  • Powerful DOM element manipulation and reference management
  • Type-safe DataVerse API operations
  • Automatic value synchronization for form elements
  • Advanced conditional rendering and validation
  • Radio button and checkbox handling
  • Event management with proper TypeScript typing
  • Mutation observer integration for dynamic content
  • Tooltip and label management utilities

Installation

npm install powerpagestoolkit

Core Modules

PowerPagesElement

A powerful class for managing DOM elements with automatic value synchronization and event handling.

Basic Usage

PowerPagesElements are instantiated with the help of the following factory function: get

get(
  target: HTMLElement | string,
  options: {
    multiple: (() => boolean) | boolean = false,
    root: HTMLElement,
    timeoutMs:number
  }
): Promise<PowerPagesElement | PowerPagesElement[]>;

get takes two main arguments:

Import the utility function for creating PowerPagesElement(s)

import { get } from "powerpagestoolkit";

Instantiate one, or multiple instances of a PowerPagesElement, and optionally configure advanced options

// Create a single reference (i.e. 'querySelector')
const node = await get("#myElement");

// Create multiple references (i.e. 'querySelectorAll')
const nodes = await get(".my-class", { multiple: true });

/******************/
// ADVANCED OPTIONS
// in the event that you need to be more granular with how you are targeting
// and retrieving elements, there are additional options

// If the node you are targeting is not available at the initial execution
// of the script, set a timeout for 2 seconds
const node2 = await get("#target", { timeoutMs: 2000 });

// need to target a node within a specific node? use that node as the root
const otherElement = document.getElementById("id");
const node3 = await get("#target", { root: otherElement });

// implement all options:
const nodes2 = await get("#target", {
  multiple: true,
  timeoutMs: 4000,
  root: otherElement,
});

Properties

PropertyTypeDescription
elementHTMLElementThe referenced DOM element
valueanyCurrent synchronized value of the element
isLoadedbooleanElement load status
targetHTMLElement | stringOriginal target selector or element
yesRadioRadio | nullReference to 'yes' radio (for yes/no fields)
noRadioRadio | nullReference to 'no' radio (for yes/no fields)
checkedbooleanCheckbox/radio checked state

Key Methods

Event Handling
// Add event listener with proper 'this' context
// uses standard eventListener API, and so supports all DOM events
node.on("change", function (e) {
  console.log("Current value:", this.value);
});

node.on("click", function (e) {
  console.log(this, " has been clicked");
});

...
Business Rule Application

This utility provides a flexible way to dynamically control field visibility, requirement status, values, and enabled states based on dependencies within PowerPages forms.

Method Signature:

applyBusinessRule(
  rule: BusinessRule,
  dependencies: PowerPagesElement[]
): PowerPagesElement; /* Instance of this is returned for optional
 method chaining */

BusinessRule Definition

interface BusinessRule {
  setVisibility?: () => boolean;
  setRequirements?: () => {
    isRequired: () => boolean;
    isValid: () => boolean;
  };
  setValue?: () => {
    condition: () => boolean;
    value: () => any | any;
  };
  setDisabled?: () => boolean;
}
Visibility Control
// Show the 'taxIdField' only when
// 'businessTypeField' is set to 'Corporation' or 'LLC'
taxIdField.applyBusinessRule(
  {
    setVisibility: () =>
      businessTypeField.value === "Corporation" ||
      businessTypeField.value === "LLC",
  },
  [businessTypeField] // Re-evaluate when businessTypeField changes
);
Validation and Requirements
// Require 'taxIdField' when 'businessTypeField' is 'Corporation' or 'LLC'
taxIdField.applyBusinessRule(
  {
    setRequirements: () => ({
      isRequired: function () {
        return (
          businessTypeField.value === "Corporation" ||
          businessTypeField.value === "LLC"
        );
      },
      isValid: function () {
        return this.value != null && this.value !== "";
      },
    }),
  },
  [businessTypeField] // Revalidate when businessTypeField changes
);
Setting Field Values Conditionally
// Set default industry value when 'businessTypeField' is 'Corporation'
industryField.applyBusinessRule(
  {
    setValue: () => ({
      condition: () => businessTypeField.value === "Corporation",
      value: "Corporate",
    }),
  },
  [businessTypeField] // Apply value when businessTypeField changes
);
Enabling and Disabling Fields
// Disable 'taxIdField' when 'businessTypeField' is 'Individual'
taxIdField.applyBusinessRule(
  {
    setDisabled: () => businessTypeField.value === "Individual",
  },
  [businessTypeField] // Enable/disable when businessTypeField changes
);
Element Manipulation

Value management

// set a static value
node.setValue("new value");

// or set a value by using some sort of logic
node.setValue(() => {
  if (true) {
    return "value";
  } else return "default";
});

// Sync with DOM
node.updateValue();

// Clear the value for both the instance and the target element
node.clearValue();

Content manipulation

node.setInnerHTML("<span>New content</span>");
node.append(childElement);
node.prepend(headerElement);
node.after(siblingElement);
node.before(labelElement);

Styling

node.setStyle({
  display: "block",
  color: "red",
});

Enabling/Disabling inputs

node.disable();
node.enable();
Label and Tooltip Management
// LABEL AND INFO OPERATIONS
const label = node.getLabel();
// appends a tooltip to the label associated with the element targeted by 'this'
node.addLabelTooltip(
  "Helper text",
  /* Optionally pass in css styles to customize the tooltip icon*/
  { color: "orange", fontSize: "30px" }
);
// appends a tooltip directly to the element targeted by 'this'
node.addTooltip(
  "Inline helper",
  /* Optionally pass in css styles to customize the tooltip icon*/
  { color: "orange", fontSize: "30px" }
);

Example:

import { get } from "powerpagestoolkit";

const title = await get("#myTitle");

title.addTooltip("This is an Example of a tooltip!", { color: "red" });

Example

Here's an improved markdown documentation with more comprehensive details:

BindForm Method

The bindForm method simplifies form element management in DataVerse by providing a semantic and efficient way to access form controls, sections, and tabs.

Key Features
  • Retrieves form definition directly from DataVerse
  • Automatically generates references for:
    • Controls
    • Sections
    • Tabs
Element Types
Element TypeDescriptionAccessibility
controlIncludes all form fields and sub-gridsAccessed via logical name
sectionStandard PowerApps form sectionsAccessed via logical name
tabForm tabs corresponding to PowerApps layoutAccessed via logical name
Usage Example
import { bindForm } from "powerpagestoolkit";

// Basic form binding
bindForm("form-guid").then((form) => {
  // Access elements by their logical name
  const nameField = form["name"];

  // execute custom methods
  nameField.applyBusinessRule(
    {
      setVisibility: [() => someNode.value === "desired value"],
    },
    [someNode]
  );

  // Or executes methods immediately upon accessing
  form["phonenumber"].addTooltip("Example tooltip text");
});
Method Signature
/**
 * Binds a form by its GUID and returns a collection of form elements
 * @param formGuid Unique identifier for the form
 * @returns Promise resolving to form element references
 */
function bindForm(formGuid: string): Promise<PowerPagesElementArray & Record<string: PowerPagesElement>>;
Benefits
  • Reduces code complexity
  • Improves readability
  • Provides type-safe access to form elements
  • Supports flexible form interactions
Best Practices
  • Use logical names consistently
  • Handle async nature of form binding
  • Leverage TypeScript for enhanced type checking
Error Handling

Ensure proper error handling for form binding:

bindForm("form-guid")
  .then((form) => {
    // Form processing
  })
  .catch((error) => {
    console.error("Form binding failed", error);
  });

DataVerse API

Perform secure API calls to DataVerse from your PowerPages site. This method implements the shell deferred token to send requests with __RequestVerificationToken

Create Records

await API.createRecord("accounts", {
  name: "Gypsum LLC",
  type: "Vendor",
})
  .then((recordId) => {
    console.log("Created record:", recordId);
  })
  .catch((error) => {
    console.error("Creation failed:", error);
  });

Get Records

// Single record
const record = await API.getRecord(
  "accounts",
  "record-guid",
  "select=name,accountnumber"
);

// Multiple records
const records = await API.getMultiple(
  "contacts",
  '$filter=firstname eq "Jane"&$select=firstname,lastname'
);

Update Record

await API.updateRecord("contacts", "record-guid", {
  name: "Jane Smith",
  email: "jane@example.com",
});

Best Practices

  1. Always await PowerPagesElement creation:
const node = await get("#element");
  1. Include all referenced nodes in dependency arrays:
node.configureConditionalRendering(
  () => dependentNode.value === "test",
  [dependentNode] // Required!
);
  1. Use TypeScript for better type safety and IntelliSense support.

  2. Use proper error handling with API operations:

/* optionally await */ API.createRecord(/*...*/)
  .then((recordId) => {})
  .catch((error) => {
    // handle your errors appropriately
  });

TypeScript Support

The package includes full TypeScript definitions and type safety. Use TypeScript for the best development experience and catch potential errors at compile time.

Contributing

Contributions are welcome, feel free to create a pull request with enhancements. Please include an explanation of the changes made. All pull requests will be reviewed by the project owner.

License

This project is licensed under the AGPL-3.0 License - see the LICENSE file for details.

Funding

If you like this project, found it useful, or would like to help support the long-term support of this package, please feel free to contribute via GitHub Sponsors: Keaton-Brewster

2.221.12

1 year ago

3.0.4054

10 months ago

3.0.4055

10 months ago

2.5.303

1 year ago

3.0.4056

10 months ago

2.4.113

1 year ago

3.0.4057

10 months ago

2.7.135

11 months ago

3.0.4051

10 months ago

3.0.4052

10 months ago

3.0.4053

10 months ago

2.4.1

1 year ago

3.0.402

10 months ago

3.0.401

10 months ago

3.0.404

10 months ago

2.221.1101

1 year ago

3.0.403

10 months ago

2.7.1420

11 months ago

2.3.201

1 year ago

2.7.1422

11 months ago

2.0.1

1 year ago

2.0.0

1 year ago

2.5.4111

12 months ago

2.7.121-2.1

11 months ago

2.7.121-2.2

11 months ago

3.0.4041

10 months ago

2.7.131

11 months ago

2.7.132

11 months ago

2.7.133

11 months ago

2.7.134

11 months ago

2.6.3101

12 months ago

1.3.502

1 year ago

2.7.1414

11 months ago

1.3.501

1 year ago

1.3.104

1 year ago

1.3.103

1 year ago

2.3.311

1 year ago

2.7.1411

11 months ago

2.8.0-1.4

11 months ago

2.8.211

11 months ago

2.8.212

11 months ago

2.201.1

1 year ago

2.0.109

1 year ago

2.3.0

1 year ago

2.7.121

11 months ago

2.7.0

11 months ago

2.6.3212

12 months ago

2.3.4

1 year ago

2.6.3213

12 months ago

2.7.2

11 months ago

2.7.1

11 months ago

2.0.112

1 year ago

2.0.111

1 year ago

2.7.1443

11 months ago

2.0.110

1 year ago

2.801.4

11 months ago

2.3.101

1 year ago

2.7.1441

11 months ago

2.8.2

11 months ago

3.0.4061

10 months ago

2.7.102

11 months ago

3.0.4062

10 months ago

3.0.4063

10 months ago

2.7.104

11 months ago

2.7.111

11 months ago

2.6.3201

12 months ago

2.7.1436

11 months ago

2.6.3323

12 months ago

2.7.1437

11 months ago

2.6.3325

12 months ago

2.7.1311

11 months ago

2.6.3327

12 months ago

2.7.1433

11 months ago

2.8.311

11 months ago

3.0.3201

10 months ago

2.6.33311

12 months ago

2.7.213

11 months ago

3.0.320

10 months ago

2.2.0

1 year ago

2.7.101

11 months ago

2.6.3310

12 months ago

1.3.2041

1 year ago

2.6.3311

12 months ago

2.6.1

12 months ago

2.6.3312

12 months ago

2.6.3313

12 months ago

2.6.3

12 months ago

2.6.2

12 months ago

3.0.3

11 months ago

3.0.2

11 months ago

3.0.1

11 months ago

2.701.213

11 months ago

3.0.0

11 months ago

2.7.202

11 months ago

2.0.108

1 year ago

2.0.107

1 year ago

2.0.106

1 year ago

3.0.311

10 months ago

2.7.211

11 months ago

2.0.105

1 year ago

2.0.104

1 year ago

1.3.304

1 year ago

3.0.313

10 months ago

2.0.103

1 year ago

1.3.303

1 year ago

2.0.102

1 year ago

1.3.3001

1 year ago

2.0.101

1 year ago

2.7.1211

11 months ago

2.5.409

12 months ago

2.5.401

1 year ago

2.5.402

1 year ago

2.5.403

1 year ago

1.3.5

1 year ago

2.5.404

1 year ago

1.3.4

1 year ago

2.5.405

12 months ago

1.3.2

1 year ago

2.1.2

1 year ago

2.1.1

1 year ago

2.5.0

1 year ago

2.7.1402

11 months ago

2.5.2

1 year ago

2.7.1403

11 months ago

2.5.1

1 year ago

2.5.411

12 months ago

2.8.105

11 months ago

2.7.1401

11 months ago

2.8.101

11 months ago

3.0.3215

10 months ago

2.5.4213

12 months ago

3.0.3216

10 months ago

2.5.4212

12 months ago

3.0.3211

10 months ago

3.0.3213

10 months ago

2.5.4211

12 months ago

3.0.3214

10 months ago

2.211.1

1 year ago

2.701.4

11 months ago

2.6.4

11 months ago

2.701.3

11 months ago

1.3.201

1 year ago

1.3.204

1 year ago

1.3.1041

1 year ago

1.3.203

1 year ago

2.5.301

1 year ago

1.3.202

1 year ago

1.3.0

1 year ago

1.3.102

1 year ago

1.3.101

1 year ago

1.2.202

1 year ago

1.2.2

1 year ago

1.2.1

1 year ago

1.2.0

1 year ago

1.1.301

1 year ago

1.1.3

1 year ago

1.1.2901

1 year ago

1.1.29

1 year ago

1.1.28

1 year ago

1.1.27

1 year ago

1.1.26

1 year ago

1.1.25

1 year ago

1.1.24

1 year ago

1.1.23

1 year ago

1.1.22

1 year ago

1.1.2

1 year ago

1.1.1

1 year ago

1.0.304

1 year ago

1.0.303

1 year ago

1.0.302

1 year ago

1.0.301

1 year ago

1.0.300

1 year ago

1.0.2301

1 year ago

1.0.2201

1 year ago

1.0.22

1 year ago

1.0.21

1 year ago

1.0.20

1 year ago

1.0.14

1 year ago

1.0.13

1 year ago

1.0.12

1 year ago

1.0.11

1 year ago

1.0.0

1 year ago