One of the most frequent use case for the Yandex.Maps API is creation of a menu to show different types of PoI (Points of Interest) - geoobject collections. This menu helps an end user to choose which types of POI to see at any given time. Here is an example. Now we will implement all above based on BEM methodology.
BEM developers created a project-stub for a quick start with BEM project. We are going to use it.
Clone the project-stub and install all required dependences:
git clone https://github.com/bem/project-stub.git shopsList
cd shopsList
npm install
Now we can use the project locally. To test that everything works properly, open the project folder and run enb server
. Than check the result at localhost:8080/desktop.bundles/index/index.html in browser:
Now we can proceed to the next step.
We need to create several blocks:
map
block for the map itselfsidebar
block (a left column) for amenu
blockmenu
block for a list of organizations by groups showing.
According to BEM methodology the blocks should not “know” about each other. So, we need to create one more intermediate block that will lister to the menu clicks and interact with the map. We will call this block i-geo-controller
.
We considered all details of the page structure and defined the main blocks, so it should be easy to declare the page in BEMJSON. Now we start to write all above in JSON-styled code.
The page structure is shown below:
page
== container
==== map
==== sidebar
====== menu
======== items
 An example of BEMJSON declaration:
{
block: 'page',
content: [
{
block: 'container',
content: [
{
block: 'map'
},
{
block: 'sidebar',
content: [
{
block: 'menu',
content [ /* menu items */ ]
}
]
}
]
}
]
}
You can see the source code in desktop.bundles/index/index.bemjson.js.
We start development from the main block — map
. First of all we should connect to the API with all the needed options. We could implement this with a new block called i-API
. But, we could also choose the more convenient way, and implement all required options in one block using modifiers. We set api
modifier with ymaps
value for map
block. In the example we will use a dynamic API. However, we could use a static API instead.
To ease our work with the map, we should design additional handy placemarks for the interface. For this, we should process geoObjects
field with placemarks or placemark collections.
We create the following interface:
- For the placemark
{
coords: [],
properties: {},
options: {}
}
- For the placemark collection
{
collection: true,
properties: {},
options: {},
data: []
}
This code covers almost 90% of all possible use cases.
We should implement a two-level menu. For this, we create menu
block to catch the clicks on the groups and elements. We need to create the following elements:
item
— a menu item.content
— a container for the items.title
— a group title.
We include one menu block into another one to build needed hierarchy.
Here is a simple menu example declared in BEMJSON:
{
block: 'menu',
content: [
{
elem: 'title',
content: 'menu title'
},
{
elem: 'content',
content: [
{
elem: 'item',
content: 'menu-item-1'
},
{
elem: 'item',
content: 'menu-item-2'
}
]
}
]
}
i-geo-controller
is a block-controller that listens to menu
block events, such as menuItemClick
and menuGroupClick
to react on their behavior and make definite actions on the map.
In our example this block has the following tasks:
- If there is a click on the placemark, the controller should center the map on this placemark and open the balloon.
- If there is a click on the group, the controller should show or hide this group.
In addition to interaction with the map, the controller block must ”know“ if the map is ready for objects management. To implement all above, map
block should emmit map-inited
event, and the controller block should listen for this event trigger and keep a link of the map instance.
For example, zloylos.github.io/ymapsbem/index-en.html.
Thus, the example implemented with BEM methodology is more verbose than without BEM, we get well-structured and easy-to-support code base. So, we get benefit from scaling and expanding it easily, with no need in code rewriting, thanks to the methodology.
Thanks to Alexander Tarmolov for advice and support.