States of a block
When designing a dynamic block in BEM style, you need to provide the complete logic of changes that occur in it as a set of states for the block. Then the block behavior is determined by triggers — callback functions that are performed when the block switches from one state to another.
This allows you to write the block code declaratively as a set of statements in the format: state description
— action performed when switching to this state
.
Modifiers
According to the BEM methodology, modifiers describe the state of a block and its elements.
A modifier indicates which of the possible states the block is in. A modifier is a name — value pair. The list of acceptable modifier values describes the set of block states. For example,
to describe a block size, you can use the size
modifier with the possible values s
, m
and l
.
A simple modifier is a special case when only the presence or absence
of the modifier on the block is important, and its value is insignificant. An example is the modifier describing the ”disabled“ state: disabled
. A modifier with an unspecified i-bem.js
value is interpreted as boolean and automatically assigned the value true
.
Each block can have one or more modifiers set. A block isn't required to have any modifiers. The block developer defines the list of acceptable modifiers and their values.
Modifiers are set during initialization of a block instance (if modifiers and their values are specified in the class
attribute of the corresponding HTML element).
Modifiers can change as part of the block functioning (for example, as a reaction to a DOM event of the block), or at the request of other blocks (see Interaction of blocks).
When setting, deleting, and changing modifier values, triggers are executed.
Note If modifiers were set in a block HTML element before its initialization, the triggers to set these modifiers are not executed. In this case, the block instance gets its original state, and doesn't change it.
Managing modifiers
Methods of a block instance for working with modifiers:
hasMod([elem], modName, [modVal])
– Checks for the presence of a modifier. Returnstrue
if themodName
modifier is set.getMod([elem], modName)
– Returns the value ofmodName
.getMods([elem], [...modNames])
– Returns a hash with the values of all modifiers. You can get the values of multiple modifiers by passing their names in separate arguments ([...modNames]
). To get the modifiers of an element, you can specify the[elem]
argument.setMod([elem], modName, [modVal=true])
– Sets themodName
modifier. If the value ofmodVal
isn't specified, a simple modifier will be set.toggleMod([elem], modName, modVal1, [modVal2], [condition])
– Toggles a modifier's value. If the[modVal2]
argument is passed, it switches betweenmodVal1
andmodVal2
. If not,modVal1
will be set and removed in turn. Thecondition
argument with thetrue
value allows inverting the order for toggling modifier values.delMod([elem], modName)
– DeletesmodName
.
Example
The changeColor
method of the square
block toggles the color
modifier between the values green
and red
, if the block has the has-color
modifier set:
BEMDOM.decl('square', {
changeColor : function(e) {
if(this.hasMod('has-color')) {
this.toggleMod('color', 'green', 'red');
}
}
});
The same methods allow managing modifiers of the block elements. To do this, a reference to the element DOM node (not the element name) is passed as the first argument.
Example
On a click, the searchbox
block can assign its input
element the simple modifier clean
(the assumed value is true
):
BEMDOM.decl('searchbox', {
_onClick: function() {
this.setMod(this.elem('input'), 'clean');
}
});
Note Use the API for changing the values of modifiers. Don't set modifiers by altering the CSS classes of the corresponding DOM node yourself.
For complete documentation of the API for managing modifiers, see the JSDoc section for the i-bem
block.
Triggers to set modifiers
Triggers to set modifiers are executed in two phases:
Before setting the modifier. This phase is reserved for the ability to cancel setting modifiers. If at least one of the triggers executed in this phase returns
false
, modifiers are not set.After setting the modifier. Triggers executed in this phase can't cancel setting modifiers.
Triggers can be bound to the following types of changes to modifier values:
Setting any modifier to any value.
Setting a specific
modName
modifier to any value (including setting a simple modifier totrue
).Setting a specific
modName
modifier to a specificmodVal
value.Setting a modifier to the value
''
(empty string), which is equivalent to deleting the modifier or setting a simple modifier tofalse
.
When setting the modName
modifier to the modVal
value, triggers in
each phase (if they are defined) are fired in the same order as they are
listed in the list of events above (from general to specific).
Thus, when defining a trigger, the user specifies:
The execution phase (before or after setting a modifier).
The event type (the modifier name and value to set).
Execution phases
An additional phase prior to setting a modifier allows performing certain checks without risk of affecting the logic for setting the modifier. For example, if there are mutually exclusive modifiers, it makes sense before setting one of them to check whether the other is already set.
Example
The focused
modifier won't be set on the searchbox
block if it has the disabled
modifier.
BEMDOM.decl('searchbox', {
beforeSetMod : {
'focused' : {
'true' : function() {
return !this.hasMod('disabled');
}
}
},
onSetMod : {
'focused' : {
'true' : function() { /* ... */ }
}
}
});
If the trigger for the phase prior to setting (beforeSetMod
) returns false
, the modifier is not set.
For more information about using triggers, see Declaring triggers.
Note The trigger to set the
js
modifier toinited
is a constructor of a block instance, but with the value''
it is a destructor of a block instance. For more information, see Initialization.