0

I am trying to launch an Election-Dapp. I have these dependencies installed:
- Nodejs v9.11.1
- npm v5.8.0
- Truffle v4.1.3
- web3js v0.2
- ganache-cli

Below is my solidity contract

pragma solidity ^0.4.18;
contract Election {
    //model a candidate
    struct Candidate {
        uint id;
        string name;
        uint voteCount;
    }
    //fetch candidate
    mapping (uint => Candidate) public candidates;
    uint public candidatesCount;
    function Election() public {
        addCandidate("Blockchain");
        addCandidate("Groot");
    }
    function addCandidate(string _name) private {
        candidatesCount++;
        candidates[candidatesCount] = Candidate(candidatesCount, _name, 0);
    }
}

Here is my js and Web3 for the Dapp:

    App = {
  web3Provider: null,
  contracts: {},
  account: "0x0",

  init: function() {
    return App.initWeb3();
  },

  initWeb3: function() {
    if(typeof web3 !== 'undefined'){
      App.web3Provider = web3.currentProvider;
      web3 = new Web3(web3.currentProvider);
    } else {
      App.web3Provider = new Web3.providers.HttpProvider('http://localhost:8545');
      web3 = new Web3(App.web3Provider);
    }
    return App.initContract();
  },

  initContract: function() {
    $.getJSON('Election.json', function(election) {
      //Instantiate a new truffle contract from the artifact
      App.contracts.Election = TruffleContract(election);
      //connect provider to interact with contract
      App.contracts.Election.setProvider(App.web3Provider);
    });
    return App.render();
  },

  render: function() {
    var electionInstance;
    var loader = $("#loader");
    var content = $("#content");

    loader.show();
    content.hide();

    //load account data
    web3.eth.getCoinbase(function(err, account) {
      if(err == null) {
        App.account = account;
        $("#accountAddress").html("Your account: " + account);
      }
    });

    //load contract data
    App.contracts.Election.deployed().then(function(instance) {
      electionInstance = instance;
      return electionInstance.candidatesCount();
    }).then(function(candidatesCount){
      var candidatesResults = $("#candidatesResults");
      candidatesResults.empty();

      for(let i = 1; i <= candidatesCount; i++) {
        electionInstance.candidates(i).then(function(candidate) {
          var id = candidate[0];
          var name = candidate[1];
          var voteCount = candidate[2];

          //render candidate results
          var candidateTemplate = "<tr><th>" + id + "</th><td>" + name + "</td><td>" + voteCount + "</td></tr>";
          candidatesResults.append(candidateTemplate);
        });
      }

      loader.hide();
      content.show();
    }).catch(function(error) {
        console.warn(error);
    });
  }
};

$(function() {
  $(window).load(function() {
    App.init();
  });
});

This is the scrnshot of the issue: I can see my contract through the chrome console

Also I can interact with my contract using truffle console and JS promises like this:
enter image description here

Problem: why is it undefined?

P.S.: if it can help, here is a link to this project on my GitHub:
LINK TO GITHUB

Any help is appreciated, thank you.

  • The issue might be that getJSON is async, and you are calling App.render() in initContract before you are sure it has finished. Another possibility is that your json doesn't have the deployed address. If you know the address you can use App.contracts.Election.at(0xKnowAddress) instead of deployed(). – Ismael Apr 21 '18 at 21:53
  • @Ismael thank you, toggling my json request to {async: false} helped – Vlad Apr 24 '18 at 16:26
  • It doesn't sound like a good solution to me, is there a way to delay the rendering until the getJson returns? ie something like this ``` initContract: function() { $.getJSON('Election.json', function(election) { /* do something with election */ return App.render(); }); }, ``` – Ismael Apr 24 '18 at 16:50
  • 1
    @Ismael, tried that a minute before you answered :D Setting ajax to sync is deprecated, so yeah, it would be better assuring App.render() goes strictly after the ajax response. I will update the answer to this question. – Vlad Apr 24 '18 at 17:02
-1

The issue was that $.getJSON is asynchronous.
Setting it to synchronous solved the problem.

$.ajaxSetup({async: false});  

Thanks to @Ismael for help.

UPD:
Since synchronous ajax is deprecated, it would be better to assure that the ajax response isn't called before it actually got the response.
So in my case it was like this:

  initContract: function() {
$.getJSON('Election.json', function(election) {
  //Instantiate a new truffle contract from the artifact
  App.contracts.Election = TruffleContract(election);
  //connect provider to interact with contract
  App.contracts.Election.setProvider(App.web3Provider);
  return App.render();
});
//return App.render();},  

What I did is just replaced App.render() from where it is commented out up to the end of $.getJSON(){...} function.

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.