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.
- 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
npm install powerpagestoolkit
A powerful class for managing DOM elements with automatic value synchronization and event handling.
DOMNodeReferences are instantiated with the help of the following factory function: createRef
createRef(
target: HTMLElement | string,
options: {
multiple: (() => boolean) | boolean = false,
root: HTMLElement,
timeout: number
}
): Promise<DOMNodeReference | DOMNodeReference[]>;
createRef takes two main arguments:
Property | Type | Details |
---|---|---|
target |
|
Use standard querySelector syntax to target an element, or elements in the DOM, or pass in an instance of the element itself to create a reference.
|
options |
|
Provides advanced configurations for niche scenarios, such as async DOM element loading, returning arrays of elements, or specifying the parent to search within for the target node. |
Import the utility function for creating DOMNodeReference(s)
import { createRef } from "powerpagestoolkit";
Instantiate one, or multiple instances of a DOMNodeReference, and optionally configure advanced options
// Create a single reference
const node = await createRef("#myElement");
// Create multiple references
const nodes = await createRef(".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 targeted is not available at the initial execution
// of the script, set a timeout for 2 seconds
const node2 = await createRef("#target", { timeout: 2000 });
// need to target a node within a specific node? use that node as the root
const otherElement = document.getElementById("id");
const node3 = await createRef("#target", { root: otherElement });
// implement all options:
const nodes2 = await createRef("#target", {
multiple: true,
timeout: 4000,
root: otherElement,
});
Property | Type | Description |
---|---|---|
element | HTMLElement | The referenced DOM element |
value | any | Current synchronized value of the element |
isLoaded | boolean | Element load status |
target | HTMLElement | string | Original target selector or element |
yesRadio | DOMNodeReference | null | Reference to 'yes' radio (for boolean fields) |
noRadio | DOMNodeReference | null | Reference to 'no' radio (for boolean fields) |
checked | boolean | Checkbox/radio checked state |
// 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");
});
...
// Basic visibility
node.hide();
node.show();
Advanced conditional rendering
Out of the box, Microsoft does not provide PowerPages developers the ability to hide or show fields or form elements based on the value of another field. This method allows such configurations
Method signature:
configureConditionalRendering(
condition: () => boolean,
dependencies?: DOMNodeReference[],
clearValuesOnHide: boolean = true
): DOMNodeReference /* Instance of this returned
for optional method chaining */
Example implementation:
node.configureConditionalRendering(
function () // Function to evaluate wether this node should be visible or not
{
return otherNode.value === "some value";
},
[otherNode] /* Dependency array | if the values or visibility of these
change, the function is re-evaluated */,
true /* should the values in the targeted elements (this.element)
be cleared if this node is hidden? Default = true */
);
This utility enhances PowerPages forms by adding dynamic field validation and conditional requirements based on other field values.
Method signature:
configureValidationAndRequirements(
isRequired: () => boolean,
isValid: () => boolean,
fieldDisplayName: string,
dependencies: DOMNodeReference[]
): DOMNodeReference; /* instance of this is returned for optional
method chaining */
Example implementation:
node.configureValidationAndRequirements(
// Make field required only when "Yes" is checked
() => dependentNode.yesRadio?.checked ?? false,
// Basic validation: ensure field isn't empty
function () {
return this.value != null && this.value !== "";
},
"Contact Phone", // Shows in error message: "Contact Phone is required"
[dependentNode] // Revalidate when dependentNode changes
);
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 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 { createRef } from "powerpagestoolkit";
const title = await createRef("#myTitle");
title.addTooltip("This is an Example of a tooltip!", { color: "red" });
Perform secure API calls to DataVerse from your PowerPages site. This method implements the shell deferred token to send requests with __RequestVerificationToken
await API.createRecord("accounts", {
name: "Gypsum LLC",
type: "Vendor",
})
.then((recordId) => {
console.log("Created record:", recordId);
})
.catch((error) => {
console.error("Creation failed:", error);
});
// 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'
);
await API.updateRecord("contacts", "record-guid", {
name: "Jane Smith",
email: "[email protected]",
});
- Always await DOMNodeReference creation:
const node = await createRef("#element");
- Include all referenced nodes in dependency arrays:
node.configureConditionalRendering(
() => dependentNode.value === "test",
[dependentNode] // Required!
);
-
Use TypeScript for better type safety and IntelliSense support.
-
Use proper error handling with API operations:
/* optionally await */ API.createRecord(/*...*/)
.then((recordId) => {})
.catch((error) => {
// handle your errors appropriately
});
The package includes full TypeScript definitions and type safety. Use TypeScript for the best development experience and catch potential errors at compile time.
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.
This project is licensed under the AGPL-3.0 License - see the LICENSE file for details.
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