As some of you can tell I have been diving deep into liveview and particularlly the integration with JS via hooks. So far most of it makes sense and I have been really impressed by just how easy it is to get data into the DOM and update efficiently. I have one very strange problem where anytime updated() is called in my JS hook, my JS map shifts on the page and the text on the lower right corner gets bigger. I created a fresh liveview app to reproduce the issue and it still happens, all I need in my updated() call is a console.log(“test”) so that I know it is triggered, there is nothing else in there and the map shift still occurs.
Below I will detail the steps I used to build a fresh app and get a map up and running using hooks. Everything works perfectly, I can send data properly into the updated() call as well, its just this weird shift of the map is occurring right when updated() is called. Sorry this is a bit hard to reproduce as you need a mapboxgl key to get the map up but I did my best to show the steps below.
This app displays a map and whenever a location is clicked, that longitude and latitude are sent as params to the handle_event on the server, which then update the test field in the assigns, which then triggers updated() as the map div takes data-test.
Create a new app with liveview
mix phx.new mapping --live
Install mapboxgl
cd assets
npm install --save mapbox-gl
Add mapboxgl required css to root template (root.html.leex)
<link href='https://api.mapbox.com/mapbox-gl-js/v1.11.0/mapbox-gl.css' rel='stylesheet' />
Add some width/height css for the map div
#map {
width: 800px;
height: 600px;
}
page_live.ex
defmodule MappingWeb.PageLive do
use MappingWeb, :live_view
def mount(_params, _session, socket) do
{:ok, assign(socket, test: [])}
end
def handle_event("map_click",
%{"location" => %{"lat" => latitude, "lng" => longitude}},
socket) do
{:noreply, assign(socket, test: %{latitude: latitude, longitude: longitude})}
end
end
page_live.html.leex
<div id="map" phx-hook="Map" data-test="<%= Jason.encode!(@test) %>" phx-update="ignore"></div>
Add in the Hook in the apps.js file
import "phoenix_html"
import { Socket } from "phoenix"
import NProgress from "nprogress"
import { LiveSocket } from "phoenix_live_view"
import mapboxgl from 'mapbox-gl';
let Hooks = {}
Hooks.Map = {
mounted() {
mapboxgl.accessToken = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/outdoors-v11', // stylesheet location
center: [-122.4376, 37.7577],
zoom: 8
});
const view = this;
map.on('click', function (e) {
view.pushEvent("map_click", { location: e.lngLat })
});
},
updated() {
console.log("UPDATED")
}
}
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
let liveSocket = new LiveSocket("/live", Socket, { params: { _csrf_token: csrfToken }, hooks: Hooks })