0

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!

kenny
  • 19
  • 4
  • First of all, I do not think you have to pass immediately the filter array to all allListenings. Maybe not always you will filter. Just map the array in the filter method and there in filter copy the array of all listening. When you pass the array with =, you are not copying but just passing reference, copy array is [...array] or Array. from(the filtered values). If you have any questions or do not understand, I can write it for you. Check here for array copying: https://www.samanthaming.com/tidbits/35-es6-way-to-clone-an-array/ – Muhamet Smaili Mar 14 '22 at 18:24

1 Answers1

0

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
}
ug_
  • 11,267
  • 2
  • 35
  • 52
  • OMG... I never knew this and it totally went over my head. Thanks so much! *grumbles* OF COURSE it isn't a clone... why would I think it was a clone... >.> – kenny Mar 14 '22 at 20:46