Stop window.Retool.modelUpdate from refreshing the custom component

Hi, I have a custom pivot table in a custom component

When I used window.Retool.modelUpdate to pass the data out to javascript query to do processing, it refreshes the whole pivot table and cause the filtering to be back to initial.

How can we stop it from refreshing when we call window.Retool.modelUpdate

1 Like

Hey @Budder! I'm not sure you'll be able to stop the component from refreshing... Does it work for you to include filter settings in your model and pass your current filters along when you call .modelUpdate?

Yeah there's another way I have to do it and I need to reload the filters again once it's refreshed which is quite tedious. But if there's no other way out, then I guess I just have to use it this way

Was there any update on this?
I have a mapbox component where I want to use modelUpdate to return the selected country code, but each time the component does this it refreshes the map

Hey @DavidM, I don't believe there's been any update. Could you share your Custom Component code? With that, we can see if it's possible to change things up to work around this!

Hi Everett,

Thanks for getting back to me.

We want to use a map with colour overlays to show per data country, but then show the details in a separate table when a country is clicked.

So I use the modelUpdate method to pass the clicked country back to retool

        window.Retool.modelUpdate({ sel_country_iso3: country.iso_3166_1_alpha_3 });

This works and I can then use the value for querying the data; however as this updates the same model that's used for the input to the custom component it causes the whole map to refresh

Model

{ 
  data: {{map_data.value}},
  sel_country_iso3: 'AUT',
  map_center: [10,50],
  map_zoom: 2
}

HTML:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Join local JSON data with vector tile geometries</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<link href="https://api.mapbox.com/mapbox-gl-js/v2.13.0/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v2.13.0/mapbox-gl.js"></script>
<style>
body { margin: 0; padding: 0; }
  
#map canvas {
cursor: crosshair;
}
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<div id="map"></div>

<script>


window.Retool.subscribe(function(model) {
  
  
  // TO MAKE THE MAP APPEAR YOU MUST
  // ADD YOUR ACCESS TOKEN FROM
  // https://account.mapbox.com
  mapboxgl.accessToken = '####';

  const map = new mapboxgl.Map({
        container: 'map',
        // Choose from Mapbox's core styles, or make your own style with Mapbox Studio
        style: 'mapbox://styles/mapbox/light-v11',  //light-v11 Globe / light-v10 Projection / outdoors-v12 satellite-streets-v12
        //Workaround for retool refreshing updating the data model
        //Center and zoom are stored in the model
        center: model.map_center,
        zoom: model.map_zoom

    });

 
    map.on('load', () => {

        // Add source for country polygons using the Mapbox Countries tileset
        // The polygons contain an ISO 3166 alpha-3 code which can be used to for joining the data
        // https://docs.mapbox.com/vector-tiles/reference/mapbox-countries-v1
        map.addSource('countries', {
            type: 'vector',
            url: 'mapbox://mapbox.country-boundaries-v1'
        });

        // Build a GL match expression that defines the color for every vector tile feature
        // Use the ISO 3166-1 alpha 3 code as the lookup key for the country shape
        const matchExpressionColor = ['match', ['get', 'iso_3166_1_alpha_3']];

        // Calculate color values for each country based on 'hdi' value
        for (const row of model.data) {
            // Convert the range of data values to a suitable color
          const saturation = row['saturation'];
          const hue = row['hue'];
          const color = `hsl(${hue}, ${saturation}, 50%)`;
          matchExpressionColor.push(row['country_iso'], color);

        }

        // Last value is the default, used where there is no data
        matchExpressionColor.push('rgba(0, 0, 0, 0)');


        // The mapbox.country-boundaries-v1 tileset includes multiple polygons for some
        // countries with disputed borders.  The following expression filters the
        // map view to show the "US" perspective of borders for disputed countries.
        // Other world views are available, for more details, see the documentation
        // on the "worldview" feature property at
        // https://docs.mapbox.com/data/tilesets/reference/mapbox-countries-v1/#--polygon---worldview-text
        const WORLDVIEW = "US";
        const worldview_filter = [ "all",  [ "any", [ "==", "all", ["get", "worldview"] ], [ "in", WORLDVIEW, ["get", "worldview"] ] ] ];

        // Add layer from the vector tile source to create the choropleth
        // Insert it below the 'admin-1-boundary-bg' layer in the style
        map.addLayer(
            {
                'id': 'countries-join',
                'type': 'fill',
                'source': 'countries',
                'source-layer': 'country_boundaries',
                'paint': {
                    'fill-color': matchExpressionColor,
                    'fill-opacity': 0.5
                },
                 'metadata' :{
            //      'color-val': matchExpressionColor,
                  'hello': 'World'
                },
                'filter': worldview_filter
            },
            'admin-1-boundary-bg'
        );

        map.on('mouseover', 'countries-join', function (e) {
          // Change the cursor style as a UI indicator.
          map.getCanvas().style.cursor = 'pointer';
        });

       map.on('click', (e) => {
       
        var feat = map.queryRenderedFeatures(e.point, { layers: ['countries-join'] });

        var country = feat[0].properties;
      //  var meta = feat[0].layer.metadata;
          
        // Fix for Kosovo ISO in Mapbox data
       // country.find(e => e.iso_3166_1_alpha_3 === 'XKS').iso_3166_1_alpha_3 = 'XKX';
      
        window.Retool.modelUpdate({ sel_country_iso3: country.iso_3166_1_alpha_3 });
        //Workaround to store the current view as the above causes retool to refresh
        window.Retool.modelUpdate({ map_center:  map.getCenter() });
        window.Retool.modelUpdate({ map_zoom: map.getZoom() });
       });

    });
  })

</script>

</body>
</html>

Example Map data for setting colours:

[
  {
    "country_iso": "ABW",
    "hue": 180,
    "saturation": 0.179
  },
  {
    "country_iso": "AFG",
    "hue": 180,
    "saturation": 0.463
  },
  {
    "country_iso": "AGO",
    "hue": 120,
    "saturation": 0.132
  },
  {
    "country_iso": "AIA",
    "hue": 180,
    "saturation": 0.280
  },
  {
    "country_iso": "ALB",
    "hue": 180,
    "saturation": 1.209
  },
  {
    "country_iso": "AND",
    "hue": 0,
    "saturation": 0.100
  },
  {
    "country_iso": "ARE",
    "hue": 240,
    "saturation": 0.174
  },
  {
    "country_iso": "ARG",
    "hue": 180,
    "saturation": 0.505
  },
  {
    "country_iso": "ARM",
    "hue": 180,
    "saturation": 0.497
  },
  {
    "country_iso": "ATG",
    "hue": 180,
    "saturation": 0.295
  },
  {
    "country_iso": "AUS",
    "hue": 180,
    "saturation": 0.226
  },
  {
    "country_iso": "AUT",
    "hue": 240,
    "saturation": 1.605
  },
  {
    "country_iso": "AZE",
    "hue": 180,
    "saturation": 0.654
  }
]

Hey just want to chime back in here and say that there's no update yet. We have a couple internal feature requests open that we can report back here on which would make transferring data from custom components back to your app easier. In the meantime, though, you may have to continue using workarounds that let you save the component's state in its model.

Thanks for posting yours as an example @DavidM! Sorry to not have a better answer for you.

1 Like