Events

Events are the primary way to interact with the Promotion Engine. The app publishes events when data becomes available and subscribes to a number of events that can be published by third parties.

The documentation below describes the API as of version 9.x of the script.

Public properties or functions that are not in the discountNinja.api namespace should be considered obsolete and will be removed in the next major version release.

Using undocumented functions or objects will result in issues as custom code that relies on those functions or objects may break in the future when Discount Ninja's script is automatically updated.

API ready

Details

Event

la:dn:api:ready

Direction

This event is published by the app. You can optionally subscribe to it.

Behavior

Signals that the script has loaded and interaction with the API is possible.

Syntax

function performActionWhenApiIsReady() {
    //Add your logic here
    console.log('API ready');
}

//Check if the API is ready
if (typeof discountNinja === 'undefined' || 
    typeof discountNinja.api === 'undefined') {
    //The API is not ready, wait for it
    document.addEventListener("la:dn:api:ready", function(event) { 
        performActionWhenApiIsReady();
    });
}
else {
    //The API was already available, no need to wait
    performActionWhenApiIsReady();
}

Promotions loaded

Details

Event

la:dn:promotions:loaded

Direction

This event is published by the app. You can optionally subscribe to it.

Behavior

Published after promotions have been loaded, processed and filtered by the app. It allows the consumer to inspect which promotions are available for the user during the browsing session.

Event properties

The event data contains a promotions object.

Syntax

document.addEventListener("la:dn:promotions:loaded", function(event) { 
    const promotions = event.detail.data[0]; 
    console.log('Promotions loaded', promotions);
});

Product discount calculated

Details

Event

la:dn:product:discount:calculated

Direction

This event is published by the app. You can optionally subscribe to it.

Behavior

This event is published when the (discounted) price of any marked product on the page has been calculated.

The app will attempt to find all products on a page based on markers in the HTML. It then applies the available promotions to those products and publishes one event per product variant with the results.

For the current product, this event is published when the page is loaded and is published again when the selected variant or selected selling plan changes. For other products, this event is published only once per product and per page load.

Event properties

The event data contains a product variant price info object.

Syntax

document.addEventListener("la:dn:product:discount:calculated", function(event) {
    const productVariantPriceInfo = event.detail.data[0]; 
    console.log('Product variant price calculated', productVariantPriceInfo);
});

Cart updated

Details

Event

la:dn:cart:updated

Direction

This event is published by the app. You can optionally subscribe to it.

Behavior

Published when the (discounted) cart has been calculated.

This event is published when the page is loaded and is published again when the content of the cart changes or the set of applied promotions changes.

Event properties

The event data contains a discounted cart object.

Syntax

document.addEventListener("la:dn:cart:updated", function(event) {
    const discountedCart = event.detail.data[0]; 
    console.log('Discounted cart available', discountedCart); 
});

Cart mutations processing

Details

Event

la:dn:cart-mutations:processing

Direction

This event is published by the app. You can optionally subscribe to it.

Behavior

Published when the store is making updates to the cart.

