didInsertElement deprecation in 1.13, how to init plugins now?


#1

In 1.13 there is a deprecation warning if you try to set any property from within the didInsertElement hook. Ok, simple enough for some fixes. However some things are “seemingly” impossible to replace. How would i go about removing the deprecation on this?

    initMap: function(){
        var map = new google.maps.Map(this.$().children('.map-canvas')[0], this.getMapOptions());
        this.set('map',map);
    }.on('didInsertElement'),

I can’t set the map property until the element has been inserted in the DOM.


#2

It’s unclear how you’re using the map prop. Can you post your template and component?

If you want to get rid of the deprecation and can push the re-render to the next runloop, you can do this:

didInsertElement: function() {
  this._super.apply(this, arguments);
  Ember.run.scheduleOnce('afterRender', this, function() {
    var googleMap = new google.maps.Map(this.$().children('.map-canvas')[0], this.getMapOptions());
    this.set('map', googleMap);
  });
}

#3

The map prop is essential to triggering sub components adding markers to the map. It is passed around and observed for initialization. It is also used inside the component to observe and trigger updates to and from ember properties.

I would love to initialize it before the didInsertElement hook as it effectively causes a second event chain to run but google maps won’t let you instantiate the object without an element to attach to.

Here’s the rest of the template and necessary parts of the component.

<div class="map-canvas"></div>

{{#portal.track.map.marker-clusterer map=map minimumClusterSize=locationClusterDensity as |locationClusterer|}}
    {{#portal.track.map.marker-spiderfier map=map markerClicked='onLocationMarkerClicked' as |locationSpiderfier|}}
        {{#each locations as |location|}}
            {{portal.track.map.marker.marker-location
                map=map
                location=location
                locationConfigArray=config.locationConfigArray
                markerAction='onLocationMarkerAction'
                isEditing=(eq location.id locationEditId)
                clusterer=locationClusterer
                spiderfier=locationSpiderfier
            }}
        {{/each}}
    {{/portal.track.map.marker-spiderfier}}
{{/portal.track.map.marker-clusterer}}
/**
    * Contains the mappings between properties that exist in the map object and properties
    * that exist in the ember object that need to be mapped together. This is used to initialize the property mixin
    */
    googlePropertyMap: [
        { event: 'center_changed', property: 'center', getFunc: 'getCenter', setFunc: 'setCenter' },
        { event: 'heading_changed', property: 'config.heading', getFunc: 'getHeading', setFunc: 'setHeading' },
        { event: 'zoom_changed', property: 'config.zoom', getFunc: 'getZoom', setFunc: 'setZoom' },
        { event: 'maptypeid_changed', property: 'config.mapTypeId', getFunc: 'getMapTypeId', setFunc: 'setMapTypeId'},
        { event: 'rightclick', eFunc: 'contextMenuOpen'},
    ],

    /**
     * This is used to initialize the property mixin.
     */
    googlePropertyObject: Ember.computed.alias('map'),

I’ll give the afterRender schedule a try but i really can’t afford too much lag involved as its just the beginning of a much larger chain of events that occur.


#4

For future reference i was able to get around it with a lucky feature of google maps. Google maps requires that it has a node to attach to but it doesn’t require that the node actually be attached to the DOM at the time of initialization.

So i was able to do.

 /**
     * Main initialization for the map object. This is the main entry-point for the map code
     * It must be run before the rest of the code. It creates a DOM element the map will be
     * attached to and then instantiates the map against that new node. It then saves the
     * node for latter insertion once this components element is determined.
     */
    initMap: function(){
        // Create the node
        var node = document.createElement("div");
        $(node).addClass('map-canvas');

        // Create the map
        var map = new google.maps.Map(node, this.getMapOptions());
        this.set('map',map);
        this.set('mapNode', node);
    }.on('init'),

    /**
     * This takes the `mapNode` from the initialization process and places it inside the
     * this components element. This completes the bootstrapping of the map.
     */
    attachMap: function(){
        this.$().prepend(this.get('mapNode'));
    }.on('didInsertElement'),