Ethereum Hello World Dapp Discussion

Hi,

I followed your suggestion and wrote the .js file with just two anonymous functions. Code below

(function (Contract) {
    var web3;
    var instance;



    function init(cb) {
        web3 = new Web3(
            (window.web3 && window.web3.currentProvider) ||
            new Web3.providers.HttpProvider(Contract.endpoint));

        var contract_interface = web3.eth.contract(Contract.abi);
        instance = contract_interface.at(Contract.address);
        cb();
    }


    // init function takes as argument the function cb() and does the following:
    // 1. creates a web3 object
    // 2. grabs abi from our contract and creates an instance of contract at the given address
    // 3. calls the function cb

    function getMessage(cb) {
        instance.message(function (error, result) {
            cb(error, result);
        });
    }

    // getMessage function retrieves message variable from contract and calls function cb

    function setMessage(){
                getMessage(function(error, result){
                    if(error){
                          console.error("Could not get artice:", error);
                          return;
                    }
                    $('#message').html(result);
                     });
    }


    // setMessage function sets the variable 'message' -in html file- to the value given by contract 



    function updateMessage() {
        let newMessage = $('#message-input').val();
        if(newMessage && newMessage.length > 0){
            instance.update.sendTransaction(newMessage, {from: "0xa48f2e0be8ab5a04a5eb1f86ead1923f03a207fd", gas: 30000000}, function(error, result){
                if(error){
                    console.log("error in sendTransaction");
                }
                else{
                    setTimeout(setMessage, 1000);
                }
            });
        }
        else{
            alert("Newmessage not defined");
        }
    }

    // updateMessage sends a transaction to function update in smart contract that sets
    // message variable to newMessage

    function documentreadyFunction(){
        init(setMessage);
          $('#submitButton').click(function (){
              updateMessage()
          });
    }

    $(document).ready(documentreadyFunction);

})(Contracts['HelloWorld']);

Now I understand more anonymous functions (thanks) but have another question, this time about how to read the code:

instance.message(function (error, result) {
            cb(error, result);
        })

I understand that instance.message ā€œlooksā€ at the variable message inside the smart contract but the next part inside on parenthesis is a function. What is this function? What does it do? I thought instance.message gives directly the string message, but no, I tried and does not work.

In other words, ā€œinstance.messageā€ (just like that) is a data that can be read by the .js file?

Good job! Iā€™m glad you took the opportunity to learn and rebuild.

In order to answer your question about the instance.message function we need to understand that instance.message is not variable. Message is a variable in the solidity contract, but now we are in the javascript file. So instance.message is a getter function, a function that will query the contract for the variable. It will return the message in the result parameter if everything goes correctly. If there is an error during the query it will return an error message in the error parameter.

When we get the response from the query we call our callback function, referred to as just cb. This functino is passed in through the variable in getMessage, as you can see below.

function getMessage(cb) {
        instance.message(function (error, result) {
            cb(error, result);
        });
    }

Then when we call getMessage, we make sure to pass in a function as the cb variable.

getMessage(function(error, result){
        if(error){
              console.error("Could not get artice:", error);
              return;
        }
        $('#message').html(result);
});
1 Like

Hi, everyone.

Just for fun, I was trying to get the webpage in HelloWorld dapp to display the address of the contract that is interacting with. So I wrote the function

    function  displayAddress(){ 
        let addressA=instance.options.address;
                     $('#displayedAddress').html(addressA);
    }

and include

<h3> Address: <span id="displayedAddress"></span></h3>

in the html file. But this does not work.

Any pointers that might help me solve this problem?

Whatā€™s the result? Any errors?

First of all, make sure that you call displayAddress() somewhere in your code. Then second of all I would console.log you addressA to actually see if gets fetched correctly from web3. Let me know how it goes. Would be happy to help you further.

Hi Filip,

I do call my function displayAddress(), inside documentreadyFunction like

function documentreadyFunction(){
        init(setMessage);
          $('#submitButton').click(function (){
              updateMessage()
          });
         displayAddress();
    }

In chromeā€™s console I got these errors:

