1

I have a series of CARTO.js four dataviews, but I want to manually get the data instead of listening to the 'dataChanged' event (when multiple datasets are created, this end in multiple errors). I tried using the getData

this.widgetFormula = new carto.dataview.Category(this.dataset, 'class', 
                    {operation: carto.operation.SUM, operationColumn: 'pavementlengthinfeet'});

client.addDataview(this.widgetFormula);

var xx = this.widgetFormula.getData();

but this returns an empty carto.dataview.categoryData object (a JSON object with the regular keys, but values empty). The online documentation doesn't provide an example to use the getData. Any idea?

1

You have to wait for the dataView to load. It provides a statusChanged event for this

this.widgetFormula.on('statusChanged', (status) => {
  if (status === 'loaded') {
    this.widgetFormula.getData(); // This should return data now
  }
});
  • Your code works, but this will work if I have 10 layers, each layer with 20 or 30 dataviews? I believe those dataviews works based on ajax calls, when multiple parallel calls are made, usually cartojs fails. This happens when you try to load several layers at the same time, all sorts of errors comes if you try to load more than 3 at the same time. My solution for that is to add the first layer to the client, when the promise returns the actual layer, then I add the second layer to the client and so on, until every layer is loaded. – BernieSF Aug 27 at 15:02
0

What it's needed is to manage properly how to get the data asynchronously. This is an example that's adding 10 layers, each one with 10 different dataviews:

