#Updating a Leflet map in a custom widget based on data in a query.

1 messages · Page 1 of 1 (latest)

humble belfry
#

Im trying to build a custom widget with the leaflet API.

I have a Snowflake DB with some data. I query that in a query called get_lic.

select distinct
    l.callsign,
    l.license_key,
    l.licensee_name,
    st_asgeojson(l.license_area) as geojson_column,
    l.status
from license as l
join frequency_range f on l.license_key = f.license_key
where 
    f.start_frequency >= {{freqSlider.start}}
    and f.end_frequency <= {{freqSlider.end}}
order by callsign 
limit 800;

This query has the "Run query on page load" setting toggled to true.

The idea is that the page should load, this query should be run (based on the default values set for the freqSlider), the results returned should populate my table, and in turn, the Custom widget leaflet map should display the data as it is in my table.

The Default Model in my Custom Widget is set up to pass in the licenseTable.tableData.

But my problems I'm having so far are these:

  1. When the page loads, for some reason, the query does not run unless I turn on "Request confirmation before running query", in which case, the modal for that option pops up, and if I click yes, the query runs fine.
    1.a. I think this may have something to do with the fact that get_lic depends on the default values set in the freqSlider, which themselves are retrieved dynamically using a different query that sets maximum and minimum default values (see attached image). If I hard code these values, the query runs fine, but I wish I could set max and min dynamically.
  2. Even if the query does run, on page load or otherwise, the Leaflet app in the Custom Widget does not display the data. The only way I can get the Widget to display the data in my table is by clicking into the "Edit Source" on the Custom Widget, and re-running the JS from within.

Any help would be appreciated. If @patent jewel you have any advice, I would greatly appreciate it - your FTW video on leaflet has been tremendously helpful so far 🙂 Thanks!

edgy mortarBOT
#

Hello! I'm AppsmithBot, here to assist you with your Appsmith queries.

  1. Query Not Running on Page Load: It seems like the issue might be related to the dynamic values of freqSlider. Ensure that the query fetching these values is set to run before get_lic. You can control the execution order by using a JSObject to manage the sequence of query executions. Here's a basic example:

export default {
async initializePage() {
await fetchSliderDefaults.run();
await get_lic.run();
}
}

Set initializePage to run on page load?5:0?Appsmith Documentation.md?.

  1. Leaflet Map Not Displaying Data: Ensure that your Custom Widget is correctly set up to receive data from licenseTable.tableData. Use appsmith.onModelChange to update the map whenever the data changes:

appsmith.onModelChange(() => {
const data = appsmith.model.licenseTableData;
// Code to update the Leaflet map with new data
});

Make sure the Default model property of your Custom Widget is bound to ** {?{ licenseTable.tableData }?} **?5:7?Appsmith Documentation.md?.

  1. Dynamic Default Values for freqSlider: If you want to set these dynamically, ensure that the query fetching these values is executed first and that the freqSlider is updated accordingly. You can use the storeValue function to store these values and bind them to the freqSlider properties.

If you continue to face issues, please let me know!

If you don't find my response helpful, you can request to speak to a human agent.

humble belfry
#

The JS for the Custom Widget, from the attached image:

appsmith.onReady(() => {
    // Initialize the map with a temporary view (it will be updated dynamically)
    var map = L.map('map').setView([0, 0], 2);

    // Set the tile layer
    L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
        maxZoom: 19,
        attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
    }).addTo(map);

    // Get the query output
    const geojsonData = appsmith.model.query;
    
    const allBounds = [];

    geojsonData.forEach(row => {
        try {
            // Parse the GeoJSON string into an object
            const geojsonObject = JSON.parse(row.GEOJSON_COLUMN);

            // Extract Callsign and License Key (replace with correct column names if necessary)
            const callsign = row.CALLSIGN || "Unknown Callsign";
            const licenseKey = row.LICENSE_KEY || "Unknown License Key";

            // Create popup content
            const popupContent = `
                <b>Callsign:</b> ${callsign}<br>
                <b>License Key:</b> ${licenseKey}
            `;

            // Add the GeoJSON object to the map
            const layer = L.geoJSON(geojsonObject, {
                onEachFeature: function (feature, layer) {
                    // Bind the popup to the polygon
                    layer.bindPopup(popupContent);
                }
            }).addTo(map);

            // Store the bounds for fitting the map view
            allBounds.push(layer.getBounds());
        } catch (e) {
            console.error("Failed to parse GeoJSON:", row.GEOJSON_COLUMN, e);
        }
    });

    // Fit the map view to show all polygons
    if (allBounds.length > 0) {
        const combinedBounds = allBounds.reduce((acc, bounds) => acc.extend(bounds), L.latLngBounds());
        map.fitBounds(combinedBounds);
    } else {
        console.warn("No valid GeoJSON polygons found to fit on the map.");
    }
});
edgy mortarBOT
#