jQuery.Deferred exception: Cannot read property 'address' of undefined TypeError: Cannot read property 'address' of undefined
    at displayAddress (about:srcdoc:96:38)
    at HTMLDocument.documentreadyFunction (about:srcdoc:107:10)
    at mightThrow (https://unpkg.com/[email protected]/dist/jquery.js:3534:29)
    at process (https://unpkg.com/[email protected]/dist/jquery.js:3602:12) undefined

and

jquery.js:3827 Uncaught TypeError: Cannot read property 'address' of undefined
    at displayAddress (VM227 about:srcdoc:96)
    at HTMLDocument.documentreadyFunction (VM227 about:srcdoc:107)
    at mightThrow (VM223 jquery.js:3534)
    at process (VM223 jquery.js:3602)

when conle.log my variable addressA gives me

console.log(addressA)
VM2530:1 Uncaught ReferenceError: addressA is not defined
    at <anonymous>:1:13
(anonymous) @ VM2530:1

I guess the address is not fetched correctly from web3? Donā€™t know why.

Ok, I think I might see the issue. Your displayAddress function will be called before the init function is finished. Your displayAddress function depends on the init function FIRST setting up the instance variable. Now you basically call displayAddress directly after you call init, so it wonā€™t have time to finish before you request the instance object.

I know this can be tricky to grasp. Javascript functions runs asynchronously, it wonā€™t wait for functions calls to finish. Thatā€™s why we pass a callback function to init. You would need to do like this.


function documentreadyFunction(){
     init(function () {
          setMessage();
          displayAddress();
     });
     $('#submitButton').click(function() {
          updateMessage();   
    });
}

Try my solution and let me know if you have more questions. But Iā€™m not 100% sure what your code does. Why call setMessage without any argument? What does it do?

Hi Filip,
I did try your solution but it did not work. I still have the same errors. I also try to implement your solution in the original script for the solution of the Hello World dapp and did not work. I also tried other contract options like gas but have same error, saying: can not read property gas nor address. I will put pause on this and come back later.

Can you send your entire code? There might be more errors that I couldnā€™t see.

Yes, thanks.

javascript

(function (Contract) {
    var web3;
    var instance;


    // init function takes as argument the function cb() and does the following:
    // 1. creates a web3 object
    // 2. grabs abi from our contract and creates an instance of contract from given address
    // 3. calls the function cb

    function init(cb) {
        web3 = new Web3(
            (window.web3 && window.web3.currentProvider) ||
            new Web3.providers.HttpProvider(Contract.endpoint));

        var contract_interface = web3.eth.contract(Contract.abi);
        instance = contract_interface.at(Contract.address);
        cb();
    }

    // getMessage function retrieves message variable from contract and calls function cb

    function getMessage(cb) {
        instance.message(function (error, result) {
            cb(error, result);
        });
    }

    // setMessage function sets the variable 'message' -in html file- to the value given by contract

    function setMessage(){
                getMessage(function(error, result){
                    if(error){
                          console.error("Could not get artice:", error);
                          return;
                    }
                    $('#message').html(result);
                     });
    }




    // updateMessage sends a transaction to function update in smart contract that sets
    // message variable to newMessage


    function updateMessage() {
        let newMessage = $('#message-input').val();
        if(newMessage && newMessage.length > 0){
            instance.update.sendTransaction(newMessage, {from: "0xa48f2e0be8ab5a04a5eb1f86ead1923f03a207fd", gas: 30000000}, function(error, result){
                if(error){
                    console.log("error in sendTransaction");
                }
                else{
                    setTimeout(setMessage, 1000);
                }
            });
        }
        else{
            alert("Newmessage not defined");
        }
    }


    //  displayAddress grabs address from instance and passes it to html
    
    function displayAddress(){
      let addressA=instance.options.address;
          $("#displayedAddress").html(addressA);
    }

    

    
    function documentreadyFunction(){
        init( function(){
            setMessage();
            displayAddress();
        });
          $('#submitButton').click(function (){
              updateMessage()
          });
    }

    $(document).ready(documentreadyFunction);

})(Contracts['HelloWorld']);

html


<!DOCTYPE html>
<html lang="en">
<head>
  <script type="text/javascript" src="https://unpkg.com/[email protected]/dist/jquery.js"></script>
  <script type="text/javascript" src="https://unpkg.com/[email protected]/dist/web3.min.js"></script>
  <!-- JAVASCRIPT -->        <!-- STYLE -->
</head>
  <body>

        <h1>Hello World DApp</h1>
        <h2>Message: <span id="message"></span>  </h2>
        
        <input type="text" id="message-input" />
        <button id="submitButton"> Submit </button>
        
        <h3> Address: <span id="displayedAddress">  </span></h3>
    </body>
</html>

and solidity

pragma solidity ^0.4.17;

contract HelloWorld {
    string public message;
    
    function HelloWorld(string message2) public {
        message=message2;
    }

    function update(string message2) public {
        message=message2;
    }
}

By the way, with this the dapp does not work, the message does not update. If I delete the lines corresponding to displayAddress function, then works fine. Thank you.

Thanks for sending the code. This will solve your problem. Address is available in instance.address and not options.address.

function displayAddress(){
    let addressA=instance.address;
    $("#displayedAddress").html(instance.address);
}

Yes, it works! thank you!. It was so easy.

1 Like

Haha yes, I make those types of issues sometimes as well. Where you spend hours trying to find it and itā€™s super simple :smiley:

In the code given below what is the use of return; inside the if(error) statement?

else{
setTimeout(function(){
getMessage(function(error, result){
if(error){
console.error(ā€œCould not get artice:ā€, error);
return;
}
$(ā€™#messageā€™).html(result);
});
}, 1000)

@filip forgot to mention you.

Hey,
Just having a small problem with this lecture. I have re-watched it 3 times and done exactly as Filip does but still when Iā€™m sending the message it does just nothing. Not even an error message.
here is my app.js code:

and app.html:

Does anyone see any problem?!
Thanks guys