PrimeSteak

Senior Member
Joined
Nov 7, 2020
Messages
895
So I'm making a dynamic search bar for the final project I'm making for CS50W (A library management system). Aaaand I'm stuck. Funnily enough, getting the results from the input I have via an onkeyup event listener and sending the value of it to the server for query results and those results back to JS again as JSON all works, but now I can't display the actual results, lmao.

I've watched a vid or two about making a dynamic search bar but the page containing the bar already has everything available in a database and it just filters through them, w3schools also had something similar but it isn't what I want to do. Essentially, what I want to do, when the user types something in the input, the titles of the books found should show up just under the search bar and be active links that take them to the selected book's page.

Link related and contains all the code I'm using:

(P.S Wouldn't a general help/fixes/code review thread here in the software dev board be nice? lol)

Thanks in advance for the help!

Kind Regards
PrimeSteak
 

SaucePlz

Senior Member
Joined
Aug 11, 2020
Messages
549
const par = document.createElement("par");

par is not a valid html tag.

Did you inspect your dom, is anything being appended?
 

PrimeSteak

Senior Member
Joined
Nov 7, 2020
Messages
895
const par = document.createElement("par");

par is not a valid html tag.

Did you inspect your dom, is anything being appended?
Lmao, ok so now the HTML is doing something but the input bar is getting wonky:
1631511345015.png
I'm sure a bit of CSS adaptation should work out the problems
 

PrimeSteak

Senior Member
Joined
Nov 7, 2020
Messages
895
const par = document.createElement("par");

par is not a valid html tag.

Did you inspect your dom, is anything being appended?
1631513271549.png
Btw, what would be the correct way to access JSON? Cause I try to directly access it, but it only returns undefined in the console. Should I use toString()? (The array is the AJAX result that printed in console)

1631513335306.png
1631513525619.png
 

SaucePlz

Senior Member
Joined
Aug 11, 2020
Messages
549
I am? (Well, I think so?) It's the last picture in the post
My bad, still busy with the first coffee of the day. :p

Ok, so just look at the object and look at how you are trying to access it. Where in the object are the properties you want to access? Root level or perhaps children of a root property?

Hint: In the console, if you hover your cursor over the property you want to access, Chrome will show you a little popup with the path to that property.
 

PrimeSteak

Senior Member
Joined
Nov 7, 2020
Messages
895
My bad, still busy with the first coffee of the day. :p

Ok, so just look at the object and look at how you are trying to access it. Where in the object are the properties you want to access? Root level or perhaps children of a root property?

Hint: In the console, if you hover your cursor over the property you want to access, Chrome will show you a little popup with the path to that property.
ok, thx will check out
 

MagNorthDigital

Active Member
Joined
Aug 5, 2015
Messages
76
View attachment 1146434
Btw, what would be the correct way to access JSON? Cause I try to directly access it, but it only returns undefined in the console. Should I use toString()? (The array is the AJAX result that printed in console)

View attachment 1146436
View attachment 1146438
You need to traverse the object...
toString will not work

loop through query and get the fields
So query[0].fields for the first item

Once you can reliably console log a list of names, you need to inject / create those items in the page.

Are you using any type of framework or is this vanilla js. If it's vanilla, create a function that returns a document fragment to you, and then appendChild that into the page after clearing the container element

Container.innerHTML = "" is fast and ugly.
 

PrimeSteak

Senior Member
Joined
Nov 7, 2020
Messages
895
Did you get it sorted?
Well, the JSON part, yes. When I tried the hover thing you suggested in Firefox (didn't work, lmao), then I thought that I should maybe change the call to this: ```query.fields.name``` and it worked. But now another problem has arisen

Before I search:
1631619541494.png
After I search (couldn't take it with Snipping Tool):
img_20210914_133957-jpg.1147460

IMG_20210914_134013.jpg
I reckon I can jangle this with some eventlisteners and child destruction
 

Attachments

  • IMG_20210914_133957.jpg
    IMG_20210914_133957.jpg
    499.9 KB · Views: 61

PrimeSteak

Senior Member
Joined
Nov 7, 2020
Messages
895
Well, the JSON part, yes. When I tried the hover thing you suggested in Firefox (didn't work, lmao), then I thought that I should maybe change the call to this: ```query.fields.name``` and it worked. But now another problem has arisen

Before I search:
View attachment 1147434
After I search (couldn't take it with Snipping Tool):
img_20210914_133957-jpg.1147460

View attachment 1147458
I reckon I can jangle this with some eventlisteners and child destruction
P.S it's also removing links from the nav when backspacing and typing again, whether the bar and results' div is in the nav or not it for some reason deletes them
 

MagNorthDigital

Active Member
Joined
Aug 5, 2015
Messages
76
P.S it's also removing links from the nav when backspacing and typing again, whether the bar and results' div is in the nav or not it for some reason deletes them
You need to clear the children of the containing element, not remove the container...

Think of it like a cup of coffee, you use the same cup every time, drink the old coffee and pour in new coffee
 

MagNorthDigital

Active Member
Joined
Aug 5, 2015
Messages
76
Start with Vue, then Svelte, then React
In the industry it'll be either React, Vue or (shudder) Angular

It's all about getting a feel for components and state

ui = function(state)
 

PrimeSteak

Senior Member
Joined
Nov 7, 2020
Messages
895
Code for search.js:
JavaScript:
document.addEventListener("DOMContentLoaded", () => {
    const search = document.querySelector("#search");
    const display_div = document.querySelector("#results");
    if (search !== null)
    {
        search.onkeyup = (e) => {
            display_div.style.display = "none";
            if (e.key !== " " || e.key !== "Enter")
            {
                get_results(search.value);
            }
        };
        document.addEventListener("click", (e) => {
            if (e.target !== 'a.nav-link') {
                display_div.style.display = "none";
            }
        });
    }
});

function get_results(query)
{
    if (query === null || query.length < 3)
    {
        return []
    }
    if (query !== "")
    {
        fetch(`/results/${query}`)
        .then(response => response.json())
        .then(result => {
            console.log(result);
            const a = document.createElement("a");
            const display_div = document.querySelector("#results");
            display_div.innerHTML = "";
            result.forEach(query => {
                console.log(query);
                a.setAttribute("class", "nav-link");
                a.textContent = query.fields.name;
                link = `book/view/${query.pk}`
                a.href = `http://127.0.0.1:8000/${link}`;
                a.onclick = () => {
                    window.location.href = `http://127.0.0.1:8000/${link}`;
                };
                display_div.appendChild(a);
            });
            display_div.style.display = "block";
        });
    }
}

Concerning the HTML, I moved the bar and div outside of the nav

Thanks to everyone who participated in this thread!
 

_kabal_

Expert Member
Joined
Oct 24, 2005
Messages
3,690
your function `function get_results(query)` either returns an empty array (on no matching conditions), or returns nothing, on matching conditions. that doesnt make sense.

why not change it to

Code:
function get_results(query)
{
    if (query === null || query.length < 3 || query === "")
    {
        return
    }
    fetch(`/results/${query}`)
        .then(response => response.json())
        .then(result => {
            console.log(result);
            const a = document.createElement("a");
            const display_div = document.querySelector("#results");
            display_div.innerHTML = "";
            result.forEach(query => {
                console.log(query);
                a.setAttribute("class", "nav-link");
                a.textContent = query.fields.name;
                link = `book/view/${query.pk}`
                a.href = `http://127.0.0.1:8000/${link}`;
                a.onclick = () => {
                    window.location.href = `http://127.0.0.1:8000/${link}`;
                };
                display_div.appendChild(a);
            });
            display_div.style.display = "block";
        });   
}

or even better

Code:
function get_results(query)
{
    if (!is_valid_query(query))
    {
        return
    }
    ...   
}


the takeway/enhancement here is to "invert your if's" and return early.
removing indentation and using return early makes code so much easier to understand.

event listener could be refactored to

Code:
document.addEventListener("DOMContentLoaded", () => {
    const search = document.querySelector("#search");
    const display_div = document.querySelector("#results");
    if (search == null)
    {
        return
    }
    search.onkeyup = (e) => {
        display_div.style.display = "none";
        if (e.key !== " " || e.key !== "Enter")
        {
            get_results(search.value);
        }
    };
    document.addEventListener("click", (e) => {
        if (e.target !== 'a.nav-link') {
            display_div.style.display = "none";
        }
    });
});
 
Top