<!DOCTYPE html>
<html>
  <head>
    <title>Single layer | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <!-- Include Leaflet -->
    <script src="https://unpkg.com/leaflet@1.5.1/dist/leaflet.js"></script>
    <link href="https://unpkg.com/leaflet@1.5.1/dist/leaflet.css" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://libs.cartocdn.com/carto.js/v4.1.11/carto.min.js"></script>
    <link href="https://fonts.googleapis.com/css?family=Montserrat:600" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>

    <script>
      const map = L.map('map').setView([30, 0], 3);
      map.scrollWheelZoom.disable();

      L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
        maxZoom: 18
      }).addTo(map);

      const client = new carto.Client({
        apiKey: 'default_public',
        username: 'cartojs-test'
      });

      const source1 = new carto.source.SQL('SELECT * from ne_10m_populated_places_simple WHERE adm0name=\'Spain\'');
      const source2 = new carto.source.SQL('SELECT * from ne_10m_populated_places_simple WHERE adm0name=\'Russia\'');
      const source3 = new carto.source.SQL('SELECT * from ne_10m_populated_places_simple WHERE adm0name=\'United States of America\'');
      const source4 = new carto.source.SQL('SELECT * from ne_10m_populated_places_simple WHERE adm0name=\'France\'');
      const source5 = new carto.source.SQL('SELECT * from ne_10m_populated_places_simple WHERE adm0name=\'Portugal\'');
      const source6 = new carto.source.SQL('SELECT * from ne_10m_populated_places_simple WHERE adm0name=\'Italy\'');
      const source7 = new carto.source.SQL('SELECT * from ne_10m_populated_places_simple WHERE adm0name=\'Germany\'');
      const source8 = new carto.source.SQL('SELECT * from ne_10m_populated_places_simple WHERE adm0name=\'Australia\'');
      const source9 = new carto.source.SQL('SELECT * from ne_10m_populated_places_simple WHERE adm0name=\'United Kingdom\'');
      const source10 = new carto.source.SQL('SELECT * from ne_10m_populated_places_simple WHERE adm0name=\'Ireland\'');

      const style1 = new carto.style.CartoCSS(`
        #layer {
          marker-fill: #A6CEE3;
        }
      `);

      const style2 = new carto.style.CartoCSS(`
        #layer {
          marker-fill: #1F78B4;
        }
      `);

      const style3 = new carto.style.CartoCSS(`
        #layer {
          marker-fill: #B2DF8A;
        }
      `);

      const style4 = new carto.style.CartoCSS(`
        #layer {
          marker-fill: #FB9A99;
        }
      `);

      const style5 = new carto.style.CartoCSS(`
        #layer {
          marker-fill: #E31A1C;
        }
      `);

      const style6 = new carto.style.CartoCSS(`
        #layer {
          marker-fill: #FDBF6F;
        }
      `);

      const style7 = new carto.style.CartoCSS(`
        #layer {
          marker-fill: #FF7F00;
        }
      `);

      const style8 = new carto.style.CartoCSS(`
        #layer {
          marker-fill: #FABADA;
        }
      `);

      const style9 = new carto.style.CartoCSS(`
        #layer {
          marker-fill: #C0FFEE;
        }
      `);

      const style10 = new carto.style.CartoCSS(`
        #layer {
          marker-fill: #00FFAA;
        }
      `);

      const layer1 = new carto.layer.Layer(source1, style1);
      const layer2 = new carto.layer.Layer(source2, style2);
      const layer3 = new carto.layer.Layer(source3, style3);
      const layer4 = new carto.layer.Layer(source4, style4);
      const layer5 = new carto.layer.Layer(source5, style5);
      const layer6 = new carto.layer.Layer(source6, style6);
      const layer7 = new carto.layer.Layer(source7, style7);
      const layer8 = new carto.layer.Layer(source8, style8);
      const layer9 = new carto.layer.Layer(source9, style9);
      const layer10 = new carto.layer.Layer(source10, style10);

      const sources = [
        source1,
        source2,
        source3,
        source4,
        source5,
        source6,
        source7,
        source8,
        source9,
        source10
      ];

      const dataViews = [
        (source) => {
          return new carto.dataview.Formula(source, 'pop_max', {
            operation: carto.operation.COUNT
          });
        },

        (source) => {
          return new carto.dataview.Formula(source, 'pop_max', {
            operation: carto.operation.SUM
          });
        },

        (source) => {
          return new carto.dataview.Formula(source, 'pop_max', {
            operation: carto.operation.AVG
          });
        },

        (source) => {
          return new carto.dataview.Formula(source, 'pop_max', {
            operation: carto.operation.MIN
          });
        },

        (source) => {
          return new carto.dataview.Formula(source, 'pop_max', {
            operation: carto.operation.MAX
          });
        },

        (source) => {
          return new carto.dataview.Category(source, 'adm0name', {
            limit: 10,
            operation: carto.operation.COUNT,
            operationColumn: 'pop_max'
          });
        },

        (source) => {
          return new carto.dataview.Category(source, 'adm0name', {
            limit: 10,
            operation: carto.operation.SUM,
            operationColumn: 'pop_max'
          });
        },

        (source) => {
          return new carto.dataview.Category(source, 'adm0name', {
            limit: 10,
            operation: carto.operation.AVG,
            operationColumn: 'pop_max'
          });
        },

        (source) => {
          return new carto.dataview.Category(source, 'adm0name', {
            limit: 10,
            operation: carto.operation.MIN,
            operationColumn: 'pop_max'
          });
        },

        (source) => {
          return new carto.dataview.Category(source, 'adm0name', {
            limit: 10,
            operation: carto.operation.MAX,
            operationColumn: 'pop_max'
          });
        }
      ]

      const dataViewsPromises = [];

      sources.forEach((source) => {
        dataViews.forEach((dataViewFn) => {
            const dataView = dataViewFn(source); 

            const dataViewPromise = new Promise((resolve, reject) => {
              client.addDataview(dataView);

              dataView.on('statusChanged', (status) => {
                if (status === 'loaded') {
                  resolve(dataView.getData());
                }
              });
            });

            dataViewsPromises.push(dataViewPromise);
        });
      });

      Promise.all(dataViewsPromises)
        .then((data) => {
          console.log('All dataviews loaded', data);
        });

      client.addLayer(layer1);
      client.addLayer(layer2);
      client.addLayer(layer3);
      client.addLayer(layer4);
      client.addLayer(layer5);
      client.addLayer(layer6);
      client.addLayer(layer7);
      client.addLayer(layer8);
      client.addLayer(layer9);
      client.addLayer(layer10);

      client.getLeafletLayer().addTo(map);
    </script>
  </body>
