0

I have made a simple contract function where a user can write a message and then submit it to the array in the contract Messages:

  string[] public Messages; 

  function WriteMessage (string MessageInput) public {

    Messages.push(MessageInput);

}

On the frontend, I want to print in order all of the messages contained in the array. With one message it is very simple, you just write the call via Web3.js like this:

   Contract.WriteMessage(0, function(error, result) {
    if (!error) {
        $("#messagediv1").html("" + result);         
    } else
        console.error(error);
});

It's a bit confusing the syntax, but the 0 represents the first entry into the Messages array. In the div with the ID messagediv1, you will see the very first message printed. If you omit the entry number it will error. You cannot just download the whole array and then write something like this:

   Contract.WriteMessage(function(error, result) {
    if (!error) {
        $("#messagediv1").html("" + result[0]);    
        $("#messagediv2").html("" + result[1]); 
        $("#messagediv3").html("" + result[2]); 
        $("#messagediv4").html("" + result[3]);      
    } else
        console.error(error);
});

Is there a way to do a for loop on the this dynamic array until a result returns as invalid/null/0?

Note: Writing a getter function for the array does work, but you must transact each time to retrieve everything in the array.

1 Answer 1

3

Your Note: is nudging yourself in the wrong direction, I think.

I would separate concerns. Let's finish the contract first, then think about what the client can do.

First, walking off the end of an array is a nasty way to discover the length, so I would add:

function getMessageCount() public view returne(uint count) {
  return messageList.length; // <== (normal naming conventions)
}

Great. You would also want an event emitter for every important state change that unfolds inside the contract. This is not a firm standard or universally agreed. Let's call it a default stance while we avoid premature optimisation.

Above the functions ...

event LogNewMessage(address sender, string message);

Inside the state-changing function ...

emit LogNewMessage(msg.sender, message);

Great. Now the client has two ways to stay informed.

  1. Inspect the state. Go get the count first and start requesting messages, by row (starts at 0, and that's what the mysterious 0 in your code does).
  2. Listen to the event log from the block in which the contract was deployed.

You can combine those methods. That is, get the current state and then listen for real-time events.

Importantly, none of those read-only inspections sends a transaction, costs gas or requires waiting for mining. They will return as fast as the local client can fetch the data. This may or may not be fast enough for the client to do it every time. That's a performance concern that should be addressed as a separate concern.

Have a look over here for some guidelines: https://medium.com/solidified/the-joy-of-minimalism-in-smart-contract-design-b67fb4073422

Hope it helps.

2
  • My solution currently is to keep track of the total number of strings written to the array by adding a variable and doing this '''TotalMessages++''' each time a message is written. I can generate the correct number of divs now (which will contain the messages), but I can't figure out how to run the method of '''Contract.MessageArray(n,''' in a loop a variable number of times. I see no examples of looping the basic retrieval methods. I am able to print in the console log all of the messages in the array, so it seems it is just syntax of my loop preventing success. I will update later progre Commented Apr 15, 2018 at 9:17
  • You're in fact correct. Solution is to set a determinate array, and to loop through it. This was quite a fun exercise in exploring the limitations of Solidity and Web3.js. Perhaps there is a complicated way to create new arrays, or duplicate contracts, but for current needs, just setting an array to a large number will work for what I'm doing. Commented Apr 18, 2018 at 8:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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