Understanding Elements

Note: This guide is under complete restructuring. We will provide a new documentation in the Contributing Guite in our Git-Repository:

https://github.com/mapbender/mapbender-starter/blob/release/3.0.6/CONTRIBUTING.md#elements.

Parts of an Elements

PHP Class

TODO

Twig Template

Every Element must have an HTML element it is represented by. In the most basic case, this can be a simple DIV element, but this can be complex as needed.

For HTML generation Mapbender3 uses Twig. A minimal twig template for an element would like this:

<div id="{{ id }}" class="mb-element mb-element-myclass"></div>

As you can see you need to set the id (generated by Mapbender) as well as the general mb-element class and a class specifically for your element.

JavaScript Widgets

Element widgets are build using the jQuery UI widget factory. This ensures a common pattern for widget development and offers

  • default options.
  • constructors and (optional) destructors.
  • private and public methods.

The basic skeleton looks like this:

(function($) {

// This is the widget factory. It will create an widget class "mbMyClass" in the jQuery object as well as an
// "mbMyClass" object in the "mapbender" namespace in the jQuery object (they are used differently). Be sure
// to use the "mb" prefix for your widget name as not to overwrite existing jQuery functions.
$.widget('mapbender.mbMyClass', {
    // This sets up the default options which can be overriden in the Mapbender configuration.
    // This will be moved into the PHP class at a later point.
    // The final options object can be accessed as "this.options".
    options: {
        foo:    'bar',
        answer: 42
    },

    // This attribute is private for your widget.
    var1: null,

    // Constructor, gets called on widget initialization.
    _create: function() {
        // Do everything needed for set up here, for example event handling
        this.element.bind('mbmyclassmagicdone', $.proxy(this._onMagicDone, this));
        this.element.bind('click', $.proxy(this._clickCallback, this));
    },

    // Destructore, here set to the jQuery empty function
    destroy: $.noop,

    // Public function, callable like "$('#element-13').mbMyClass('methodA', parameterA, parameterB)"
    methodA: function(parameterA, parameterB) {
        this._methodB(parameterA);
    },

    // Private function, only callable from within this widget
    _methodB: function(parameterA) {
        // The triggered signal will be named "mbmyclassmagicdone" (all lowercase)
        this._trigger('magicdone');
    },

    _onMagicDone: function() {
        alert("Oh, magic!");
    },

    _clickCallback: function(event) {
        var target = $(event.target);
        var id = target.attr('id');
        // ...
    }

});

})(jQuery);

For event handling, jQuery.proxy is your friend to ensure that the callback is guaranteed to be executed in the right context:

// ...

this.element.click($.proxy(this._clickCallback, this));

// ...

This way, “this” inside the clickCallback method is the this given as the second parameter here (usually the widget instance) and not the HTML element which triggered the event. To access the HTML event, use the target property of the event passed as the argument to the clickCallback method.

Element to Element communication

There’s an active and an passive way to communicate with another widget. The first - active - way is to call a public method of the other widget. For that you need to select the widget’s HTML element with jQuery and call the method like this:

var otherElement = $('#element-13').mbMyClass('methodA', parameterA, parameterB);

This is standard jQuery UI stuff and pretty much self-explanatory. The more tricky question is how do you know the other’s HTML element? As you can see, using the id to select the element is preferred, but these ids are generated on the fly by Mapbender3 when the application is started, so you can’t assume that the id is the always the same. Luckily you can pass a Element id in the configuration as the target options for an Element. This will be replaced with the run-time id of that target Elements’ HTML element for you, so that in your widget code you can access the right id as “this.options.target”.

$('#' + this.options.target).mbMyClass('methodA', parameterA, parameterB);

The passive way for communication is to subscribe to events of another target. You also need to know the HTML element, but you can now listen for the other widget to call your widget. This is done using standard jQuery events. Well, almost standard jQuery events:

If you use the “_trigger” method provided by the jQuery UI widget factory