Creating your own module

Open in CodeSandbox

The Yandex.Maps API consists of a large number of interrelated modules.
By default, when the API is enabled, it loads a standard set of modules (package.full), which includes everything needed for working with the API.
A developer who uses the Yandex.Maps API can create custom modules.

In this example, we create a custom control with its own custom layout.
Both the control and the layout are designed as separate modules.
You can define your own module using the define
method After creating the map, a request is made to get the custom module using require

For more information about modules, see the section Modules.
<!DOCTYPE html>
<html>
    <head>
        <title>An example of loading only necessary modules</title>
        <meta
            http-equiv="Content-Type"
            content="text/html; charset=UTF-8"
        />
        <!--
            Set your own API-key. Testing key is not valid for other web-sites and services.
            Get your API-key on the Developer Dashboard: https://developer.tech.yandex.ru/keys/
        -->
        <script
            src="https://api-maps.yandex.ru/2.1/?lang=en_RU&amp;apikey=<your API-key>"
            type="text/javascript"
        ></script>
        <script src="custom_module.js" type="text/javascript"></script>
        <style>
            html,
            body,
            #map {
                margin: 0;
                padding: 0;
                width: 100%;
                height: 100%;
            }

            .placemark_counter {
                width: 50px;
                height: 50px;
                font-family: Arial;
                text-align: center;
                font-size: 22px;
                line-height: 50px;
                background-color: white;
                color: black;
                font-weight: bold;
            }
        </style>
    </head>
    <body>
        <div id="map"></div>
    </body>
</html>
// Creating our first custom module - a layout for our control.
ymaps.modules.define(
    "plugin.PlacemarkCounterControlLayout",
    [
        /**
         * The list of module dependencies.
         * These modules will be loaded (if they have not yet been loaded) before calling the function that defines the module.
         */
        "templateLayoutFactory",
    ],
    function (provide, templateLayoutFactory) {
        /**
         * The function that defines the module itself.
         *  The first argument is the provide function. The provide function must be passed directly to the module.
         *  The provide function call may be delayed. For example, in order to load some data.
         *  Subsequent arguments are requested in the module dependencies.
         */
        provide(
            templateLayoutFactory.createClass(
                "<div class=placemark_counter>{{ data.placemark_count }}</div>"
            )
        );
    }
);

/**
 * Creating a second custom module.
 * This module provides its own control, which is based on the buttons.
 */
ymaps.modules.define(
    "plugin.PlacemarkCounterControl",
    [
        "control.Button",
        "util.extend",
        "util.augment",
        // The second module in the dependencies requests the first one.
        "plugin.PlacemarkCounterControlLayout",
    ],
    function (
        provide,
        Button,
        extend,
        augment,
        PlacemarkCounterControlLayout
    ) {
        var CounterControl = function () {
            CounterControl.superclass.constructor.call(this, {
                data: { placemark_count: 0 },
                options: {
                    selectOnClick: false,
                    layout: PlacemarkCounterControlLayout,
                    maxWidth: 100,
                },
            });
        };
        // Inheriting all the methods of a standard button.
        augment(CounterControl, Button, {
            // Overriding the setParent method.
            setParent: function (parent) {
                CounterControl.superclass.setParent.call(this, parent);
                if (parent) {
                    if (!this._mapEventListener) {
                        this._mapEventListener =
                            this.getMap().geoObjects.events.group();
                        this._mapEventListener.add(
                            ["add", "remove"],
                            this._refresh,
                            this
                        );
                    }
                    this._refresh();
                } else if (this._mapEventListener) {
                    this._mapEventListener.removeAll();
                }
            },

            _refresh: function () {
                this.data.set(
                    "placemark_count",
                    this.getMap().geoObjects.getLength()
                );
            },
        });

        provide(CounterControl);
    }
);

// Map initialization.
ymaps.ready(function () {
    var myMap = new ymaps.Map("map", {
        center: [55.734046, 37.588628],
        zoom: 7,
        controls: [],
    });

    // Requesting our custom control in the module system.
    ymaps.modules
        .require(["plugin.PlacemarkCounterControl"])
        .spread(function (PlacemarkCounterControl) {
            // Creating an instance of your custom button and adding it to the map.
            myMap.controls.add(new PlacemarkCounterControl());
        });
    // Creating a button that we use for adding placemarks to the map.
    var addPlacemarkButton = new ymaps.control.Button({
        data: { content: "Add a placemark" },
        options: { maxWidth: 200, float: "right", selectOnClick: false },
    });
    myMap.controls.add(addPlacemarkButton);

    // Adding a placemark by clicking randomly.
    addPlacemarkButton.events.add("click", function () {
        var center = myMap.getCenter();
        center[0] += Math.random() * 2 - 1;
        center[1] += Math.random() * 2 - 1;
        myMap.geoObjects.add(new ymaps.Placemark(center));
    });
});