Hi,
I was just throwing this out there to see if anybody had been able to successfully embed the mapbox js library inside a custom widget inside SAC?
I can load the library ok but when I instantiate the map through the constructor it fails to find the div which is defined at the beginning?
I was wondering if anybody had been able to successfully do this?
This is the Javascript I am using...
(function () {
let template = document.createElement("template");
template.innerHTML = `
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<link rel="stylesheet" href="https://api.mapbox.com/mapbox-gl-js/v2.10.0/mapbox-gl.css">
<style>
#map {
width: 100%;
height:100%;
}
</style>
<div id='map'></div>
`;
class Map extends HTMLElement {
constructor() {
super();
this.appendChild(template.content.cloneNode(true));
this._props = {};
let that = this;
mapboxgl.accessToken = "OUR MAPBOX TOKEN";
that._map = new mapboxgl.Map({
container: "map",
style: 'mapbox://styles/mapbox/streets-v11',
center: [-74.5, 40],
zoom: 9
});
}
onCustomWidgetBeforeUpdate(changedProperties) {
this._props = { ...this._props, ...changedProperties };
}
onCustomWidgetAfterUpdate(changedProperties) {
}
}
let scriptSrc = "https://api.mapbox.com/mapbox-gl-js/v2.10.0/mapbox-gl.js";
let onScriptLoaded = function () {
customElements.define("com-test-map", Map);
}
let customElementScripts = window.sessionStorage.getItem("customElementScripts") || [];
let scriptStatus = customElementScripts.find(function (element) {
return element.src == scriptSrc;
});
if (scriptStatus) {
if (scriptStatus.status == "ready") {
onScriptLoaded();
} else {
scriptStatus.callbacks.push(onScriptLoaded);
}
} else {
let scriptObject = {
"src": scriptSrc,
"status": "loading",
"callbacks": [onScriptLoaded]
}
customElementScripts.push(scriptObject);
var script = document.createElement("script");
script.type = "text/javascript";
script.src = scriptSrc;
script.onload = function () {
scriptObject.status = "ready";
scriptObject.callbacks.forEach((callbackFn) => callbackFn.call());
};
document.head.appendChild(script);
}
})();
Request clarification before answering.
I assume mapbox tries to find the target div by something like document.getElementById("map"). However at this point in time your custom element was not added to the DOM (see https://help.sap.com/docs/SAP_ANALYTICS_CLOUD/0ac8c6754ff84605a4372468d002f2bf/8b4c4c845b6643879e1bf.... You should defer the creation of the map to "connectedCallback" which is the point in time where the custom element was added to the DOM. You can check by calling getElementById from your constructor.
Also, do you want to allow your users to place more than one instance of this widget in an app 😉 ? If yes you should either give your map div a unique ID or use a shadow root (depends on whether mapbox supports this).
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You definitely put me on the right path Bob - thankyou very much...
(function () {
let template = document.createElement("template");
template.innerHTML = `
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<link rel="stylesheet" href="https://api.mapbox.com/mapbox-gl-js/v2.10.0/mapbox-gl.css">
<style>
#map{
width: 100%;
height:100%;
}
</style>
<div id='map'></div>
`;
class Map extends HTMLElement {
constructor() {
debugger
super();
this._shadowRoot = this.attachShadow({ mode: "open" });
this.appendChild(template.content.cloneNode(true));
this._props = {};
this._firstConnection = false;
//let that = this;
}
connectedCallback() {
this._firstConnection = true;
mapboxgl.accessToken = "THE TOKEN";
this._map = new mapboxgl.Map({
container: "map",
style: 'mapbox://styles/mapbox/streets-v11',
center: [-74.5, 40],
zoom: 9
});
}
onCustomWidgetBeforeUpdate(changedProperties) {
this._props = { ...this._props, ...changedProperties };
}
onCustomWidgetAfterUpdate(changedProperties) {
}
}
let scriptSrc = "https://api.mapbox.com/mapbox-gl-js/v2.10.0/mapbox-gl.js";
let onScriptLoaded = function () {
customElements.define("com-test-map", Map);
}
//SHARED FUNCTION: reuse between widgets
//function(src, callback) {
let customElementScripts = window.sessionStorage.getItem("customElementScripts") || [];
let scriptStatus = customElementScripts.find(function (element) {
return element.src == scriptSrc;
});
if (scriptStatus) {
if (scriptStatus.status == "ready") {
onScriptLoaded();
// console.log("SCRIPT IS LOADED");
} else {
// console.log("SCRIPT NOT LOADED");
scriptStatus.callbacks.push(onScriptLoaded);
}
} else {
// debugger
let scriptObject = {
"src": scriptSrc,
"status": "loading",
"callbacks": [onScriptLoaded]
}
customElementScripts.push(scriptObject);
var script = document.createElement("script");
script.type = "text/javascript";
script.src = scriptSrc;
script.onload = function () {
scriptObject.status = "ready";
scriptObject.callbacks.forEach((callbackFn) => callbackFn.call());
};
document.head.appendChild(script);
}
// }, false);
})();
Thanks for this Bob - I did initially try a document.getElementById("map") which returned a null inside the constructor so that rings true.
I had a look at the doc but I could do with an example of where and how to implement connectedCallback if possible?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
| User | Count |
|---|---|
| 5 | |
| 5 | |
| 4 | |
| 4 | |
| 2 | |
| 2 | |
| 2 | |
| 2 | |
| 1 | |
| 1 |
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.