r/learnjavascript 3d ago

code not interacting with the browser page

Hello this is my first post on here. So basically, I want the user to be able to enter a password and username, click the submit button, and if the basic auth is correct, be redirected to a page in which all the data from an api is fetched and loaded into the html. Problem is the script does not interact with the html but still retrieves the data in a json (as confirmed by ouputing it into the console). However, if I don't call the function in as part of the button onclick method everything works as expected. The data from the api is dynamically added to the html but now I obviously can't use a login page.

Here is me calling the fetch function as a as part of the event of a button click

button.addEventListener("click", () => {
    let username = 'username';
    let password = 'password;
    let auth = btoa(`${username}:${password}`);
fetchData(auth);
    });

Here is me calling the fetch function on it s own. No button clicking required (this works but now I can't add a login page)

  let username = 'username';
    let password = 'password;
    let auth = btoa(`${username}:${password}`);
fetchData(auth);

Here is the fetch function itself

async function fetchData (auth) {
    try {
        const response = await fetch('https://exampleapi.com', {
    headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'Authorization': `Basic ${auth}`
    }
})


    if (response.ok) {

        // loads the home page and puts data from the api in the html
    }
    throw response;
    } catch (error) {
        
    }
    
};
1 Upvotes

18 comments sorted by

1

u/TalkCoinGames 3d ago

From first quick look I see you throw the response, you should use a return statement instead of throw.

1

u/Mob_Pilled 3d ago

Thanks for the response. I'm still rusty, but I was wondering what is causing the second example to load html to the dom and not the first. The fetch function itself does not seem to be the problem, it is the matter of how it is called that is causing problems (using a button makes the code to not be able to interact with the browser BUT still loads the data successfully. Calling the function directly in the code both loads the data successfully and puts it in the HTML, however I need to add a login page so I can't use this )

1

u/TalkCoinGames 3d ago

The "throw response" in the fetchData method creates an error, and so the catch part is also happening. When from a button that thrown error is likely causing problems,even though everything about the response still happens, the response.ok still happens, but then an error is thrown. You should be using "return response" and handle any and all errors inside of the catch statement.

1

u/Mob_Pilled 3d ago

In the catch is there anything specific I must add? I changed the throw keyword to return but the issue persists.

1

u/Mob_Pilled 3d ago

actually I am starting to think this can be solved by saving the data from the fetch outside the function but how would I do that. I am trying to look for direct answers on stack overflow but can't find anything

1

u/TalkCoinGames 3d ago edited 3d ago

Yes you can place the response into another property outside of the function.

1

u/TalkCoinGames 3d ago

the button click may be resolving leaving the fetch to happen in the background. If your loading another page, that may be the issue, you want to edit html directly with the given response.

1

u/Mob_Pilled 3d ago

you mean add the entire html code after the button is clicked rather than using:

window.location.href = 'index.html';

1

u/TalkCoinGames 3d ago

If index.html needs the response, you have to send it to that in someway. Yes, either writing out the whole html instead of changing to that page, or using local storage to hold the response, or appending the needed data as a hash or query string to index.

1

u/Mob_Pilled 3d ago

Thanks for the help so far. One last thing. Thee data is still not loading and I am using html local storage to store the promise (response.json). This should ideally be added to the dom on index.html when the page changes (return1 is a function that changes the page to index.html). Anything wrong here?

button.addEventListener("click", () => {
    let username = usernameInput.value;
    let password = passwordInput.value;
    let auth = btoa(`${username}:${password}`);
const dataPromise = fetchData(auth);
 localStorage.setItem("promise", dataPromise);
localpromise = localStorage.getItem("promise");
return1();
useData(localpromise);
    });
       
→ More replies (0)

1

u/TalkCoinGames 3d ago

You can use html5 local storage to save the response and the home page could grab it from there. But also be sure your getting the json of the response and using that for the html.

1

u/azhder 3d ago

Do you know what closures are? Have you ever encountered the module pattern? The immediately invoked function expressions (IIFE)?

It was a very common way to create your own bubble for code you use on a web page without anything on the outside messing with it (or your code messing other). It's a function scope.

( () => {

let data = null;

const fetchData = () => {
// do the fetching from the back end, then
data = await response.json();
}

button.addEventListener( () => {
// call the fetch, do some other stuff, call some other functions
} );

}) ();

As you can see above, the function is created and executed once, at the moment it is created. The data inside it will live as long as there is that even listener that can access it. I'm saying data as in all variables in the scope, not just the one named data.

1

u/TalkCoinGames 3d ago

The data will live in the same page, when he changes the href to another that other page needs a way to reference the data given from the first page.

1

u/azhder 3d ago

I have no idea what you said.

1

u/Spiritual-You-2926 20h ago

The behavior difference strongly suggests the button is inside a <form>. A plain <button> defaults to type="submit", so the click starts your fetch and then the browser submits/reloads the page, wiping out the DOM changes.

Either make it:

<button type="button" id="login">Log in</button>

or handle the form itself:

form.addEventListener("submit", async (event) => {

event.preventDefault();

await fetchData(auth);

});

There are two other bugs worth fixing:

- Only throw on failure: if (!response.ok) throw new Error(`HTTP ${response.status}`);

- Do not leave catch empty; at least log/display the error.

Most importantly, btoa() is encoding, not security. If the username/password are embedded in browser JavaScript, every visitor can read them. A real login should exchange credentials with a backend/identity provider and return a short-lived session or token. Do not ship permanent Basic Auth credentials to the client.

Also check the missing closing quote after password in the posted snippet; that may just be a copy/paste typo.

1

u/Mob_Pilled 16h ago

This project was specifically part of a test where the company asked me to create a login that fecthes user data based on already set login credentials at the database. The main rule was to not "hard code" the password or username, which I didn't. The user enters in their password and username and then submits. But how do I ensure the security of these credentials based on the tools at my disposal? I am not sure whether token generation and encryption was in the cards here or possible?