To ensure your Custom Widget with Leaflet is working correctly, let's address a few key points:

  1. Ensure Data Binding: Make sure that appsmith.model.query is correctly bound to the data from your get_lic query. If licenseTable.tableData is the source, ensure that the Custom Widget's Default model is set to ** {?{ licenseTable.tableData }?} **.

  2. Check Data Structure: Verify that the data structure of geojsonData matches what your code expects. Specifically, ensure that row.GEOJSON_COLUMN, row.CALLSIGN, and row.LICENSE_KEY are correctly named and exist in the data returned by your query.

  3. Debugging: Add console logs to check if the data is being received correctly:

console.log("GeoJSON Data:", geojsonData);

This will help you verify if the data is being passed correctly to the widget.

  1. Error Handling: Ensure that the GeoJSON data is valid. If there's an error in parsing, it will be caught by the try-catch block, but you should also check the console for any errors logged.

  2. Map Initialization: Ensure that the map container ('map') exists in your Custom Widget's HTML. If the map is not displaying, it might be due to the container not being correctly set up.

  3. Dynamic Updates: If the map does not update automatically when the data changes, ensure that appsmith.onModelChange is used to re-run the map initialization code whenever the data changes.

If these steps do not resolve the issue, please provide more details about any errors you see in the console or any additional context that might help diagnose the problem.

If you don't find my response helpful, you can request to speak to a human agent.

humble belfry
#

@edgy mortar The bot message was great for my freqSlider issue - I'll try that out, but the rest of my query might require a human agent

edgy mortarBOT
#

Someone from our team will reach out to you on this thread. In the meantime, you can have a look at our documentation to try & resolve your query https://docs.appsmith.com?utm=bot

Organizations build internal applications such as dashboards, database GUIs, admin panels, approval apps, customer support tools, etc. to help improve their business operations. Appsmith is an open-source developer tool that enables the rapid development of these applications. You can drag and drop pre-built widgets to build UI. Connect securely...

edgy mortarBOT
#

Hello! Please try using the onModelChange function. It allows you to register a handler function, which will be called whenever there is a change in the model, either from the platform or from within the custom widget.

While Appsmith provides an extensive array of built-in widgets for application development, there are instances where your project demands a widget tailored to specific requirements. Appsmith's Custom widget allows you to integrate unique functionalities with your HTML, CSS, and JavaScript code for additional functionality.

humble belfry
#

I've seen this page and that function. Is there an example somewhere of it being implemented correctly?

humble belfry
#

From the resources I could find online, the examples all seem to follow a similar path.

//define some set of functionality 
function doThing(){}

//use onReady to wait for the appsmith app to start up before loading the widget and calling our function 
appsmith.onReady(doThing);

//then wrap the same exact functionality in onModelChange to wait for changes to the data passed through the "Default Model"
appsmith.onModelChange(() => {

  //include some line like this to prevent errors when loading the widget the first time
  if(!appsmith.model.someKey){return}  
  
  // call the same fn
  doThing(); 
});

According to these examples (below), unless Im misunderstanding, implementing these steps in my own widget should allow the widget to listen for changes to the default model (like different results coming from a parameterized query), and use that data to update the widget (the leaflet map in my case).

As it is now, changing the data in the Default Model is seen from within the Custom Widget editor, and the map updates as expected. But nothing happens in the UI side in the overall appsmith editor.

https://community.appsmith.com/content/guide/building-custom-list-widget-drag-and-drop-reordering
https://community.appsmith.com/content/blog/generating-organizational-chart-airtable-data

Am I misunderstanding and using onModelChange incorrectly? Am I close?

Appsmith Community Portal

Displaying an array of data in Appsmith can easily be done with a Table or List widget.

Appsmith Community Portal

Organizational charts are used to visualize the reporting structure of employees in a tree-like g

edgy mortarBOT
#

Can you share your implementation using onModelChange so we can debug on our end? Alternatively you can invite [email protected] as a developer to your app and we can take a closer look directly.

humble belfry
#

I actually found a solution to this one. Thank you though