おはようございます。
今回は前回の続きでフロントエンドの解説を行っていきます。
前回の記事はこちら
早速始めましょう。
フロントエンドの材料はすでにsrc/js/app.jsに入ってるのでそこを編集していきます。
画像やデザインはすでに用意されているので、スマートコントラクトが連結する部分を追記していきます。
1.app.jsを開き下記コードを記載する
App = {
web3Provider: null,
contracts: {},
init: function() {
$.getJSON('../pets.json', function(data) {
var petsRow = $('#petsRow');
var petTemplate = $('#petTemplate');
for (i = 0; i < data.length; i ++) {
petTemplate.find('.panel-title').text(data[i].name);
petTemplate.find('img').attr('src', data[i].picture);
petTemplate.find('.pet-breed').text(data[i].breed);
petTemplate.find('.pet-age').text(data[i].age);
petTemplate.find('.pet-location').text(data[i].location);
petTemplate.find('.btn-adopt').attr('data-id', data[i].id);
petsRow.append(petTemplate.html());
}
});
return App.initWeb3();
},
initWeb3: function() {
if (typeof web3 !== 'undefined') {
App.web3Provider = web3.currentProvider;
} else {
App.web3Provider = new Web3.providers.HttpProvider('http://localhost:7545');
}
web3 = new Web3(App.web3Provider);
return App.initContract();
},
initContract: function() {
$.getJSON('Adoption.json', function(data) {
var AdoptionArtifact = data;
App.contracts.Adoption = TruffleContract(AdoptionArtifact);
App.contracts.Adoption.setProvider(App.web3Provider);
return App.markAdopted();
});
return App.bindEvents();
},
bindEvents: function() {
$(document).on('click', '.btn-adopt', App.handleAdopt);
},
markAdopted: function(adopters, account) {
var adoptionInstance;
App.contracts.Adoption.deployed().then(function(instance) {
adoptionInstance = instance;
return adoptionInstance.getAdopters.call();
}).then(function(adopters) {
for (i = 0; i < adopters.length; i++) {
if (adopters[i] !== '0x0000000000000000000000000000000000000000') {
$('.panel-pet').eq(i).find('button').text('Success').attr('disabled', true);
}
}
}).catch(function(err) {
console.log(err.message);
});
},
handleAdopt: function(event) {
event.preventDefault();
var petId = parseInt($(event.target).data('id'));
var adoptionInstance;
web3.eth.getAccounts(function(error, accounts) {
if (error) {
console.log(error);
}
var account = accounts[0];
App.contracts.Adoption.deployed().then(function(instance) {
adoptionInstance = instance;
return adoptionInstance.adopt(petId, {from: account});
}).then(function(result) {
return App.markAdopted();
}).catch(function(err) {
console.log(err.message);
});
});
}
};
$(function() {
$(window).load(function() {
App.init();
});
});
【解説】
init: function() {
$.getJSON('../pets.json', function(data) {
var petsRow = $('#petsRow');
var petTemplate = $('#petTemplate');
for (i = 0; i < data.length; i ++) {
petTemplate.find('.panel-title').text(data[i].name);
petTemplate.find('img').attr('src', data[i].picture);
petTemplate.find('.pet-breed').text(data[i].breed);
petTemplate.find('.pet-age').text(data[i].age);
petTemplate.find('.pet-location').text(data[i].location);
petTemplate.find('.btn-adopt').attr('data-id', data[i].id);
petsRow.append(petTemplate.html());
}
});
return App.initWeb3();
},
これにより16匹のペットのデータが表示されます。
initWeb3: function() {
if (typeof web3 !== 'undefined') {
App.web3Provider = web3.currentProvider;
} else {
App.web3Provider = new Web3.providers.HttpProvider('http://localhost:7545');
}
web3 = new Web3(App.web3Provider);
return App.initContract();
},
ここでWeb3をインスタンス化しブロックチェーンと連携を可能にします。すでにアクティブなWeb3インスタンスがあるかどうかを確認します。既存のweb3インスタンスが存在する場合、そのプロバイダを取得してWeb3オブジェクトを作成します。
(ここの内容を公式から引用すると、ペットを採用した際にMetamaskが起動せず、連携が取れなかったです。上記は他の方のQiitaなどを参考に編集しました。これにするとうまくいきました。Version違いのせいでしょうか?理由がわからないので詳しい方が居ればコメント頂けると幸いです。)
initContract: function() {
$.getJSON('Adoption.json', function(data) {
var AdoptionArtifact = data;
App.contracts.Adoption = TruffleContract(AdoptionArtifact);
App.contracts.Adoption.setProvider(App.web3Provider);
return App.markAdopted();
});
return App.bindEvents();
},
これによりコントラクトをインスタンス化します。コントラクトを呼び出せる状態にします。
markAdopted: function(adopters, account) {
var adoptionInstance;
App.contracts.Adoption.deployed().then(function(instance) {
adoptionInstance = instance;
return adoptionInstance.getAdopters.call();
}).then(function(adopters) {
for (i = 0; i < adopters.length; i++) {
if (adopters[i] !== '0x0000000000000000000000000000000000000000') {
$('.panel-pet').eq(i).find('button').text('Success').attr('disabled', true);
}
}
}).catch(function(err) {
console.log(err.message);
});
},
ここではペットが採用されていればボタンをSuccessに変更し、ボタンを押してもトランザクションを起こさないコードを書いています。
まずadoptionInstance変数を宣言して、最初にインスタンスを取得した後にインスタンスにアクセスできるようにします。call()を使えばEtherなしで読み取ることができます。getAdopters()呼び出した後、ペットごとにアドレスが格納されているかどうかを確認します。 配列にはアドレス型が含まれているため、Ethereumは16個の空アドレスで配列を初期化します。このため、nullやその他のFalseの値ではなく、空のアドレス文字列をチェックします。
handleAdopt: function(event) {
event.preventDefault();
var petId = parseInt($(event.target).data('id'));
var adoptionInstance;
web3.eth.getAccounts(function(error, accounts) {
if (error) {
console.log(error);
}
var account = accounts[0];
App.contracts.Adoption.deployed().then(function(instance) {
adoptionInstance = instance;
return adoptionInstance.adopt(petId, {from: account});
}).then(function(result) {
return App.markAdopted();
}).catch(function(err) {
console.log(err.message);
});
});
}
};
Adoptと表示されたボタンを押せば、ペットを採用するコードです。
ボタンの要素からPetIdを取り出し、採用者のアカウントアドレスを取得し紐付けます。紐付けが成功すればApp.markAdopted()関数を呼び出し、ボタンをSuccessにします。失敗すればエラーメッセージを返します。
今回はcall()はない為トランザクションを送信します。取引には「差出人」アドレスが必要で、取引に関連してコストがかかります。
ブラウザにてペットショップを試すにはMetamaskが必要です。
1.Metamaskをインストール、設定する。
公式サイトはこちら
2.「Ganache」を起動して、一番初めのアドレス?(INDEX 0)の秘密鍵をコピーします。
3.Metamaskのimport Accountに先ほどの秘密鍵を貼り付け、追加します。
4.メニューの中から「Custom RPC」を選択し、「Current Network Main Ethereum Network」と表示されたフォームの中に「http://127.0.0.1:7545」と入力して「Save」を押します。
するとプライベートネットに接続されます。アカウントにGanacheと同じ金額のETHがあるのが確認できます。
1.ターミナルで下記コマンドを実行する。
nom run dev
実際にAdoptボタンを押して、Metamaskが起動し、AdoptがSuccessに変わっているか確認してみてください。
以上となります。
Dappsどんどん作っていきましょう!