Skip to content
Last update: May 8, 2024

Extend Dynamic Expression Tree

This article will show you how to extend the existing promotion expression tree of the Marketing module with these new elements:

  • New expression block:

New expression block

  • New block element:

New block element

Sample code


Prior to extending your dynamic expression tree, you need to:

Define New Class for Expression Tree Prototype

The following example creates a new derived prototype from PromotionConditionAndRewardTreePrototype that represents the original expression tree used for marketing promotion. Here, we register a new BlockSampleConditionroot block and extend the existing BlockCatalogCondition with a new element, SampleCondition:

public sealed class SamplePromotionConditionAndRewardTreePrototype : PromotionConditionAndRewardTreePrototype
        public SamplePromotionConditionAndRewardTreePrototype()
            //Extend existing 'If any of these catalog condition' block with a new condition element
            var blockCatalogCondition = AvailableChildren.OfType<BlockCatalogCondition>().FirstOrDefault();
            blockCatalogCondition.AvailableChildren.Add(new SampleCondition());

            // Add a new block with sample condition to the beginning of the tree
            var blockSampleConditions = new BlockSampleCondition().WithAvailConditions(new SampleCondition());
            AvailableChildren.Insert(0, blockSampleConditions);
            Children.Insert(0, blockSampleConditions);

Register Your Extension in module.cs

To register your extension in the module.cs file:

  1. Override the original PromotionConditionAndRewardTreePrototype type with the newly created one in the module.cs file:

    public void Initialize(IServiceCollection serviceCollection)
                // Override the original expression prototype tree with new type
                AbstractTypeFactory<PromotionConditionAndRewardTreePrototype>.OverrideType<PromotionConditionAndRewardTreePrototype, SamplePromotionConditionAndRewardTreePrototype>();
  2. Add a dependency to the Marketing module into the module.manifest file:

            <dependency id="VirtoCommerce.Marketing" version="3.0.0" />


This line is important for correct module initialization order.

Readmore Module Initialization

Define HTML Templates for New Elements

It is a best practice to define all HTML templates for new elements within a single file, where the templates are dynamically loaded as resources.


Use the following schema as a template ID: expression-{C# element class name}.html.

<script type="text/ng-template" id="expression-BlockSampleCondition.html">
    For condition evaluator with
    <a class="__link" left-click-menu data-target="allAny_menu{{}}">{{element.all | boolToValue:'all':'any'}}</a> of these sample values
    <ul class="menu __context" role="menu" id="allAny_menu{{}}">
        <li class="menu-item" ng-click='element.all=true;'>all</li>
        <li class="menu-item" ng-click='element.all=false;'>any</li>
<script type="text/ng-template" id="expression-SampleCondition.html">
    Sample condition is met: 
    <a class="__link" left-click-menu data-target="yesNo_menu{{}}">{{element1.isSatisfied | boolToValue:'yes':'no'}}</a>
    <ul class="menu __context" role="menu" id="yesNo_menu{{}}">
        <li class="menu-item" ng-click='element1.isSatisfied=true;'>yes</li>
        <li class="menu-item" ng-click='element1.isSatisfied=false;'>no</li>

Register New Elements in Main module.js File

Register your newly created expression elements in dynamicExpressionService that is used as a registry for all known tree elements:

angular.module(moduleName, [])
    .run(['virtoCommerce.coreModule.common.dynamicExpressionService', '$http', '$compile',
        function (dynamicExpressionService, $http, $compile) {
            //Register Sample expressions
                id: 'BlockSampleCondition',
                newChildLabel: '+ add sample condition',
                getValidationError: function () {
                    return (this.children && this.children.length) ? undefined : 'Promotion requires at least one eligibility';
                id: 'SampleCondition',
                displayName: 'Sample condition is []'

            $http.get('Modules/$(VirtoCommerce.MarketingSample)/Scripts/all-templates.html').then(function (response) {
                // compile the response, which will put stuff into the cache

Build Own Module and Restart Platform

  1. Build your solution and pack the module scripts with the following command:

    npm run webpack:build
  2. Restart the platform instance to apply your changes.

  3. Open Platform Manager, go to Marketing → Promotions → New promotion. The new For condition evaluator with any of these sample values block with its single Sample condition is met: no/yes line appears.