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

qubit-angular

v2.0.0

Published

A library for enabling Qubit Experiences on Angular sites

Downloads

6

Readme

qubit-angular

Smoothly integrate Qubit Experiences on Angular websites.

Wrap or inject page components using qubit-angular/wrapper and change their rendering behaviour from within Experiences to provide segment targeting, personalisation and A/B testing.

Installation

Install from npm.

npm install --save qubit-angular

Angular compatibility

The package is compatible with Angular versions 2 to 6.

Website Implementation

To expose a component for use in Experiences, wrap the relevant site components with <qubit-angular> component.

First import the QubitAngularModule in each module where you will be using the <qubit-angular> component.

import { QubitAngularModule } from 'qubit-angular/wrapper';

@NgModule({
  declarations: [],
  imports: [ QubitAngularModule ],
  providers: [],
  bootstrap: [ AppComponent ]
})
export class AppModule {}

Now you can use the <qubit-angular> component. Specify the id attribute for Qubit experiences to reference when taking over. Optionally specify the data attribute to pass some data to the experience, could be a product, user, or any other data you think might be relevant for this experience.

<div>
  <qubit-angular id="header" [data]="trip">
    <app-header></app-header>
  </qubit-angular>
</div>

Alternatively, it's possible to add the <qubit-angular> component without wrapping existing content. By default they won't show anything, but could then be used by Qubit experiences to inject new content.

<div>
  <app-content></app-content>
  <qubit-angular id="campaign"></qubit-angular>
</div>

Experience Implementation

After the site has been setup with at least one wrapper component, we can move to integrating from Qubit Experiences by using the qubit-angular/experience module.

First initiate the library in the experience activation by passing in the experience meta information.

module.exports = function experienceActivation (options, cb) {
  const experience = require('qubit-angular/experience')(options)
}

Qubit Angular uses a concept of wrapper ownership. This means that only a single experience can control the contents of a given wrapper id at any given time. This removes conflicts between experiences attempting to modify the same component.

In order to take ownership of a wrapper during the experience activation phase, use the experience.register function.

module.exports = function experienceActivation (options, cb) {
  const experience = require('qubit-angular/experience')(options)

  const release = experience.register(['header'], (slots) => {
    options.state.set('slots', slots)
    cb()
  })

  return {
    // important to release the ownership of the wrappers
    // so that other experiences on other virtual pageviews
    // can claim them.
    remove: release
  }
}

And in the experience execution, we can now render alternative content into the registered slots:

module.exports = function experienceExecution (options) {
  const { NewHeader } = require('./utils')
  const slots = options.get('slots')

  slots.render('header', NewHeader)

  // unrender, if you only wanted to render the new content temporarily
  slots.unrender('header', NewHeader)

  return {
    remove: slots.release
  }
}

Here's the NewHeader component implementation, which is kept in utils.js. It's not an angular component, but a simple JavaScript class with constructor render method and some lifecycle hooks.

  • constructor - gets passed a DOM element reference el which it can use to render whatever content in. It also gets originalEl with original content that it can use to read information from. Finally, data if data was passed to the wrapper component.
  • render - only called once, right after instantiating the component, it should use the DOM element passed in the constructor to render content and attach event listeners.
  • onChanges - called when bound data changes.
  • doCheck - if a nested data attribute changes and not the whole object, onChanges will not detect that change and so you can use doCheck hook to detect changes manually
  • onDestroy - called once when component is unmounted from the DOM, use it to perform cleanup - clear timers, remove event listeners, etc.

the onChanges, doCheck and onDestroy hooks are equivalents of ngOnChanges, ngDoCheck and ngOnDestroy hooks documented in the official Angular docs.

module.exports.NewHeader = class NewHeader {
  constructor (el, originalEl, data) {
    this.el = el
    this.originalEl = originalEl
    this.data = data
  }
  render () {
    return this.el.innerHTML = 'NEW HEADER'
  }
  onChanges () {
    // if the data passed in changed
  }
  doCheck () {
    // onChanges will not always detect changes automatically
    // use this to manually check if this.data changed, and rerender
    // e.g.
    if (this.title != this.data.title) {
      this.title = this.data.title;
      this.render();
    }
  }
  onDestroy () {
    // cleanup if necessary, e.g. unbind event listeners
  }
}

How does this work?

By default, the <qubit-angular> transparently renders all of the children components using <ng-content>. But when experience claims the wrapper, it hides the <ng-content> and reveals a <div #outlet> - a DOM element that is passed by reference to an experience. On a route change, or state change, if the component containing <qubit-angular> is removed, the experience gets a chance to cleanup via an onDestroy lifecycle hook and the ownership of the wrapper is released.

Debugging

Set __qubit.angular.debug = true to see additional logging output about the state and lifecycles of the wrapper components.

Points of interest

The implementation of the component and module is over here:

The implementation of the experience registration hook is here:

Demo

To run this locally and see how it works, use the included demo project.

1. git clone [email protected]:QubitProducts/qubit-angular.git
2. cd qubit-angular/demo
3. npm install
4. npm start
5. open http://localhost:4200

You should see a green themed website with some purple elements being controlled by the wrappers. See demo/src/experiences/index.ts to see how the wrappers are used to render alternative content.

Run the following in console to simulate what happens when Qubit smartserve is off or on:

window.unloadSmartserve()
window.loadSmartserve()

Releasing

To release a new version of the package, run

npm run release