EN RU
Forum

Methodology

Technology

Toolbox

Libraries

Tutorials

Working with the DOM tree

DOM node of a block instance

The this.domElem field is reserved in the context of a block instance with DOM representation. This field contains a jQuery object with references to all the DOM nodes that this instance is connected to.

Elements

BEM elements of blocks are represented in i-bem.js as DOM nodes nested in the DOM node of a block instance.

To access elements DOM nodes and work with their modifiers, use the block instance API:

BEMDOM.decl('link', {
    setInnerText: function() {
        this.elem('inner').text('Link text');
        /* ... */
        this.elem('inner').text('Another text');
    }
});
BEMDOM.decl('link', {
    setInnerText: function() {
        var inner = this.findElem('inner');
        inner.text('Link text');
        /* ... */
        inner.text('Another text');
    }
});

When block elements are added and removed dynamically, the cache of elements may need to be cleared. Use the dropElemCache('elements') method for this purpose. It accepts a string with a space-separated list of names of elements to drop the cache for.

BEMDOM.decl('attach', {
    clear: function() {
        BEMDOM.destruct(this.elem('control'));
        BEMDOM.destruct(this.elem('file'));
        return this.dropElemCache('control file');
    }
});

Searching for block instances in the DOM tree

Accessing a different block in i-bem.js is performed from the current block located on a particular node of the DOM tree. The search for other blocks in the DOM tree can be made in three directions (axes) relative to the current block DOM node:

The signature of the helper methods is identical:

The helper methods for searching are paired. They differ in the values they return:

Example

When the disabled modifier is toggled, the instance of the attach block finds the button block nested inside it and toggles its disabled modifer to the same value that it received itself:

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

provide(BEMDOM.decl(this.name, {
    onSetMod: {
        'disabled': function(modName, modVal) {
            this.findBlockInside('button').setMod(modName, modVal);
        }
    }
}));

});

Note Don't use jQuery selectors to search for blocks and elements. i-bem.js provides a high-level API for accessing DOM nodes of blocks and elements. Accessing the DOM tree directly makes the code less robust to changes in the BEM libraries, and may cause errors that are difficult to detect.

Dynamic changes to blocks and elements in the DOM tree

In modern interfaces, it is often necessary to create new fragments of the DOM tree and replace old ones as part of the workflow (using AJAX). The following functions are provided in i-bem.js for adding and replacing fragments of the DOM tree.

All the functions automatically initialize blocks on the updated fragment of the DOM tree.

To simplify the creation of BEM entities on updated fragments of the DOM tree, you can use the BEMHTMLtemplate engine by enabling it as a ym module. BEM entities are described in BEMJSON format directly in the block code. The BEMHTML.apply function generates HTML elements for the BEMJSON declarations according to BEM naming conventions.

Example

The attach block _updateFileElem method deletes the file element if it exists, and creates a new element using the BEMHTML.apply function:

modules.define(
    'attach',
    ['BEMHTML', 'strings__escape', 'i-bem__dom'],
    function(provide, BEMHTML, escape, BEMDOM) {

provide(BEMDOM.decl(this.name, {
    _updateFileElem : function() {
        var fileName = extractFileNameFromPath(this.getVal());
        this.elem('file').length && BEMDOM.destruct(this.elem('file'));
        BEMDOM.append(
            this.domElem,
            BEMHTML.apply({
                block : 'attach',
                elem : 'file',
                content : [
                    {
                        elem : 'icon',
                        mods : { file : extractExtensionFromFileName(fileName) }
                    },
                    { elem : 'text', content : escape.html(fileName) },
                    { elem : 'clear' }
                ]
            }));
        return this.dropElemCache('file');
    }
}));

});