Fix JavaScript context binding issues in map component

- Fix "this.__view is undefined" error when calling pushEvent in event handlers
- Bind pushEvent context properly in all marker click and hover handlers
- Replace undefined sendBoundsToServer calls with saveMapState
- Ensure all event handlers check for pushEvent availability and type
- Use .bind(self) to preserve LiveView hook context in callbacks

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Graham McIntire 2025-07-18 15:05:15 -05:00
parent 468309c70d
commit 4af0f4a421
No known key found for this signature in database
6 changed files with 37 additions and 22 deletions

View file

@ -299,14 +299,16 @@ let MapAPRSMap = {
self.pushEvent("map_ready", {});
// Send initial bounds to trigger historical loading
console.log("Sending initial bounds to server");
self.sendBoundsToServer();
if (self.map && self.pushEvent && typeof self.pushEvent === 'function') {
saveMapState(self.map, self.pushEvent.bind(self));
}
// Also send update_map_state to ensure URL updates and bounds processing
// Increase delay to ensure LiveView is fully connected and ready
setTimeout(() => {
if (self.map && self.pushEvent && !self.isDestroyed) {
console.log("Sending initial update_map_state for historical loading");
saveMapState(self.map, (event: string, payload: BaseEventPayload) => self.pushEvent(event, payload));
saveMapState(self.map, self.pushEvent.bind(self));
}
}, 500);
} else {
@ -315,12 +317,14 @@ let MapAPRSMap = {
setTimeout(() => {
if (self.pushEvent && typeof self.pushEvent === 'function' && !self.isDestroyed) {
self.pushEvent("map_ready", {});
self.sendBoundsToServer();
if (self.map) {
saveMapState(self.map, self.pushEvent.bind(self));
}
// Also trigger map state update after a delay
setTimeout(() => {
if (self.map && self.pushEvent && !self.isDestroyed) {
console.log("Sending initial update_map_state for historical loading (retry path)");
saveMapState(self.map, (event: string, payload: BaseEventPayload) => self.pushEvent(event, payload));
saveMapState(self.map, self.pushEvent.bind(self));
}
}, 500);
}
@ -354,8 +358,8 @@ let MapAPRSMap = {
if (self.boundsTimer) clearTimeout(self.boundsTimer);
self.boundsTimer = setTimeout(() => {
if (self.map && !self.isDestroyed) {
saveMapState(self.map, (event: string, payload: any) => self.pushEvent(event, payload));
if (self.map && !self.isDestroyed && self.pushEvent && typeof self.pushEvent === 'function') {
saveMapState(self.map, self.pushEvent.bind(self));
}
}, 300);
};
@ -397,8 +401,8 @@ let MapAPRSMap = {
self.lastZoom = currentZoom;
// Save map state and update URL
if (self.map && !self.isDestroyed) {
saveMapState(self.map, (event: string, payload: any) => self.pushEvent(event, payload));
if (self.map && !self.isDestroyed && self.pushEvent && typeof self.pushEvent === 'function') {
saveMapState(self.map, self.pushEvent.bind(self));
}
}, 300);
};
@ -1228,12 +1232,15 @@ let MapAPRSMap = {
}
}
safePushEvent(self.pushEvent, "marker_clicked", {
id: data.id,
callsign: data.callsign,
lat: lat,
lng: lng,
});
// Use bound pushEvent function to preserve context
if (self.pushEvent && typeof self.pushEvent === 'function' && !self.isDestroyed) {
safePushEvent(self.pushEvent.bind(self), "marker_clicked", {
id: data.id,
callsign: data.callsign,
lat: lat,
lng: lng,
});
}
});
// Handle marker hover for RF path visualization
@ -1243,9 +1250,9 @@ let MapAPRSMap = {
marker.on("mouseover", () => {
console.log("Marker hover start for:", data.callsign);
// Check if LiveView is still connected before sending event
if (self.pushEvent && !self.isDestroyed) {
if (self.pushEvent && typeof self.pushEvent === 'function' && !self.isDestroyed) {
try {
self.pushEvent("marker_hover_start", {
self.pushEvent.call(self, "marker_hover_start", {
id: data.id,
callsign: data.callsign,
path: data.path,
@ -1263,9 +1270,9 @@ let MapAPRSMap = {
marker.on("mouseout", () => {
console.log("Marker hover end for:", data.callsign);
// Check if LiveView is still connected before sending event
if (self.pushEvent && !self.isDestroyed) {
if (self.pushEvent && typeof self.pushEvent === 'function' && !self.isDestroyed) {
try {
self.pushEvent("marker_hover_end", {
self.pushEvent.call(self, "marker_hover_end", {
id: data.id,
});
} catch (error) {

View file

@ -28,5 +28,11 @@ config :esbuild,
# of environment variables, is done on config/runtime.exs.
config :logger, level: :info
config :sentry,
dsn: "https://337ece4c07ff53c6719d900adfddd6e4@o4509627566063616.ingest.us.sentry.io/4509691336785920",
environment_name: Mix.env(),
enable_source_code_context: true,
root_source_code_paths: [File.cwd!()]
# Configures Swoosh API Client
config :swoosh, :api_client, Swoosh.ApiClient.Req

View file

@ -1,6 +1,7 @@
defmodule AprsmeWeb.Endpoint do
@moduledoc false
use Phoenix.Endpoint, otp_app: :aprsme
use Sentry.PlugCapture
# The session will be stored in the cookie and signed,
# this means its contents can be read but not tampered with.

View file

@ -3,8 +3,8 @@ defmodule AprsmeWeb.InfoLive.Show do
use AprsmeWeb, :live_view
use Gettext, backend: AprsmeWeb.Gettext
import Phoenix.HTML, only: [raw: 1]
import AprsmeWeb.Components.InfoMapComponent
import Phoenix.HTML, only: [raw: 1]
alias Aprsme.Callsign
alias Aprsme.EncodingUtils

View file

@ -34,7 +34,7 @@
else:
"#{AprsmeWeb.AprsSymbol.normalize_symbol_table(symbol_table)}#{AprsmeWeb.AprsSymbol.normalize_symbol_code(symbol_code)}" %>
<div title={display_symbol}>
<%= render_symbol_html(@packet) %>
{render_symbol_html(@packet)}
</div>
<% end %>
</div>
@ -349,7 +349,7 @@
else:
"#{AprsmeWeb.AprsSymbol.normalize_symbol_table(symbol_table)}#{AprsmeWeb.AprsSymbol.normalize_symbol_code(symbol_code)}" %>
<div title={display_symbol}>
<%= render_symbol_html(ssid_info.packet) %>
{render_symbol_html(ssid_info.packet)}
</div>
<% end %>
</div>
@ -452,7 +452,7 @@
else:
"#{AprsmeWeb.AprsSymbol.normalize_symbol_table(symbol_table)}#{AprsmeWeb.AprsSymbol.normalize_symbol_code(symbol_code)}" %>
<div title={display_symbol}>
<%= render_symbol_html(neighbor.packet) %>
{render_symbol_html(neighbor.packet)}
</div>
<% end %>
</div>

View file

@ -113,6 +113,7 @@ defmodule Aprsme.MixProject do
{:hammer, "~> 7.0"},
{:cachex, "~> 4.1"},
{:gettext_pseudolocalize, "~> 0.1"},
{:sentry, "~> 11.0"},
# Gleam dependencies
{:gleam_stdlib, ">= 0.60.0 and < 1.0.0", app: false, override: true},
{:gleeunit, "~> 1.0", only: [:dev, :test], runtime: false, app: false}