I'm just trying to store a JSON object into a global variable so I don't need to run fetch every time we update search parameters (we're building a real estate listing interface). Below is my code and I'm sure I'm misunderstanding something fundamental with the async/await syntax as a function (filterListings) that fires on an element click is retrieving an empty array.
let allListings = [];
let filteredListings = [];
async function getListings() {
if(allListings.length == 0){
let response = await fetch(URL);
allListings = await response.json();
}
filteredListings = allListings;
}
/*Filtering function on search button click*/
function filterListings(){
filteredListings.length = 0;
console.log(allListings.length); //allListings is 0???
for(let i = 0; i < allListings.length; i ){
console.log("filtering happening");
}
numOfListings = filteredListings.length;
printListings();
}
/*Iterating through filteredListings to get only necessary listings to print on the page*/
function printListings(){
let listingsWrapper = document.getElementById("listings_wrapper");
let currentPageLimit = ((currentPage !== totalPages) ? listingPageLimit*currentPage : filteredListings.length);
document.getElementById("number_of_listings").innerHTML = numOfListings;
console.log("These are listings " listingOffset " - " currentPageLimit)
for (let i = listingOffset; i < currentPageLimit; i ) {
listingsWrapper.innerHTML = `<a class='listing_container' href='/listings?address=${styleLink(filteredListings[i].StreetNumber, filteredListings[i].StreetName, filteredListings[i].StreetSuffix, filteredListings[i].City, filteredListings[i].PostalCode, filteredListings[i].MLSNumber)}' style='background-image:url("https://bm-re-listings.s3.us-west-2.amazonaws.com/test_folder/pic-${filteredListings[i].Matrix_Unique_ID}-0.jpg")'>
<div class='listing_details'>
<div class='listing_details_main'>
<h2 class='listing_title'>${styleTitle(filteredListings[i].StreetNumber, filteredListings[i].StreetName, titleCase(filteredListings[i].StreetSuffix), filteredListings[i].City)}</h2>
<p class='listing_subtitle'>${filteredListings[i].City}, ${filteredListings[i].PostalCode}</p>
<p class='listing_stats'>${styleRoomNum(filteredListings[i].BedsTotal)}${styleRoomNum(filteredListings[i].BathsTotal)}${filteredListings[i].SqFtTotal} sqft</p>
</div>
<div class='listing_details_aside'>
<h3 class='listing_price'>${stylePrice(filteredListings[i].ListPrice)}</h3>
<div class='listing_cta'><span>Details</span></div>
</div>
</div>
</a>`
}
/*Hide load more button if no more listings*/
if(currentPage == totalPages){
document.getElementById("load_more").style.display = "none";
} else {
document.getElementById("load_more").style.display = "block";
}
}
/*Attaching event listner to the search button*/
document.getElementById("search_button").addEventListener("click", function(){
currentPage = 1;
listingOffset = (currentPage -1) * listingPageLimit
filterParams.lowPrice = (document.getElementById("price_min").value <= document.getElementById("price_min").getAttribute("min") ? 0 : document.getElementById("price_min").value);
filterParams.highPrice = (document.getElementById("price_max").value >= document.getElementById("price_max").getAttribute("max") ? 1000000000 : document.getElementById("price_max").value);
filterParams.lowSqft = (document.getElementById("sqft_min").value <= document.getElementById("sqft_min").getAttribute("min") ? 0 : document.getElementById("sqft_min").value);
filterParams.highSqft = (document.getElementById("sqft_max").value >= document.getElementById("sqft_max").getAttribute("max") ? 100000 : document.getElementById("sqft_max").value);
filterParams.address = document.getElementById("address_search").value;
filterListings();
});
/*Final Function Firing Order*/
async function refreshListing(){
await getListings();
await printListings();
}
refreshListing();
The problem I found was that when the element with the ID of "search_button" was clicked and filterListings function would fire, it would return allListings as an empty array and thus the for loop wouldn't even fire.
Any help is much appreciated!
CodePudding user response:
The problem lies in the reference of filteredListing
is the same as allListings
. They are the same underlying value
filteredListings = allListings;
This behavior can be observed in this simple example
let allListings;
let filteredListings;
allListings = ['a', 'b', 'c'];
filteredListings = allListings;
console.log(allListings); // ['a', 'b', 'c']
filteredListings.length = 0;
console.log(allListings); // []
This issue is outlined in many places on the web such as here Does JavaScript pass by reference?
To fix simply make a copy of the underlying object instead of using the same object. For our simple example:
let allListings;
let filteredListings;
allListings = ['a', 'b', 'c'];
filteredListings = [...allListings]; // copy the array
console.log(allListings); // ['a', 'b', 'c']
filteredListings.length = 0;
console.log(allListings); // ['a', 'b', 'c']
For your code your function should read:
async function getListings() {
if(allListings.length == 0){
let response = await fetch(URL);
allListings = await response.json();
}
filteredListings = [...allListings]; // clone all listings into filtered
}