This event is published when Discount Ninja detects that network requests have been made to clear, update, change or add to the cart. Specifically, the app detects fetch requests to the /cart/add.js, /cart/update.js, /cart/change.js and /cart/clear.js (see https://shopify.dev/docs/api/ajax/reference/cart).

Syntax

<div id="cart-mutations-processing-label" style="display:none">
    Processing cart changes...
</div>

document.addEventListener("la:dn:cart-mutations:processing", function() {
    console.log('Cart mutations are processing...'); 
    
    // Optionally, show an HTML element 
    // The HTML element can be used to communicate this process to the visitor
    document.getElementById("cart-mutations-processing-label").style.display = 'block'
});

Cart mutations processed

Details

Event

la:dn:cart-mutations:processed

Direction

This event is published by the app. You can optionally subscribe to it.

Behavior

Published when the store has finished making updates to the cart.

This event is published when Discount Ninja detects that all network requests to the /cart/add.js, /cart/update.js, /cart/change.js and /cart/clear.js (see https://shopify.dev/docs/api/ajax/reference/cart) have been completed.

Syntax

<div id="cart-mutations-processing-label" style="display:none">
    Processing cart changes...
</div>

document.addEventListener("la:dn:cart-mutations:processed", function() {
    console.log('Cart mutations are processed...'); 
    
    // Optionally, hide an HTML element 
    // The HTML element can be used to communicate this process to the visitor
    document.getElementById("cart-mutations-processing-label").style.display = 'none';
});

Trigger checkout

Details

Event

la:dn:checkout:initiate

Direction

This event is subscribed to by the app. To publish it, use the following syntax:

document.dispatchEvent(new CustomEvent('la:dn:checkout:initiate'));

Behavior

This approach is useful if you need to trigger checkout programmatically without bypassing Discount Ninja.

Note: if you need a custom checkout pipeline (for example, you may want to execute custom validation logic before allowing the checkout to proceed) when clicking the checkout button, use this API function instead.

Syntax

/// The markup below shows a custom button for illustration purposes
/// (i.e. not a button of type="submit" with name="checkout")
/// Note: we advise against using a custom checkout button
<button name="customcheckout" onclick="handleCustomCheckout()">
  Check out
</button>
/// This function should be called by a custom checkout button 
/// such as the one described above
function handleCustomCheckout() {
  if (canAdvanceToCheckout() === true) {
     // Checks if Discount Ninja is available 
     if (discountNinja) {
        // Check if a Discount Ninja offer is applied to the cart        
        discountNinja.api.checkout.isDiscounted().then(function(requiresAdvancedCheckout) {
          if (requiresAdvancedCheckout === true) {
            // DN needs to handle the checkout
            advanceToCheckoutUsingDiscountNinja():
          }
          else {
            handleNonDiscountNinjaCheckout();
          }
        }); 
     }
     else {
        handleNonDiscountNinjaCheckout();
     }
  }
  else {
     //Custom logic to explain why the user cannot advance
  }
}

/// This optional function returns true if the user 
/// can advance to the checkout
function canAdvanceToCheckout() {
  return true;
}

/// This function instructs Discount Ninja
/// to advance to the checkout and apply offers
function advanceToCheckoutUsingDiscountNinja() {
  document.dispatchEvent(new CustomEvent('la:dn:checkout:initiate'));
}

/// This function should redirect the user to the checkout
/// when a checkout with Discount Ninja is not required
function handleNonDiscountNinjaCheckout() {
  //Custom logic to handle checkout
}

Redirect to checkout

Discount Ninja expects users to transfer from the cart to the checkout using a checkout button or link. See this article for more information: https://support.discountninja.io/en/articles/3505661-discount-ninja-checkout-button

As a result, any code that redirects the user to the checkout using window.location is not supported. The following example shows what such an implementation would look like:

/// The markup below shows a custom button for illustration purposes
/// (i.e. not a button of type="submit" with name="checkout")
/// Note: we advise against using a custom checkout button
<button name="customcheckout" onclick="handleCustomCheckout()">
  Check out
</button>
/// This function is called by a custom checkout button 
function handleCustomCheckout() {
  window.location = "/checkout";
}

Redirecting a user to the checkout by setting the window.location causes problems with Discount Ninja. Additionally, it causes other integration issues for the merchant since redirecting without submitting the form has numerous flaws:

  • The order note field is not submitted if it was changed during this session (and not updated using cart.js)

  • The locale may not be passed

  • The discount code present in the cart form is not passed

  • ...

To resolve this, either use a standard checkout button (a button of type="submit" with name="checkout") or change your checkout logic as follows:

/// This function is called by a custom checkout button 
function handleCustomCheckout() {
  if (discountNinja) {
    document.dispatchEvent(new CustomEvent('la:dn:checkout:initiate'));
  }
  else {
    // Your fallback logic
    // Note: we do not recommend redirecting to the checkout this way
    //       (see documentation), preferably resubmit the cart form
    window.location = window.Shopify.routes.root + "checkout";
  }
}

Convert money fields

Details

Event

la:dn:money:convert

Direction

This event is subscribed to by the app. To publish it, use the following syntax:

document.dispatchEvent(new CustomEvent('la:dn:money:convert'));

Behavior

Most currency conversion mechanisms are supported out-of-the-box by Discount Ninja. This means there is no need to implement custom logic in most cases.

In case the currency conversion mechanism of your theme (or supporting app) is not automatically triggered, you can publish this event after the theme has updated prices to let Discount Ninja know that it should re-render prices.

Syntax

function test() {
    // Custom logic that overrides prices
    document.dispatchEvent(new CustomEvent('la:dn:money:convert'));
}

Collection products updated

Details

Event

la:dn:collection:updated

Direction

This event is subscribed to by the app. To publish it, use the following syntax:

document.dispatchEvent(new CustomEvent('la:dn:collection:updated'));

Behavior

When collection products are added, removed or updated the app must recalculate the discounted prices and render the price.

Most mechanisms used to update collections are supported out-of-the-box by Discount Ninja. This means there is no need to implement custom logic in most cases.

In case the app is not automatically detecting a situation where collection products are updated, you can publish this event after the theme has updated the products to let Discount Ninja know that it should re-render prices.

Syntax

function test() {
    // Custom logic that updates collection products
    document.dispatchEvent(new CustomEvent('la:dn:collection:updated'));
}

Variant changed

Details

Event

la:dn:variant:changed

Direction

This event is subscribed to by the app. To publish it, use the following syntax:

document.dispatchEvent(new CustomEvent('la:dn:variant:changed'), [variantId]);

Behavior

When a different variant is selected, the app must recalculate the discounted price and render the price.

Most mechanisms used to change variants are supported out-of-the-box by Discount Ninja. This means there is no need to implement custom logic in most cases.

In case the app is not automatically detecting a situation where the product variant is changed, you can publish this event to let Discount Ninja know that it should re-render prices.

Parameters

variantId (number): the id of the selected variant

Syntax

function test() {
    // Custom logic that changes the selected variant
    const variantId = 123456;
    document.dispatchEvent(new CustomEvent('la:dn:variant:changed'), [variantId]);
}

Drawer cart opened

Details

Event

la:dn:drawercart:opened

Direction

This event is subscribed to by the app. To publish it, use the following syntax:

document.dispatchEvent(new CustomEvent('la:dn:drawercart:opened'));

Behavior

When a drawer cart is opened (or updated) the app may need to render discounted prices.

In case the app is not automatically detecting a situation where the drawer cart is opened, you can publish this event to let Discount Ninja know that it should re-render prices.

Syntax

function test() {
    //Custom logic that opens the drawer cart
    //And renders the content (including prices)
    document.dispatchEvent(new CustomEvent('la:dn:drawercart:opened'));
}

Entitlements calculated

Details

Event

la:dn:entitlements:calculated

Direction

This event is published by the app. You can optionally subscribe to it.

Behavior

Published when the (discounted) cart and the associated entitlements have been calculated.

This event is published when the page is loaded and is published again when the content of the cart changes or the set of applied promotions changes.

Event properties

The event data contains an array with Entitlement info objects. Each object documents if the user is entitled to a gift for a gift offer.

Syntax

document.addEventListener("la:dn:entitlements:calculated", function(event) {
    const entitlements = event.detail.data[0]; 
    console.log('Entitlements calculated', entitlements); 
});

Promotion code added

Details

Event

la:dn:promotioncode:added

Direction

This event is published by the app. You can optionally subscribe to it.

Behavior

Published when the a promotion code is redeemed using the promotion code field.

Event properties

The event data contains: - promotionCode: the promotion code that is applied - success: a boolean indicating that the code was added successfully - manual: a boolean indicating if the code was added manually or by the system

Syntax

document.addEventListener("la:dn:promotioncode:added", function(event) {
    const eventData = event.detail.data[0]; 
    console.log('Promotion code added', eventData); 
});

Promotion code removed

Details

Event

la:dn:promotioncode:removed

Direction

This event is published by the app. You can optionally subscribe to it.

Behavior

Published when the a promotion code is removed using the promotion code field.

Event properties

The event data contains: - promotionCode: the promotion code that is removed - success: a boolean indicating that the code was removed successfully

Syntax

document.addEventListener("la:dn:promotioncode:removed", function(event) {
    const eventData = event.detail.data[0]; 
    console.log('Promotion code removed', eventData); 
})

Last updated