npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@helga-agency/dynamic-content-loader

v1.0.2

Published

Extensible, loosely coupled custom elements that load content asynchronously, e.g. for filtered search results

Downloads

182

Readme

Dynamic Content Loader

Modular components to update multiple content blocks on a page in a synchronized way, e.g. to update pagination, filters and content separately (to keep the UI as responsive as possible) when a filter is changed.

Different components are wrapped in a dynamic-content-orchestrator and play together in a loosely coupled way. There are two types of components:

  • Listeners handle DOM or other events and request an update by dispatching an event.
  • Updaters that return the URL from where their content should be fetched and handle the content once it arrives.

Basic Flow:

  1. All Updaters register themselves at the DynamicContentOrchestrator by dispatching an addDynamicContentUpdater event with { updateResponseStatus, assembleURL }.
  2. Once a user interaction happens, a Listener dispatches a loadDynamicContent event with { requestConfiguration: { searchParams } }. The searchParams correspond to the filters that should be applied to the fetched content.
  3. The DynamicContentOrchestrator calls assembleURL on each Updater and collects the returned URLs.
  4. The DynamicContentOrchestrator fetches the content from every URL and calls updateResponseStatus on each Updater with the corresponding content.

Why the Orchestrator?

  • If user interactions happen at a fast pace, we must make sure that all previous requests are canceled (or at least discarded). If not, we might run into race conditions and display outdated content. The orchestrator cancels all previous requests (for all Updaters) once a new user interaction happens.
  • If multiple Updaters intend to fetch the same URL, it batches those requests and makes sure a URL is only fetched once.

An element can at the same time be a Listener and an Updater if it implements the the functions and events of both types.

Some of those components are provided within this package, others can be developed and integrated for specific use cases.

Example

<dynamic-content-orchestrator>
    <content-updater data-endpoint-url="/results" data-is-main-content>
        <div data-loading hidden>Loading…</div>
        <div data-error hidden><!-- Will be populated when needed --></div>
        <div data-content>Initial content</div>
    </content-updater>

    <a href="/page?q=5">
        <link-listener>
            <!-- This content-updater fetches the new pagination when the page changes-->
            <content-updater data-endpoint-url="/page">
                <div data-loading hidden>Loading…</div>
                <div data-error hidden><!-- Will be populated when needed --></div>
                <div data-content>Page 3</div>
            </content-updater>
        <link-listener>
    </a>

Components

Dynamic Content Orchestrator

Exposed Element

<dynamic-content-orchestrator></dynamic-content-orchestrator>

Structure

Serves as a wrapper around all other components below and ensures that they play togehter nicely.

Handles two events:

  • addDynamicContentUpdater ({ detail: { assembleURL: function, updateResponseStatus: function } }). The argument signatures are:
    • assembleURL (function({ searchParams: SearchParams })) will be called when new content should be fetched. Must return a string or null if nothing should be fetched.
    • updateResponseStatus (function({ status: string, content: string })) will be called when the orchestrator receives new content. Valid status are loading, loaded and failed. content will be the content that will be displayed (empty if the status is loading).
  • loadDynamicContent ({detail: { requestConfiguration: { searchParams: SearchParams } }}): Dispatched by Listeners when they want to fetch new content.

Attributes

None

Content Updater

Exposed Element

<content-udpater></content-updater>

Attributes

  • data-endpoint-url (string, attribute is required but value may be empty): URL that should be fetched; a query string may be automatically attached if it is requested by a listener (e.g. to paginate or filter the view).
  • data-is-main-content (boolean, optional): If set, the browser will scroll to the top of the element when the content changes.

Content

The following elements must be provided within <aync-loader>:

  • An element matching [data-content] (required): If the request succeeds, it will be added to this element and the element will be displayed.
  • An element matching [data-loading] (required): It will be displayed while the data is loading.
  • An element matching [data-error] (required): It will be displayed if loading data fails; the error message will be added to this element.

Events

Link Listener

Exposed Element

<link-listener></link-listener>

Attributes

None

Structure

Wrap the link-listener around any number of links to update the content dynamically when they're clicked. It listens to clicks on any child element and takes the href from the first surrounding element that has a href attribute. The href's query string will be used to dispatch a loadDynamicContent event.

Example

<link-listener>  
    <a href="/page?p=1"><span>1</span></a>  
    <a href="/page?p=2"><span>2</span></a>  
</link-listener>  

The click happens on the <span> elements (which do not have a href attribute); therefore the query string will be taken from the clicked span's first ancestor with a href attribute.

Events

  • loadDynamicContent (see DynamicContentOrchestrator) with the clicked link's (or its ancestral element's) href query string as searchParams.

Filter Change Listener

Exposed Element

<filter-change-listener></filter-change-listener>

Attributes

None

Structure

Wrap the filter-change-listener around a form to update the content dynamically when the form is changed.

Query String Updater

Exposed Element

<query-string-updater></query-string-updater>

Attributes

None

Structure

Updates the window location (query string) to represent the currently selected filters. Place it anywhere in the DOM (below the <dynamic-content-orchestrator>).

Facets Updater

Exposed Element

<facets-updater></facets-updater>

Attributes

  • data-endpoint (required, but may be empty): URL that should be fetched; a query string may be attached if it is requested by a listener.

Structure

Wrap around the facets provided by Drupal; component is quite Drupal-specific.