Forum

Methodology

Toolbox

Platform

Community

Initialization

Block initialization creates a JS object corresponding to the block instance in the browser memory. Initialization of block instances is performed by the init() method of the i-bem__dom module on the specified fragment of the DOM tree.

Each instance of a block can be assigned three states:

  • The block instance is not initialized (the JS object has not been created).
  • The block instance is initialized (the JS object has been created in the browser memory).
  • The block instance was destroyed (all references to the block instance were deleted, and it may be removed by the garbage collector).

In i-bem.js, these states of the block instance are described using the auxiliary js modifier.

  • Before initialization, the block instance does not have a js modifier.

    <div class="my-block i-bem" data-bem="...">
     ...
    </div>
    
  • At the time of the block instance initialization, the js modifier is set to inited.

    <div class="my-block i-bem my-block_js_inited" data-bem="...">
     ...
    </div>
    
  • If a fragment of the DOM tree is deleted during workflow (using the destruct method of the i-bem__dom module), block instances are also deleted with it if their HTML elements are all located in this fragment. Before deleting a block instance, the js modifier is deleted so that the block instance destructors are executed.

Note If a block instance was bound to multiple HTML elements, the block will exist as long as at least one element it is connected to remains in the HTML tree.

If multiple instances of other blocks are located on an HTML element, the initialization of one of them (the appearance of the js_inited modifier) doesn't affect the initialization of the rest of them.

Example

Only the my-block instance is initialized on the HTML element.

The lazy-block instance is not initialized:

<div class="my-block my-block_js_inited lazy-block i-bem" data-bem="{ " my-block="my-block">
 ...
</div>

Note The presence of the js modifier makes it possible to write various CSS styles for a block that depend on whether it is initialized or not.

Block instance constructor

Triggers can be assigned for changing the values of the js modifier, the same way as for other block modifiers.

The trigger to set the js modifier to the inited value is executed during block creation. This trigger can be considered a block instance constructor:

onSetMod: {
    'js': {
        'inited': function() { /* ... */ } // block instance constructor
    }
}

Block instance destructor

The moment of block deletion is the moment when all references to the block JS object are destroyed. After this, the garbage collector can delete it from browser memory.

The trigger to delete the js modifier (set it to an empty value '') is executed before deleting the block. This trigger can be considered a block instance destructor.

onSetMod: {
    'js': {
        '': function() { /* ... */ } // block instance destructor
    }
}

Waves of initialization

The instances of blocks that are present on a page do not have to be initialized simultaneously. The blocks can be added dyamically and initialized on request or on an event. Initialization of a consecutive group of blocks is called a wave of initialization.

A new wave of initialization is created in the following cases:

Automatic initialization

The i-bem.js framework allows automatically initializing blocks with DOM representation when the domReady event occurs.

For automatic initialization, JS objects will be created in browser memory for all the DOM nodes containing i-bem in the class attribute. Initialization is performed by the init function of the i-bem__dom module.

To enable automatic initialization, specify the i-bem block with the init modifier set to the auto value in the .deps.js dependencies file.

Example of .deps.js:

({
    shouldDeps: [
        {
            block: 'i-bem',
            elem: 'dom',
            mods: { 'init': 'auto' }
        }
    ]
})

The page block already contains i-bem__dom_init_auto in dependencies, so if it is used in the project, nothing else needs to be enabled.

Note Blocks that have lazy initialization set will not be initialized automatically.

Initialization on event (lazy initialization)

If a page has many instances of blocks, automatic initialization of all the blocks at the time of loading is undesirable, since this increases the loading time and the amount of memory consumed by the browser.

It is more convenient to initialize JS objects only when their functionality is needed by the user, such as when the block is clicked. This is called lazy or live initialization.

The static property live is reserved in the declaration for describing conditions for lazy initialization. The live property can have the following types of values:

Boolean

  • true — Instances of blocks in this class will be initialized only when attempting to get the corresponding instance (see the section Interaction of blocks).
modules.define('my-block', ['i-bem__dom'], function(provide, BEMDOM) {

provide(BEMDOM.decl(this.name,
    {
        onSetMod: {
            'js': {
                'inited': function() { /* ... */ } // this code will be executed
                                                   // the first time the block instance is accessed
            }
        }
    },
    { live: true } // static methods and properties
));

});
  • false — Allows cancelling lazy initialization of blocks that is set on another redefinition level.

Function – a function that is executed before initializing the first instance of a block of the specified class. If the function returns false, instances of the block will be initialized automatically.

