looping a promise?

i have a calendar for live bands on my site so i want something like

december
list of bands

january
list of bands

february
list of bands

so far i have this that queries my database for the listings for this month, next month and the next next month based on a new Date() function that is not posted:

// would love to loop this in a function - having trouble assigning results as a dynamic value
wixData.query("LiveMusic")
  .ascending("dateId")
    .ge ("dateId", today)
    .eq("month", thismonth)
    .find()
    .then((results) => {
      if(results.items.length > 0) {
        liveMusic1 = results.items;
        $w('#repeater1').data = liveMusic1;
      }
    })
  })
  .catch((err) => {
    let errorMsg = err;
  });
  
  wixData.query("LiveMusic")
  .ascending("dateId")
  .eq("month", nextmonth)
  .find()
  .then((results2) => {
    liveMusic2 = results2.items;
    $w('#repeater2').data = liveMusic2;
    if (liveMusic2.length < 1) { $w('#group66').collapse()} })
  .catch((err) => {
    let errorMsg = err;
  });
  
  wixData.query("LiveMusic")
    .ascending("dateId")
    .eq("month", twomonth)
    .find()
    .then((results3) => {
      liveMusic3 = results3.items;
      $w('#repeater3').data = liveMusic3;
      if (liveMusic3.length < 1) { $w('#group67').collapse()}
    })
    .catch((err) => {
      let errorMsg = err;
    });
    

id really like to refactor this.
i tried this:

var queryItems = [
    ['thismonth', 'results', 'liveMusic1', '#repeater1'],
    ['nextmonth', 'results2', 'liveMusic2', '#repeater2'],
    ['twomonth', 'results3', 'liveMusic3', '#repeater3']
];

queryItems.forEach((query) => {
  wixData.query("LiveMusic")
    .ascending("dateId")
    .ge ("dateId", today)
    .eq("month", query[0])
    .find()
    .then((query[1]) => {
      if(result.items.length > 0) {
        query[2] = result.items;
        $w(query[3]).data = query[2];
       }
    })
    .catch((err) => {
       let errorMsg = err;
     });
 })

but wix doesnt like assigning the .then(results) as a value and i think i need that or my query results are being overwritten. is it possible or is there an easier way to do this? maybe with a filter or a hook or something?

The first error is in your array. thismonth, nextmonth, and twomonth are variables, so don’t wrap them in quotation marks. If you wrap them in quotation marks or tildes, they will be interpreted as literal strings.

The second…ish error is you don’t need the second column in your array. You can safely just call them all results and it will run just fine since you’re still declaring three variables in three separate scopes.

The third error is that you never define result. You’re telling JS that the data is contained in ‘results’, ‘results2’, or ‘results3’. It’s not going to guess that result is in any way related to any of those. But addressing the second point will fix this anyway, so just something to note.

ForEach loops can work nicely with promises under certain circumstances, here it is not the most reliable solution, and any error can break the loop.

I’d recommend you make use of ES6 methods to make it much more efficient than having to rely on 3 queries. Draw the data only once (you can use .or() for your query filter if necessary), then you can use filter and sort to separate the data into your three repeaters.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

awesome. thank you! i will make another attempt at refactoring and use ES6.

It’s taking a little while but i’m getting closer.
https://www.mudhenbrew.com/live-music

i have the groups containing the repeaters hidden until the promise is ready. also, that doesn’t happen until the dataset is ready. it’s hard to know what is loading first on the dom. the ui dataset? the repeater? the corvid code?

wrapping everything in dataset onready seems to load the data correctly.

$w('#dataset1').onReady(() => {
});

also some documentation shows this code inside the promise or outside the promise. does it make a difference?

$w(item.repeater).onItemReady(($w, dataItem, index) => { 
});

and also. this code is still relying on the ui dataset it seems like to make the connection from the data to the repeater. is there a way to do that without the ui dataset because that is limiting the query with however many items it will pull.


import wixData from 'wix-data';

// Get today's current date.
const now = new Date();

// Array list of months which also matches boolean columns in database.
const months = new Array('january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december');

// formate the date
function formatDate(date) {
var d = new Date(date),
month = '' + (d.getMonth() + 1),
day = '' + d.getDate(),
year = d.getFullYear();
if (month.length < 2)
month = '0' + month;
if (day.length < 2)
day = '0' + day;
return [year, month, day].join("");
}
// get the date as yyyymmdd

const today = formatDate(new Date());

//loop thru ui components
const containerData = {
month1: {
month: months[(now.getMonth())%12],
repeater: '#repeater1',
band: '#text182',
date: '#text180',
time: '#text221',
photo: '#image42',
group: '#group65'
},
month2: {
month: months[(now.getMonth() +1)%12],
repeater: '#repeater2',
band: '#text220',
date: '#text219',
time: '#text216',
photo: '#image46',
group: '#group66'
},
month3: {
month: months[(now.getMonth() +2)%12],
repeater: '#repeater3',
band: '#text224',
date: '#text223',
time: '#text225',
photo: '#image48',
group: '#group67'
}
}
$w.onReady(function() {
$w('#dataset1').onReady(() => {
Object.values(containerData).forEach(item => {
wixData.query("LiveMusic")
.ascending("dateId")
.ge ("dateId", today)
.eq(item.month, true)
.find()
.then((results) => {
$w(item.repeater).data = results.items;
if ($w(item.repeater).data.length === 0) {
$w(item.group).collapse();
} else {
$w(item.group).show();
}
});

$w(item.repeater).onItemReady(($w, dataItem, index) => {
$w(item.band).text = dataItem['title'];
$w(item.date).text = dataItem['date'];
$w(item.time).text = dataItem['time'];
$w(item.photo).src = dataItem['photo'];
});
});
// month text in red bar
$w('#text217').text = thismonth;
$w('#text218').text = nextmonth;
$w('#text226').text = twomonth;
});
});

it took a while but i got it.
i put a query in the backend to only query the data i need, passed the data to the page, filtered the data into the month section.