</html>

10 layers loaded with carto.js

  • this works perfectly when it is executed the first time. If a filter is added then a lot of 'statusChanged' events are fired and promises doesn't catch the upcoming data. – BernieSF Sep 5 at 20:20
  • This is because, for this case, you need to listen to another event. I'm attaching here another example that adds a filter after the data has loaded, and listens to this change in the next answer: – Elena Torró Sep 6 at 13:39
0

In this example, there's a button that triggers a change by adding a simple Range filter. The 'statusChanged' event is needed when the data is loaded the first time. The 'dataChanged' event, once the data has been loaded. This is all explained in the guides and reference https://carto.com/developers/carto-js/reference

<!DOCTYPE html>
<html>
  <head>
    <title>Single layer | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <!-- Include Leaflet -->
    <script src="https://unpkg.com/leaflet@1.5.1/dist/leaflet.js"></script>
    <link href="https://unpkg.com/leaflet@1.5.1/dist/leaflet.css" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://libs.cartocdn.com/carto.js/v4.1.11/carto.min.js"></script>
    <link href="https://fonts.googleapis.com/css?family=Montserrat:600" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">

    <style>
      #button-js {
        position: absolute;
        top: 20px;
        right: 20px;
        font-size: 24px;
        z-index: 10;
      }
    </style>
  </head>
  <body>
    <button id="button-js">Reload Source</button>
    <div id="map"></div>

    <script>
      const map = L.map('map').setView([30, 0], 3);
      map.scrollWheelZoom.disable();

      L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
        maxZoom: 18
      }).addTo(map);

      const client = new carto.Client({
        apiKey: 'default_public',
        username: 'cartojs-test'
      });

      const source1 = new carto.source.SQL('SELECT * from ne_10m_populated_places_simple WHERE adm0name=\'Spain\'');
      const source2 = new carto.source.SQL('SELECT * from ne_10m_populated_places_simple WHERE adm0name=\'Russia\'');
      const source3 = new carto.source.SQL('SELECT * from ne_10m_populated_places_simple WHERE adm0name=\'United States of America\'');
      const source4 = new carto.source.SQL('SELECT * from ne_10m_populated_places_simple WHERE adm0name=\'France\'');
      const source5 = new carto.source.SQL('SELECT * from ne_10m_populated_places_simple WHERE adm0name=\'Portugal\'');
      const source6 = new carto.source.SQL('SELECT * from ne_10m_populated_places_simple WHERE adm0name=\'Italy\'');
      const source7 = new carto.source.SQL('SELECT * from ne_10m_populated_places_simple WHERE adm0name=\'Germany\'');
      const source8 = new carto.source.SQL('SELECT * from ne_10m_populated_places_simple WHERE adm0name=\'Australia\'');
      const source9 = new carto.source.SQL('SELECT * from ne_10m_populated_places_simple WHERE adm0name=\'United Kingdom\'');
      const source10 = new carto.source.SQL('SELECT * from ne_10m_populated_places_simple WHERE adm0name=\'Ireland\'');

      const style1 = new carto.style.CartoCSS(`
        #layer {
          marker-fill: #A6CEE3;
        }
      `);

      const style2 = new carto.style.CartoCSS(`
        #layer {
          marker-fill: #1F78B4;
        }
      `);

      const style3 = new carto.style.CartoCSS(`
        #layer {
          marker-fill: #B2DF8A;
        }
      `);

      const style4 = new carto.style.CartoCSS(`
        #layer {
          marker-fill: #FB9A99;
        }
      `);

      const style5 = new carto.style.CartoCSS(`
        #layer {
          marker-fill: #E31A1C;
        }
      `);

      const style6 = new carto.style.CartoCSS(`
        #layer {
          marker-fill: #FDBF6F;
        }
      `);

      const style7 = new carto.style.CartoCSS(`
        #layer {
          marker-fill: #FF7F00;
        }
      `);

      const style8 = new carto.style.CartoCSS(`
        #layer {
          marker-fill: #FABADA;
        }
      `);

      const style9 = new carto.style.CartoCSS(`
        #layer {
          marker-fill: #C0FFEE;
        }
      `);

      const style10 = new carto.style.CartoCSS(`
        #layer {
          marker-fill: #00FFAA;
        }
      `);

      const layer1 = new carto.layer.Layer(source1, style1);
      const layer2 = new carto.layer.Layer(source2, style2);
      const layer3 = new carto.layer.Layer(source3, style3);
      const layer4 = new carto.layer.Layer(source4, style4);
      const layer5 = new carto.layer.Layer(source5, style5);
      const layer6 = new carto.layer.Layer(source6, style6);
      const layer7 = new carto.layer.Layer(source7, style7);
      const layer8 = new carto.layer.Layer(source8, style8);
      const layer9 = new carto.layer.Layer(source9, style9);
      const layer10 = new carto.layer.Layer(source10, style10);

      const sources = [
        source1,
        source2,
        source3,
        source4,
        source5,
        source6,
        source7,
        source8,
        source9,
        source10
      ];

      const dataViews = [
        (source) => {
          return new carto.dataview.Formula(source, 'pop_max', {
            operation: carto.operation.COUNT
          });
        },

        (source) => {
          return new carto.dataview.Formula(source, 'pop_max', {
            operation: carto.operation.SUM
          });
        },

        (source) => {
          return new carto.dataview.Formula(source, 'pop_max', {
            operation: carto.operation.AVG
          });
        },

        (source) => {
          return new carto.dataview.Formula(source, 'pop_max', {
            operation: carto.operation.MIN
          });
        },

        (source) => {
          return new carto.dataview.Formula(source, 'pop_max', {
            operation: carto.operation.MAX
          });
        },

        (source) => {
          return new carto.dataview.Category(source, 'adm0name', {
            limit: 10,
            operation: carto.operation.COUNT,
            operationColumn: 'pop_max'
          });
        },

        (source) => {
          return new carto.dataview.Category(source, 'adm0name', {
            limit: 10,
            operation: carto.operation.SUM,
            operationColumn: 'pop_max'
          });
        },

        (source) => {
          return new carto.dataview.Category(source, 'adm0name', {
            limit: 10,
            operation: carto.operation.AVG,
            operationColumn: 'pop_max'
          });
        },

        (source) => {
          return new carto.dataview.Category(source, 'adm0name', {
            limit: 10,
            operation: carto.operation.MIN,
            operationColumn: 'pop_max'
          });
        },

        (source) => {
          return new carto.dataview.Category(source, 'adm0name', {
            limit: 10,
            operation: carto.operation.MAX,
            operationColumn: 'pop_max'
          });
        }
      ]

      const dataViewsPromises = [];

      sources.forEach((source) => {
        dataViews.forEach((dataViewFn) => {
            const dataView = dataViewFn(source); 

            const dataViewPromise = new Promise((resolve, reject) => {
              client.addDataview(dataView);

              dataView.on('statusChanged', (status) => {
                if (status === 'loaded') {
                  resolve(dataView);
                }
              });
            });

            dataViewsPromises.push(dataViewPromise);
        });
      });

      function handleDataChange(dataView, newData) {
        console.log('New Data:', newData);
      }

      function onDataChanged(dataViews) {
        dataViews.forEach((dataView) => {
          dataView.on('dataChanged', (newData) => {
            handleDataChange(dataView, newData);
          });
        });
      }

      Promise.all(dataViewsPromises).then(onDataChanged);

      client.addLayer(layer1);
      client.addLayer(layer2);
      client.addLayer(layer3);
      client.addLayer(layer4);
      client.addLayer(layer5);
      client.addLayer(layer6);
      client.addLayer(layer7);
      client.addLayer(layer8);
      client.addLayer(layer9);
      client.addLayer(layer10);

      client.getLeafletLayer().addTo(map);

      const $button = document.getElementById('button-js');

      $button.addEventListener('click', () => {
        const popMaxFilter = new carto.filter.Range('pop_max', { gte: 9000 });
        source2.addFilter(popMaxFilter);
      });
    </script>
  </body>
</html>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.