0

I'm using an event listener for "DOMContentLoaded" to hopefully wait until my web3 instance has been established. Unfortunately, this does not work as expected and in my getHash() function web3 has yet to be instantiated. What's the proper way to listen for when web3 has been defined?

<!DOCTYPE html>
<html>
    <script type="text/javascript" src="./web3.min.js"></script>
    <script type="text/javascript" src="./setup_web3.js"></script>
    <script type="text/javascript" src="./get_hash.js"></script>
<body>
    <h1>Transaction Hash Fetch.</h1>
    <p>Here is the hash for "Transfer(address,address,uint256)"</p>
    <script>
        window.addEventListener('DOMContentLoaded', (event) => {
            getHash();
        });
    </script> 
    <div id="output"></div>
</body>
</html>
0

Here's how I solved it. I used the observer pattern.

<!DOCTYPE html>
<html>
    <script type="text/javascript" src="./web3.min.js"></script>
    <script type="text/javascript" src="./Web3Manager.js"></script>
    <script type="text/javascript" src="./Hasher.js"></script>
<body>
    <h1>Transaction Hash Fetcher.</h1>
    <p>Here is the hash for "Transfer(address,address,uint256)"</p>
    <script>
        const manWeb3 = new Web3Manager();
        const hashOutput = new Hasher("Transfer(address,address,uint256)");
        manWeb3.subscribe(output);
        manWeb3.connect();
    </script> 
    <div id="output"></div>
</body>
</html>

Where Hasher looks like this

class Hasher {
    constructor(hashable) {
        this.hashable = hashable;
    }

    run() {
        console.log("Preparing to hash transaction.");
        var hash = web3.utils.keccak256(this.hashable);
        console.log("Hashed transaction ="+hash);
        document.getElementById("output").innerHTML = hash;
    }
}

And Web3Manager alerts the hasher after it's connected.

class Web3Manager {
    constructor() {
        this.observers = []
        this.isConnected = false;
    }

    connect() {
        window.addEventListener('load', () => {
            if (typeof web3 !== 'undefined') {
                console.log('Web3 Detected! ' + web3.currentProvider.constructor.name)
                this.setIsConnected(true);
            } else {
                console.log('No Web3 Detected... using HTTP Provider')
                window.web3 = new Web3(new Web3.providers.HttpProvider("https://mainnet.infura.io/v3/<api>"));
                this.setIsConnected(true);
            }
        })
    }

    subscribe(f) {
        this.observers.push(f);
    }

    unsubscribe(f) {
        this.observers = this.observers.filter(subscriber => subscriber !== f);
    }

    setIsConnected(status) {
        this.web3 = status;
        this.notify();
    }

    notify() {
        this.observers.forEach(observer => observer.run())
    }
}

Hope this helps someone in the future!

3
  • They do not recommend to connect when loading the page but to add an explicit button, see docs.metamask.io/guide/….
    – Ismael
    Aug 19 '20 at 6:38
  • @Ismael This looks like it's for account info, not for connecting to web3? Aug 19 '20 at 20:54
  • 1
    I don't think so, you cannot have access to web3 without enabling an account. They want the user to be aware when an webapp request access to metamask (for security reasons).
    – Ismael
    Aug 19 '20 at 22:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.