2

I have a JS code which is connected to ganache. I am trying to call a solidity function which in tern emit the event. In JS i am watching the event. Now when i call the function first time it sets some values in the event and emit. I get that value in watch. But when i call it second time, I get the previous logs which i printed in UI and the current value comes after some time. In my UI, i just need the current value which is set by the solidity function, i do not want the previous value. Looks like JS continuously polling the watch and in first pass it prints the old value and then finally it prints the current value. I want certain things to work only and only when the new values are sent by event. How do i do that. Let me know if you need more information or code to view.

Solidity Code :- Below solidity function emit the event.

function getStudent(string _searchHash) payable public {
      var searchHash = _searchHash;
      university.transfer(msg.value);
      for(uint i=0; i<students.length; i++)
      {
          if (keccak256(students[i].hash) == keccak256(searchHash))
          {
              emit foundStudentInfo(students[i].fname, students[i].year, 
                   university.balance);
          }
      }
      emit foundStudentInfo("Failed","Failed",university.balance);
  }
}

Below is my JS code to watch for an event:- what is happening here is, i am able to get the event data back. But it prints the data even before metamask comes up and i complete the transaction. Once the metamask transaction is complete it again prints the data. This time it prints the latest data which i want to get from solidity function. I precisely want to stop the loader when i get the current data. But in below code my loader stops before I receive the actual data. I want just want to display the current value which solidity function is finding based on the given input parameters. But I am getting all the previous data and do not know what is the correct time to print the data. I am new to this technology so not sure my expectation is right or I need to do some more changes.

async function temp (){
   await Student.getStudent(hashCode, function(error, result){
   if(!error)
   {
       console.log('result in callback' + result);
   }
   else
      console.error(error);
   });
} //async temp ends. 

temp(); // calling temp. 

async function getEvent()  // function to watch event. 
 {
     var studentEvent = await Student.foundStudentInfo();
     eventData = await studentEvent.watch(function(error, result1){
     if (!error)
      {
        if (result)
        {
           console.log(result1.args);
           console.log(result1.blockHash);
           $scope.loading = false;
           $state.go('result');
         }
         else
         {
            console.log(error);
         }
      }              
});

console.log('event data' ||eventData);
}

getEvent();
5
  • Can you share your code? Chances are you are not starting your event search from block 0 rather than looking at the block after the first event is emitted. Commented Aug 31, 2018 at 5:53
  • I have added my code above. Please check.
    – SSS
    Commented Aug 31, 2018 at 6:38
  • Just a short advice: If you really need to store your student information in an array for specific reasons, you should also definitely make them searchable by storing that information a mapping, instead of iterating through an array. Besides being a bad practice, there was evidence that infura doesn't return function calls if they impose too much load on their system (e.g. metamask users won't be able to use your dApp, if the array to iterate over gets too big)
    – n1cK
    Commented Aug 31, 2018 at 9:53
  • ok....thanks. I will try to use mapping. Any good source for learning mapping?
    – SSS
    Commented Aug 31, 2018 at 9:58
  • Before you continue with solidity development, make sure you at least follow this tutorial: CryptoZombies Commented Aug 31, 2018 at 17:36

2 Answers 2

0

I think the trick here is, when the page loads, you need to first get the latest block. Then, when you set up the listener, only listen for events which happen after that block number.

Something like this:

async function getEvent()  // function to watch event. 
 {
     var latestblock = 0;
     web3.eth.getBlockNumber(function (error, result) {
         if (!error) {
            latestBlock = result;
         }
      });

     var studentEvent = await Student.foundStudentInfo({fromBlock: latestblock});
     eventData = await studentEvent.watch(function(error, result1){
     if (!error)
      {
        if (result)
        {
           console.log(result1.args);
           console.log(result1.blockHash);
           $scope.loading = false;
           $state.go('result');
         }
         else
         {
            console.log(error);
         }
      }              
});

You can see I added code to fetch the latest block number, and I added code which defines the fromBlock I want to start listening for events.

Let me know if this helps.

1
  • Please check my reply above. Thank you very much for your suggestion.
    – SSS
    Commented Aug 31, 2018 at 9:03
0
function temp (){
Student.getStudent(hashCode, function(error, result){
if(!error)
  {
      console.log('result in callback  -> ' + result);
  }
  else
    console.error(error);
 });
}

temp();

function getEvent()
{
  var studentEvent = Student.foundStudentInfo({fromBlock: result.currentBlockNumber});

  eventData = studentEvent.watch(function(error, result1){
    if (!error)
        {
            console.log('Block number in event -> '+ result.currentBlockNumber);
            if (result1)
            {
              if (result1.blockNumber > result.currentBlockNumber)
              {
                console.log(result1.args);
                $scope.loading = false;
               //
               result.currentBlockNumber = result1.blockNumber;
               console.log('New block numer -> '+result.currentBlockNumber)
               $state.go('result');
                   //var balance = web3.eth.getBalance(web3.eth.accounts[1]);
                   //console.log(balance);
                   //studentEvent.stopWatching();
               }
            }

           } 
           else
           {
                   console.log(error);
           }

      });
   }

   web3.eth.getBlockNumber(function (error, bcNumber) {
    if (!error) {
        result.currentBlockNumber = bcNumber;
      console.log('latestblock ->  '+ result.currentBlockNumber);
   }
   });

It did not worked as you have suggested but it did give me some idea to write more code around it to work as i wanted. Please check my code to see the changes. If condition if (result1.blockNumber > result.currentBlockNumber) helped me to stop Repetition. result.currentBlockNumber is just a global variable. The other change i made is to remove all async and await key words.

thank you very much!!

1
  • if it works, it works! Commented Aug 31, 2018 at 17:34

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.