Creating Components with Third-Party Libraries

Learn how to create self-contained, reusable custom components that integrate third-party JavaScript libraries like FullCalendar, Leaflet maps, Chart.js, and more.


Overview

BetterForms custom components can integrate any JavaScript library using lifecycle hooks. This guide shows you how to:

  • βœ… Load external libraries on-demand

  • βœ… Initialize libraries with DOM elements

  • βœ… Properly clean up when components are removed

  • βœ… Create fully self-contained, shareable components


Prerequisites

  • Basic understanding of JSON

  • Familiarity with the BetterForms Component Editor

  • Knowledge of the third-party library you want to integrate


Component Lifecycle Hooks

Custom components support lifecycle hooks for managing loading, initialization, and cleanup:

Available Hooks

Hook
When it Fires
Use For

onBeforeMount

Before component renders (blocks rendering)

Loading external libraries, fetching data

onMount

After component renders to DOM

Initializing libraries, accessing DOM elements

onUpdated

After component data changes

Updating library instances

onBeforeDestroy

Before component is removed

Cleanup, destroying library instances

onDestroyed

After component is removed

Final cleanup

Execution Order


Complete Example: FullCalendar Component

This example demonstrates all key patterns for integrating a third-party library.

Step 1: Component Structure

Step 2: Load the Library (onBeforeMount)

Why onBeforeMount?

  • Component waits for library to load before rendering

  • Prevents "FullCalendar is not defined" errors

  • BF.libraryLoadOnce() deduplicates - safe to use in multiple components

Step 3: Initialize the Library (onMount)

Key Patterns:

  1. Access DOM with document.getElementById()

  2. Always check if element exists

  3. Store API reference globally

  4. Access model data

Step 4: Add Cleanup (onBeforeDestroy)

Why cleanup is important:

  • Prevents memory leaks

  • Stops event listeners

  • Clears intervals/timeouts

  • Frees resources

Step 5: Add Custom Actions (Optional)

This action can be called from buttons or other components:


Complete Working Component

Here's the full JSON you can copy and use:


Using the Component on a Page

Add to your page schema:

Providing Event Data

Set model.calendarEvents in your page data model:

Adding Navigation Buttons


Common Patterns

Pattern 1: Simple Library (No DOM Access)

For libraries that don't need DOM elements (like Lodash, Moment.js):

Pattern 2: Library Needing DOM Access

For libraries that render to a DOM element (FullCalendar, Chart.js, Leaflet):

Pattern 3: Singleton Initialization

When registering Vue components or global objects (only initialize once):


Important: DOM Access in namedActions

❌ What DOESN'T Work

βœ… What DOES Work

Best Practice: Use id Attributes

Always add id attributes to elements you need to access in lifecycle hooks:


Another Example: Chart.js Component


Finding CDN URLs for Libraries

Most JavaScript libraries provide CDN links. Here are common sources:

https://www.jsdelivr.com/

Search for your library and get the CDN URL:

Option 2: Library's Official Docs

Most libraries document their CDN links:

Loading CSS Stylesheets

Some libraries require CSS files:


Troubleshooting

Issue: "Element not found" in onMount

Symptoms:

  • Console error: "Element not found"

  • Library fails to initialize

  • Blank component

Solutions:

  1. Verify the id in HTML matches the getElementById() call

  2. Check console for JavaScript errors

  3. Ensure the element has content/dimensions (add style="min-height: 500px;")

Issue: Library is not defined

Symptoms:

  • "ReferenceError: FullCalendar is not defined"

Solutions:

  1. Verify CDN URL is correct

  2. Check that onBeforeMount is loading the library

  3. Check browser Network tab - is the script loading?

  4. Try a different CDN or version

Issue: Component works but memory leak

Symptoms:

  • Multiple instances stack up

  • Performance degrades over time

Solutions:

  1. Add onBeforeDestroy cleanup

  2. Call library's destroy/remove method

  3. Clear global references (window._api = null)

Issue: "this.$refs is not a function"

Symptoms:

  • TypeError about $refs

Solution:

  • You cannot use this.$refs in namedAction functions

  • Use document.getElementById() instead

Issue: "schema is not defined"

Symptoms:

  • ReferenceError: schema is not defined

Solution:

  • schema is not accessible in namedAction functions

  • Store configuration in model or hardcode in the function

  • Access via model.myConfig instead


Best Practices

βœ… DO:

  • Use id attributes for elements you need to access

  • Check if elements exist before using them

  • Store library instances in window for global access

  • Add cleanup in onBeforeDestroy

  • Use model for dynamic data

  • Log to console for debugging

  • Test with mock data first

❌ DON'T:

  • Use this.$refs in namedActions (not available)

  • Access schema directly in functions (not available)

  • Forget to destroy library instances

  • Load libraries globally if components are self-contained

  • Use synchronous operations that block rendering


More Examples

Leaflet Maps

CodeMirror Editor


Quick Reference Checklist

When creating a component with a third-party library:


See Also


Next Steps

  1. Copy one of the complete examples above

  2. Modify the HTML, configuration, and actions for your needs

  3. Test in the component editor with mock data

  4. Add to your component library

  5. Use on pages across your app

You now have everything needed to integrate any JavaScript library into BetterForms! πŸŽ‰

Last updated