modules.define('my-block', ['i-bem__dom', 'ua'], function(provide, BEMDOM, ua) {

provide(BEMDOM.decl(this.name, {
    onSetMod : {
        'js' : {
            'inited' : function() {
                // executed when the block instance is first accessed
            }
        }
    }
}, {
    live : function() { // executed before initialization of the first instance of the block
        if(ua.msie && ua.version < 9) {
                          // disables lazy initialization of the block
            return false; // for old versions of Internet Explorer
        }
    }
}));

});

Note Lazy initialization can be canceled for a specific instance of a block. To do this, specify data-bem='{"live": false}' in the parameters of the HTML element that the block instance is bound to.

To initialize block instances as DOM events or BEM events occur, subscribe to delegated events in the function body or use a helper.

Example

Instances of my-block will be initialized on the click DOM event on the block DOM node. For each click DOM event, the _onClick method of the block instance is called:

modules.define('my-block', ['i-bem__dom'], function(provide, BEMDOM) {

provide(BEMDOM.decl(this.name, {
    onSetMod: {
        'js': {
            'inited': function() { /* ... */ } // executed on the first "click" DOM event
        }
    },

    _onClick: function(e) { /* ... */ } // executed on every ”click“ DOM event
}, {
    live: function() {
        this.liveBindTo('click', function(e) {
            this._onClick(e);   // block instance will be created when a click occurs
                                // and its _onClick method will be called
        });
    }
}));

});

Note The live property applies to static methods of a block class. So even if it is set in the block declaration with a particular modifier, live will be applied to all the blocks in this class, regardless of the modifiers.

Helpers for initialization on an event

To simplify initialization on events in the context of a block instance, a set of helper methods is reserved for subscribing to the following types of events:

  • DOM events:
    • liveBindTo([elemName], event, [callback]) — Subscribes to an event on the block DOM node or its elements, with deferred initialization. The block will be initialized on the first event. The callback handler function will be called on event and after block initialization.
    • liveUnbindFrom([elemName], event, [callback]) — Deletes the subscription with deferred initialization on an event on the block DOM node or its elements.
    • liveInitOnEvent([elemName], event, callback) — Initialization on an event on the block DOM node or its elements.
  • BEM events:
    • liveInitOnBlockEvent(event, blockName, callback) — Initialization on a BEM event of an instance of a different block placed on the DOM node of the current block instance.
    • liveInitOnBlockInsideEvent(event, blockName, [callback]) — Initialization on a BEM event of an instance of a different block nested in the DOM node of the current block instance.

For example, the menu block is initialized on the click BEM event of the nested menu-item block.

modules.define('menu', ['i-bem__dom', 'menu-item'], function(provide, BEMDOM) {

provide(BEMDOM.decl(this.name, {
    _onItemClick : function(e, data) {
        // handler function for the ”click“ BEM event on nested ”menu-item“ instances
    }
}, {
    live : function() {
        this.liveInitOnBlockInsideEvent('click', 'menu-item', function(e, data) {
            this._onItemClick(e, data);
        });
    }
}));

});

Initialization of blocks on a fragment of the DOM tree

The initialization of JS objects can be called directly for a specified fragment of the DOM tree. This is often necessary when developing AJAX interfaces, when new instances of blocks have to be dynamically added to a page or existing ones have to be updated.

In i-bem.js, the following functions perform dynamic initialization of blocks:

  • init, destruct – Initialization/destruction of blocks on a specified fragment of the DOM tree.
  • update, replace, append, prepend, before, after – Adding/replacing a fragment of the DOM tree with simultaneous initialization of blocks on the updated fragment.

For an example of using functions that perform dynamic initialization, see Dynamically updating blocks and elements in the DOM tree.

Deleting blocks on a fragment of the DOM tree

Like the block initialization process, the deletion process can be called directly for a specified fragment of the DOM tree. For example, you may use this for dynamically deleting instances of blocks from a page when developing AJAX interfaces.

Explicitly invoking this procedure guarantees correct deletion of:

  • Nested DOM nodes.
  • Blocks mixed into other blocks.

Use the BEMDOM.destruct static method to explicitly invoke deletion.

The method accepts:

  • ctx {jQuery} – The root DOM element. Deleted together with all the nested DOM nodes.
  • excludeSelf {Boolean} – Doesn't delete the root DOM element if set to true. By default, false.

Initializing and deleting blocks without DOM representation

Use the BEM.create method for creating JS objects of a block without DOM representation (that aren't bound to an HTML element).

The method accepts:

  • name {String|Object} – The name of the block.

Returns an instance of a block of the specified class.

Deletion of instances of blocks without DOM representation can't be performed automatically. Blocks without DOM representation are normal JS objects and are deleted when all the references to the block object are deleted.

If you notice a mistake or want something to supplement the article, you can always write to us at GitHub, or correct an article using prose.io.