I would like to filter repeater content. I know this can be done, but my request is a little different to the examples I’ve seen so far on the community.
I have a UK postcode from the customer and I will have UK postcodes as a field within the database used for each of the businesses that will be listed in the repeater output.
I have a function that calculates the distance between the postcode that is provided by the customer and each of the business postcodes, and based on a “radius” entered by the customer, I would like to show only businesses where the postcodes are within the “radius” mileage given by the user. This will effectively allow me to show “local” businesses to the customer from the business database repeater entries.
I can work out the distances myself, but need to know how I would run the function against each of the repeater entries and then only display the entries for which the distance is within the “radius” limit.
I think I will need to use wixdata.query, but I’m not very familiar with this as I’m fairly new to Velo and Wix only having been using it for around 3 months or so.
Can anyone please help me with how I might do this for each of the database entries and then only show the entries that fit the criteria. Thanks!!!
Have no experience with UK-postcodes, but maybe you can take a postcode apart using ‘postcode’ NPM (it’s already in the list of Wix-approved NPM’s) and then do a query on your collection using ‘startswith’ or ‘between’.
Sorry Giri, but you misunderstand what I need to do - I already have the function and code to do the postcode comparison and obtain the distance between them. What I need to know how to do is to filter the repeater entries so that they only contain the entries that fit the criteria. I basically need to know how to filter the repeater results using Velo code rather than simply filtering on the front end.
Got you. Give me an example of a postcode used as input, please reveal collection column setup (whole postcode in 1 column or split into 2) and some postcodes which should be regarded as “hits” and we’ll take it from there. Querying in the backend and then hand it over to a repeater in frontend is quite easy, don’t worry.
Thanks - I’ve attached the test data database collection that I’m using. The customer postcode for testing is “SN25 3NA”, and just assume a radius of 20 miles or so - that would be the inputs I would use to test here. The postcode field has a name of addressPostcode.
All I’m after is how the wix-data.query code would look if I were to use the function (let’s call it calculateDistance( postcode1, postcode2) ) in order to return a number (miles) between the two postcodes, the customer postcode SN25 3NA and the current database business postcode (each one of the 4 in the test data).
I basically need to only show the entries for which the distance between the postcodes is less than the radius entered by the customer, but you can hard code this as 10 miles for testing.
Hope this makes sense.
Makes sense. But wixData cannot perform functions during a query, that has to go into a post processor. That’s why I asked if you can first narrow the larger result down to some manageable array using wixData “startswith” or “between” and after that query returns a result, do a calculateDistance( postcode1, postcode2) with that first, unrefined result.
Example: with “SN25 3NA”, should the (first) hit from the query be those 2 entries which also start with SN? That way we can let wixData do a rough selection first and then write a function that calcs the radius (here: those 2 which start with SN also).
Do I make sense now?
Ah, OK. The inability to call a function from the query is a bit of a pain, but I have had another thought.
Could we get the customer postcode from an input field and simply work through the database, updating a new field called “willDisplay” or something similar (boolean), by running the function against each database field and the customer source postcode. Then, once the database has been updated, we run the query extracting only the entries that include the “willDisplay” field value TRUE?? Potentially using get() and update() wix-data calls? I’m not sure I’m saying the right things here, just an idea?
@paulgoodchild Hi, Yes you can easily filter the repeater data. As you didn’t post any code that’s why I’m providing generalized answer. Just store the repeater data into an array. Then use the array filter functions.
let newArrayForRepeater = arrayName.filter(function(currentElement){
return currentElement.addresspostcode<=radiusvalue;
})
@wix-expert-velo-cert Thanks. Could you please provide sample code so that I can work out how to get all the _id fields and then how to also use the update() call in order to update the willDisplay field ? Sorry to ask such newbie questions, but I have the attached code and it doesn’t seem to be working - the get works and then the update doesn’t for some reason. Thanks.
Hi Team Support!
So, this is the code that I’ve currently got that I’m sure is almost working but not quite. The idea is that I read the LocalBusinesses database into “results” and then work through each entry returned, calling my “distance” function and then updating each entry in the database with new distanceInMiles and durationText field values based on what’s returned from the “distance” function. It’s not quite working.
Here’s the code…
And here’s the errors - please could someone help me sort out what’s wrong as I’m not skilled enough in Javascript just yet! - Thanks.
Errors…
Paul, the .length property is 1 based. An array is 0-based. Meaning, if an array has 10 entries, .length will be 10. But, the can only be addressed as array[0] (the first one) to array[9], the last 1, so NOT 10.
In short, change the
for var i=1; i<=itemCount; i++
into
for var i=0; i< itemCount; i++
so, in the case of 10, it will run for 0-9 (which = length 10).
It’s a Javascript thing, you’ll just have to get used to it.
Sorry, but I’ve changed the for loop as instructed and I’ve also changed all references to “loopy” rather than “loopy-1” so that I reference the 0 to 3 values (there are four items in the current database). I’m still getting the same errors. I’m not sure that this is from a value outside of the array limits - I think this may be an issue referencing loopy variable itself for the wixdata.get call??? Can’t work out what’s wrong here sorry. Appreciate any help.
I’ve had “some” success…
I now have the loop working correctly, and I can see that I’m obtaining the correct 4 different postcodes and I’m also getting 4 difference distance calculations from the user postcode to the 4 different postcodes.
I think I’ve got some sync issues though as I am seeing the values of distanceInMiles and durationText within the wixdata.get piece, all having the same values in all for loops.
Am I right in thinking that all the code gets executed at the same time and not one line after another - if this is the case, I’m not sure how to work with this as I’m used to seeing code execute one line after another.
It seems as though the wixdata.get code is running at the same time as the distance function being called and so on.
I’m really confused how I control the sequence of execution within the code.
If anyone has suggestions, please, please help! This is really frustrating.I’m almost there, but cannot quite seem to get the database updated correctly, ready to then display the relevant businesses on the page!
Here’s the code that’s almost working…!!!
Paul, you’re right, that stuff runs asynchronous. Also, doing a .get inside a loop, over an internet connection instead of against a local hard disk, introduces trouble. One .get might get lost, the result of the next one may come in before the first one, etc. There is a way out of this (using async await), but before we start doing this, please answer me these ones first: why store the distance in a table per request (what’s the point)? And how about concurrency: 2 users at the same time request this: what is the table going to hold?
Paul, I typed an answer, but I do not see it anymore. Do you?
Paul, I see that my answer is suddenly way up there, not at the bottom of this conversation. Sorry about the confusion, but it looks like there is a glitch in the matrix.
Ah, right - you bring up some good points. Firstly, I have found the async function and await calls and have started to use these. Thanks.
However, I am a little concerned now that you mention multiple users and what the database may hold at any particular point - it’s a good point and one that I hadn’t taken into consideration.
I’m not really sure how to get over this one.
My basic need is to be able to show local businesses (in relation to the postcode entered by the user).
My original idea was to lookup and store the distances from the user postcode and all of the business postcodes, and then using the radius entered by the user, somehow filter the repeater content, but to do this, I do need to make changes in the database entries so that I can then filter the output in the repeater.
If you have any ideas how I can do this, I would really appreciate knowing, as at the moment, all I can do is change the database entries and have a “willDisplay” field that I then filter on, but this may affect other users that are trying to filter the data at the same time!
This issue must happen all the time! How do people get around this!?!?!?
I suppose I’d have to “copy” the database to an array and then use the array as the source for the repeater? Can this sort of thing be done, so that I have the source of the repeater in memory, local for each user, rather than changing the actual database?
@paulgoodchild Yes Paul, we do it all the time, without writing stuff back to the db. To eliminate the multiple user problem, you should:
- generate the businesses within a certain distance (as you do now, but without the writing back)
- stuff it into an array of objects and hand over that array to, e.g. a repeater
In order for 2 to work, you will need to add _id’s to the array of objects, otherwise the repeater will not work (it expects _id’s). For this, first install the uuid-NPM. After that, at the top of your app, import is like so:
import { v4 as uuidv4 } from 'uuid';
Array of obj’s
An example of an array of objects would be:
{"name": "Somecompany1", "address" : "Somestreetname1", "distance" : 9, "_id" : "123456"},
{"name": "Somecompany2", "address" : "Somestreetname2", "distance" : 8, "_id" : "1234567"},
{"name": "Somecompany3", "address" : "Somestreetname3", "distance" : 5, "_id" : "12345678"}
You declare first the array, like so:
let arrBusinesses = []; //now we have an array
then, you build, for every query_item, an object, like so:
let toPush ={
"name" : item[index].name,
"address" : item[index].address,
"distance" : calcDifference (arg1, arg2), //your function where you calc your stuff
"_id" : uuidv4() //add an _id
}
arrBusinesses .push(toPush);
And then, when all is done, you hand over this array to a repeater and Bob’s your uncle. NO writing to disk, nicely clean for every new user.
PS Did not test parts of the code, but it should be kind of ok.
PPS Of course, instead of creating a new array of objects, you could also add the calculated stuff to the query-result array of obj’s. Up to you. I did this one, so you you only return data to frontend which are really necessary.
@giri-zano Thanks so much for this. I’ve found similar code snippets in the Velo examples under the Repeater section, so sort of guessed that I could somehow create an array that could then be used for the repeater data source. This is a great start and welcome comments from you thank you. I’ll crack on and see what I can come up with (extreme newbie here, struggling, but making small progress steps each day!)