Now let's build the frontend of our application. Our frontend will contain an editor, using which the user writes code. And when the user clicks on the compile button, we will dynamically display input boxes where each input box will represent a constructor argument. When the deploy button is clicked on, the constructor argument values are taken from these input boxes. The user will need to enter the JSON string in these input boxes.
Here is the frontend HTML code of our app. Place this code in the index.html file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="/css/codemirror.css">
<style type="text/css">
.CodeMirror
{
height: auto;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6">
<br>
<textarea id="editor"></textarea>
<br>
<span id="errors"></span>
<button type="button" id="compile" class="btn btn-primary">Compile</button>
</div>
<div class="col-md-6">
<br>
<form>
<div class="form-group">
<label for="address">Address</label>
<input type="text" class="form-control" id="address" placeholder="Prefixed with 0x">
</div>
<div class="form-group">
<label for="key">Private Key</label>
<input type="text" class="form-control" id="key" placeholder="Prefixed with 0x">
</div>
<hr>
<div id="arguments"></div>
<hr>
<button type="button" id="deploy" class="btn btn-primary">Deploy</button>
</form>
</div>
</div>
</div>
<script src="/js/codemirror.js"></script>
<script src="/js/main.js"></script>
</body>
</html>
Here, you can see that we have a textarea. The textarea tag will hold whatever the user will enter in the codemirror editor. Everything else in the preceding code is self-explanatory.
Here is the complete frontend JavaScript code. Place this code in the main.js file:
var editor = CodeMirror.fromTextArea(document.getElementById("editor"), {
lineNumbers: true,
});
var argumentsCount = 0;
document.getElementById("compile").addEventListener("click", function(){
editor.save();
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
if(JSON.parse(xhttp.responseText).errors != undefined)
{
document.getElementById("errors").innerHTML = JSON.parse(xhttp.responseText).errors + "<br><br>";
}
else
{
document.getElementById("errors").innerHTML = "";
}
var contracts = JSON.parse(xhttp.responseText).contracts;
for(var contractName in contracts)
{
var abi = JSON.parse(contracts[contractName].interface);
document.getElementById("arguments").innerHTML = "";
for(var count1 = 0; count1 < abi.length; count1++)
{
if(abi[count1].type == "constructor")
{
argumentsCount = abi[count1].inputs.length;
document.getElementById("arguments").innerHTML = '<label>Arguments</label>';
for(var count2 = 0; count2 < abi[count1].inputs.length; count2++)
{
var inputElement = document.createElement("input");
inputElement.setAttribute("type", "text");
inputElement.setAttribute("class", "form-control");
inputElement.setAttribute("placeholder", abi[count1].inputs[count2].type);
inputElement.setAttribute("id", "arguments-" + (count2 + 1));
var br = document.createElement("br");
document.getElementById("arguments").appendChild(br);
document.getElementById("arguments").appendChild(inputElement);
}
break;
}
}
break;
}
}
};
xhttp.open("GET", "/compile?code=" + encodeURIComponent(document.getElementById("editor").value), true);
xhttp.send();
})
document.getElementById("deploy").addEventListener("click", function(){
editor.save();
var arguments = [];
for(var count = 1; count <= argumentsCount; count++)
{
arguments[count - 1] = JSON.parse(document.getElementById("arguments-" + count).value);
}
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200)
{
var res = JSON.parse(xhttp.responseText);
if(res.error)
{
alert("Error: " + res.error)
}
else
{
alert("Txn Hash: " + res.result.hash);
}
}
else if(this.readyState == 4)
{
alert("An error occured.");
}
};
xhttp.open("GET", "/deploy?code=" + encodeURIComponent(document.getElementById("editor").value) + "&arguments=" + encodeURIComponent(JSON.stringify(arguments)) + "&address=" + document.getElementById("address").value + "&key=" + document.getElementById("key").value, true);
xhttp.send();
})
Here is how the preceding code works:
- At first, we add the code editor to the web page. The code editor will be displayed in place of textarea and textarea will be hidden.
- Then we have the compile button's click event handler. Inside it, we save the editor, which copies the content of the editor to textarea. When the compile button is clicked on, we make a request to the /compile path, and once we get the result, we parse it and display the input boxes so that the user can enter the constructor arguments. Here, we only read the constructor arguments for the first contract. But you can enhance the UI to display input boxes for constructors of all the contracts if there are more than one.
- And finally, we have the deploy button's click event handler. Here, we read the constructor arguments' value, parsing and putting them in an array. And then we add a request to the /deploy endpoint by passing the address, key, code, and argument value. If there is an error, then we display that in a popup; otherwise, we display the transaction hash in the popup.