0

can i set variables on the scope of the class to be used later?

example

class TestClass {
    #key = '';
    #reference = '';
    #onReturn = () => {};

    constructor({ key } = {}) {
        this.#key = key || this.#key;
        this.#onReturn = onReturn || this.#onReturn;
    }

    login(username, password) {
        this.#submit(username, password);
    };

    #submit(username, password) {
        fetch(
            `/login/${this.#key}`,
        )
            .then(response => response.json())
            .then((json) => {
                this.#handleResponse(json);
            })
    };

    #handleResponse(json) {
        this.#reference = json.reference;
        this.#onReturn();
    };

    token() {
        console.log(this.#key, this.#reference); // "blabla", empty
    };
};

const Test = new TestClass({ // initializing the class
    key: 'blabla',
    onReturn: tokenSubmit
});

const onLoginSubmit = () => {
    Test.login(username, password); // running a fetch which will set a private var
};

const tokenSubmit = () => {
    Test.token(); // private var returns empty
};

which has two public methods login and token where the token should log the key and the reference

as a result i do get the key which was set on the constructor but the reference which was set while handling a fetch returns empty

Kup
  • 882
  • 14
  • 31
  • 3
    `#submit` calls `fetch` which is asynchronous. So `LoginModule.login()` hasn't finished by the time you call `LoginModule.token()` [Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference](https://stackoverflow.com/q/23667086) – VLAZ Jul 27 '21 at 14:31
  • @VLAZ on the actual scenario the "token" is only called after the "login" returns – Kup Jul 27 '21 at 14:34
  • Why do you use { json } ? That syntax is meant to be used for object destruction. Are you sure that you have json child to use from that argument object in #handleReference – kalle Jul 27 '21 at 14:36
  • @kalle that's just as an example I've had other stuff in there, I'll edit the question – Kup Jul 27 '21 at 14:38
  • @Kup that's not what you show here. And the result you get is consistent with trying to handle async code before it completes. – VLAZ Jul 27 '21 at 14:42
  • @VLAZ i've edited the question now to better emulate the scenario – Kup Jul 27 '21 at 14:44
  • You could return the chained promise from `#submit()`, then also return it from `login()` so you can do: `Test.login(username, password).then(() => Test.token())` or `await Test.login(username, password)` and `Test.token()` the line below. – 3limin4t0r Jul 27 '21 at 14:47
  • @3limin4t0r it's two separate forms for the user. the first would trigger and email with the token which the user should submit on the second form – Kup Jul 27 '21 at 14:49
  • It doesn't matter too much, but be aware that `response.json()` doesn't actually resolve with JSON. – evolutionxbox Jul 27 '21 at 14:50
  • @Kup [I cannot reproduce it](https://jsbin.com/dohuzad/1/edit?js,console). I also had to make a fair few changes so the code worked. Please make sure to supply a [mcve] that clearly demonstrate the issue. – VLAZ Jul 27 '21 at 14:54
  • @VLAZ apologies for that, i did try using the [emulator](https://jsbin.com/meriwuweba/edit?js,console) and it's fine, my problem apparently resides on using it on react, because that last call just doesn't pickup the var added to the scope by the login method. will try a different way, thanks – Kup Jul 27 '21 at 16:32
  • React is still just JavaScript. It doesn't change the rules of how the language is interpreted and executions are made. – VLAZ Jul 27 '21 at 16:36
  • @VLAZ apparently the issue comes from the **handleSubmit** from **useForm** (react-hook-form) for some reason the class just losses the scope set on the first method called – Kup Jul 27 '21 at 16:52
  • @Kup you mean the age old problem [How to access the correct `this` inside a callback](https://stackoverflow.com/q/20279484)? – VLAZ Jul 27 '21 at 16:53
  • as in if i simply use `onSubmit={(e) => {e.preventDefault(); onTokenSubmit();}}` and not `onSubmit={handleSubmit(onTokenSubmit)}` the scope is there – Kup Jul 27 '21 at 16:53
  • @VLAZ haven't tried using the old way, i was just playing around with class thinking it would have the sabe behavior, but in sum, yes, it's probably the arrow functions that are screwing this up – Kup Jul 27 '21 at 16:56
  • In that case it's [addEventListener calls the function without me even asking it to](https://stackoverflow.com/q/16310423). You need to provide *a function reference* as a handler, not *call a function*. Would have taken few minutes to diagnose *if your example was representative*. – VLAZ Jul 27 '21 at 16:56

1 Answers1

0

Following up on @vlaz's comment, try the following test code:

async function test() {
    const Test = new TestClass({ key: 'blabla' }); // initializing the 
class
    await LoginModule.login({ username, password }); // running a fetch which will set a private var
    LoginModule.token(); // private var returns empty
}

The addition of await waits for the fetch to complete before proceeding to the next line, calling LoginModule.token().

For this to work, you'll also need to modify #submit to return fetch's promise:

    #submit({ username, password }) {
        return fetch(
            `/login/${this.#key}`,
        )
            .then(response => response.json())
            .then((json) => {
                this.#handleResponse({ json });
            })
    };
edemaine
  • 2,699
  • 11
  • 20