Issue interfacing smart contract with the front end - javascript

I'm actually trying to write a simple smart contract with front end that takes a value from the user and saves that in the variable in the smart contract.
The index.html part of my project is
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Example</title>
<!-- Bootstrap -->
<link href="css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div id="message"></div>
<form method="POST">
<div><input id= "message" name = "message" type= "text">
</div>
<div>
<button type="button" id="register">Register</button>
</div>
</div>
</form>
<script src="js/bootstrap.min.js"></script>
<script src="js/web3.min.js"></script>
<script src="js/truffle-contract.js"></script>
<script src="js/app.js"></script>
</body>
</html>
And app.js is
App = {
web3Provider: null,
contracts: {},
account: '0x0',
init: function() {
return App.initWeb3();
},
initWeb3: function() {
if (typeof web3 !== 'undefined') {
// If a web3 instance is already provided by Meta Mask.
App.web3Provider = web3.currentProvider;
web3 = new Web3(web3.currentProvider);
} else {
// Specify default instance if no web3 instance provided
App.web3Provider = new Web3.providers.HttpProvider('http://localhost:7545');
web3 = new Web3(App.web3Provider);
}
return App.initContract();
},
initContract: function() {
$.getJSON("HelloWorld.json", function(hello) {
// Instantiate a new truffle contract from the artifact
App.contracts.HelloWorld = TruffleContract(hello);
// Connect provider to interact with contract
App.contracts.HelloWorld.setProvider(App.web3Provider);
return App.bindEvents();
});
},
bindEvents: function() {
$(document).on('click', '#register', function(){ var msg = $('#message').val(); App.handleMessage(msg); });
},
handleMessage: function(msg){
var hwinstance;
App.contracts.HelloWorld.deployed().then(function(instance) {
hwinstance = instance;
return hwinstance.setMessage(msg);
}).then( function(result){
if(result.receipt.status == '0x01')
alert("successfully")
else
alert("failed due to revert")
}).catch( function(err){
alert("failed")
})
}
};
$(function() {
$(window).load(function() {
App.init();
console.log('starting app.js');
});
});
The smart contract code that I've written is
pragma solidity 0.5.16;
contract HelloWorld {
string private message = "hello world";
function getMessage() public view returns(string memory) {
return message;
}
function setMessage(string memory newMessage) public {
message = newMessage;
}
}
When I ran the commands truffle complie and truffle migrate, it showed no errors but when I ran 'npm run dev' the page says "Cannot GET /".
I'm not able to understand where the mistake is. Please help!
Is there any other way of interfacing the frontend to the smart contract?

Your local server cannot find your page either because it is in the wrong directory or the local server has not been installed. Run npm install --save-dev lite-server. In the package.json you should have something like
"script": {
"dev": "lite-server",
...
}
Move your index.html and App.js into src/ directory you create at the root of the project. Run npm run dev to check again. It should work. If you are interested in an easy to use truffle box with react, I have developed a truffle box with React + Material-UI. Take a look here https://github.com/rouftom/truffle-react-material

Related

API call returns image after I render the components

I'm using g-s-i a npm package to make calls to google images.
I'm unable to make this API call and, just after, render the application. I'm aware this has to do with async, but I have no idea how to use it here. I have tried many things with the function imageSearch, but nothing has worked.
I thank if someone can show me a solution to my problem.
My MWE:
HTML:
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Debug example</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<!-- Place favicon.ico in the root directory -->
</head>
<body>
<h1>Debugger example</h1>
<div id="main">
</div>
</body>
<script type="module" src="./dist/bundle.js">
</script>
</html>
JS:
var gis = require('g-i-s'); // search images from google https://www.npmjs.com/package/g-i-s
var main = document.querySelector("#main")
// Query examples
var searchTopics = [
{
searchTerm: 'sleep',
queryStringAddition: '&tbs=ic:trans'
},
{
searchTerm: 'pony',
queryStringAddition: '&tbs=ic:trans',
filterOutDomains: ['deviantart.net', 'deviantart.com']
}
];
var imageSearch = (query) => {
let response = [];
gis(query, (error, results) => {
console.log(results[1].url)
response.push(results[1].url)
}
)
return response;
};
// =results= look like:
// [
// {
// "url": "https://i.ytimg.com/vi/mW3S0u8bj58/maxresdefault.jpg",
// "width": 1280,
// "height": 720
// },
// {
// "url": "https://i.ytimg.com/vi/tntOCGkgt98/maxresdefault.jpg",
// "width": 1600,
// "height": 1200
// },
// (...)
// ]
var imageLayout = (title) =>
((src) => {let e = document.createElement("div")
e.innerHTML = title
let img = document.createElement("img")
img.src = src
e.appendChild(img)
return e})
var render = (queries) => {
queries.forEach((query) =>{
let img = imageSearch(query)
console.log(img)
main.appendChild(imageLayout(query.searchTerm)(img[0]))
})}
render(searchTopics)
NPM:
npm init
npm install g-i-s
npm install --save-dev browserify #babel/core #babel/preset-env babelify
browserify js/main.js > ./dist/bundle.js -t babelify
watchify js/*.js -o ./dist/bundle.js -d
What happens in my browser:
Your imageSearch function calls gis() which doesn't successfully create the response object until the callback passed as the second parameter to gis() is called. However, you're immediately returning the empty response array.
Instead, pass a callback in to imageSearch that gets called when gis() returns, something like this:
const imageSearch = (query, cb) => {
gis(query, (error, results) => cb(error, results[1].url));
};
const render = (queries) => {
queries.forEach((query) => {
let img = imageSearch(query, (error, img) => {
if (error) {
console.log("An error happened: ", error);
return;
}
main.appendChild(imageLayout(query.searchTerm)(img))
});
});
};
You could also move on to using Promises but that's a different matter, and would not largely change the outcome of the code, just the format of it.

electron js - cannot get button to perform simple actions from click

Long story short I am working on a single page application that sends commands over a local network. Testing out Electron JS and I can't even seem to get a simple button to work. I feel like I am not linking the logic between main.js and index.js somehow but for the life of me I cannot figure out the correct way to do it. I have even put breakpoints in index.js and through main.js & index.html but none of the breakpoints are hit aside from the ones in main.js. I put a simple function in a preload.js file and that function is correctly called but the one I am trying to attach to a button located in index.html and index.js is never even being hit. A lot of the commented out code is things I want to remember or things I have noticed a different method of creating and just wanted to try and see if that worked. If anyone has any answers or guidance it would be greatly appreciated! :D
Below is my main.js
//#region ---for dev only | hot reload
try {
require('electron-reloader')(module)
} catch (_) {}
//#endregion
const electron = require('electron');
const {app, BrowserWindow, Menu} = require('electron');
const path = require('path');
const ipcMain = electron.ipcMain;
//#region globals
const SRC_DIR = '/src/'
const IMG_DIR = '/assets/images'
//#endregion
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
//frame: false,
webPreferences: {
contextIsolation: true,
preload: path.join(__dirname, 'preload.js')
}
});
//Used to auto open dev tools for debugging
//win.openDevTools();
win.loadFile('src/index.html');
// win.loadURL(url.format({
// pathname: path.join(__dirname, 'index.html'),
// protocol: 'file',
// slashes: true
// }));
}
app.whenReady().then(() => {
//nativeTheme.shouldUseDarkColors = true;
createWindow();
})
//closes app processes when window is closed
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit();
})
var menu = Menu.buildFromTemplate([
{
label: 'Menu',
submenu: [
{label: 'Edit'},
{type: 'separator'},
{
label: 'Exit',
click() {
app.quit();
}
}
]
}
])
Menu.setApplicationMenu(menu);
Here is index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Ecas Software</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<p id="myText">Let's get started :)</p>
<button id="myBtn">Change Text</button>
<script type="text/javascript" src="./index.js" ></script>
</body>
</html>
Lastly here is my index.js (aka my first and only renderer?)
const electron = require('electron');
const chgBtn = document.getElementById('myBtn');
function replaceText(selector, text){
const element = document.getElementById(selector);
if (element) element.innerText = text;
}
chgBtn.onclick = function() {
replaceText('myText', 'no boom...');
}
// chgBtn.addEventListener('click', function(){
// // if (document.getElementById('myText').innerText == 'boom'){
// // replaceText('myText','no boom...');
// // } else {
// // replaceText('myText','boom');
// // }
// document.alert("working function");
// });
//chgBtn.addEventListener('click', replaceText('myText','no boom...'));
Why you have this error
The problem here is that you didn't use your scripts files the way Electron was intended.
If you use the Devtools Console (by uncommenting win.openDevTools()), you should see this error in your console :
Uncaught ReferenceError: require is not defined (from index.js file)
This is because your index.js file is loaded as a "normal javascript file". If you want to use the Node syntaxe (aka the "require" syntaxe), you need to do it in your preload script. Only the preload script can use the require syntaxe, since it is the only script allowed by Electron to use Node.
You can also use other javascripts files, by import it in your HTML as you did for the index.js file, but you should remove the require call. As the "require" call (on the first line) will throw and error, all the following code will not run. This is why your button did not react on click.
The correct way to do it
If you need to use some methods from the Electron Renderer API (such as the ipcRenderer), you need to put it in your preload script.
If you want to use your own script, in a separate file, you can also do it, you will not be able to directly call Electron API. There is a solution if you want to call the Electron API in your own script, it is called the Context Bridge. This allows you to create an object in your preload script, that can use the Electron API. You can give this object a name, and then call it from your others script by using the window global object.
For example, if you want to use ipcRenderer.send(channel, payload) :
// Preload script
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('theNameYouWant',
{
send: (channel, payload) => ipcRenderer.send(channel, payload)
}
)
// index.js file, imported in your HTML file
window.theNameYouWant.send("channel-name", { someData: "Hello" })
In your example
// Add this in your main.js file to see when a user click on the button from main process
ipcMain.on("button-clicked", (event, data) => console.log(data))
// Preload script
const { contextBridge, ipcRenderer } = require("electron")
contextBridge.exposeInMainWorld("electron", {
send: (channel, payload) => ipcRenderer.send(channel, payload),
})
// index.js
const chgBtn = document.getElementById("myBtn")
function replaceText(selector, text) {
const element = document.getElementById(selector)
if (element) element.innerText = text
}
chgBtn.onclick = function () {
replaceText("myText", "no boom...")
window.electron.send("button-clicked", { someData: "Hello" })
}

Exporting object in Webpack 5

I'm building a JS library with Webpack and trying to export an object.
import jwt_decode from "jwt-decode";
console.log(location.hash.replace('#', ''));
export var upstream = {
user: {
getUserDetails: () => {
if (location.hash) {
return jwt_decode(location.hash.replace('#', ''));
} else {
return null;
}
}
}
}
In my client-side code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>UpStream</title>
</head>
<body>
<script src="http://localhost:8080/app.js"> <!--server is up, connects fine-->
</script>
<script>
console.log(upstream);
</script>
</body>
</html>
The console.log(); statement works as intended, but I cannot access the upstream object. Any pointers?
To be able to access upstream via window or just upstream you would need to ensure you specify the export as a Library with libraryTarget of 'window'.
Hopefully that helps!

Keycloak login returns 404 using JavaScript adapter

I'm using Keycloak's bower package to create a very basic demo HTML/JS app. I have Keycloak running locally and keycloak.init() seems to work (no error triggered). However when I call keycloak.login() a 404 is returned. Might the login URL be wrongly created by the adapter?
The URL returned by keycloak.createLoginUrl() is
https://<keycloak url>/realms/<realm>/protocol/openid-connect/auth?client_id=account&redirect_uri=file%3A%2F%2F%2FUsers%2Fjgallaso%2FProjects%2Fdemos%2Fkeycloak-simple-web-client%2Findex.html&state=b167dc0b-3e5b-4c67-87f7-fd5289fb7b8f&nonce=1e2cb386-51db-496a-8943-efcf4ef5d5e1&response_mode=fragment&response_type=code&scope=openid
And this is my entire code:
<head>
<script src="bower_components/keycloak/dist/keycloak.min.js"></script>
</head>
<body>
<button id="login">Login</button>
</body>
<script>
var keycloak = Keycloak({
url: 'https://keycloak-keycloak.192.168.37.1.nip.io',
realm: 'demo',
clientId: 'account'
});
keycloak.init()
.success(authenticated => {
document.getElementById("login")
.addEventListener("click", () => { keycloak.login(); });
}).error(err => {
console.log("init, error: " + err);
});
</script>
</head>
Response is a plain:
ERROR 404: Not Found
You have 2 posibilities :
invoque login automatically in init method
login manually after call init without params
1)
<head>
<script src="bower_components/keycloak/dist/keycloak.min.js"></script>
</head>
<body>
<button id="login">Login</button>
</body>
<script>
var keycloak = Keycloak({
url: 'https://keycloak-keycloak.192.168.37.1.nip.io',
realm: 'demo',
clientId: 'account'
});
keycloak.init('login-required')
.success(function(authenticated) => {
}).error(err => {
console.log("init, error: " + err);
});
</script>
</head>
2)
keycloak.init().success(function(authenticated) {
if(authenticated == true){
alert('usuario logeado');
}else{
alert('usuario no logeado');
keycloak.login();
}
}).error(function() {
alert('failed to initialize');
});
I had trouble trying directly from the management.
file://c:/example.html
To do a better test you should leave your index.html on a local test server.
What I did was install the web server plugin for chrome and it worked for me.
I hope it'll help you.
regards

Workbox, staleWhileRevalidate called only once on image

I'm developing a PWA and I'm trying to use workbox to manage the service-worker and the caching of assets.
In my PWA I have to show all the newer images if the device is online and, if not, the images in the cache.
When I try to implement it I see that the staleWhileRevalidate method on image is called only once in the page for each image, also if I try to refresh multiple times. I need to close the webpage and when I reopen it the image is updated correctly. It's normal that it work in this way?
When I try it with localhost, the staleWhileRevalidate is called every time I reload the page, but when I load the website on a remote server, the app does not work anymore in this way.
service-worker.js:
importScripts('workbox-sw.prod.v2.0.0.js');
const workboxSW = new WorkboxSW();
var CACHE_NAME = 'my-cache';
var filesToCache = [
'imgs/images.png',
'index.html'
];
self.addEventListener('install', function(e) {
console.log('[ServiceWorker] Install');
e.waitUntil(
caches.open(CACHE_NAME).then(function(cache) {
console.log('[ServiceWorker] Caching App Shell');
return cache.addAll(filesToCache);
})
);
});
workboxSW.router.registerRoute(
/.*\/imgs\/(.*\/)?.*\.(png|jpg|jpeg|gif)/,
({event}) => {
console.log("staleWhileRevalidate called);
return workboxSW.strategies.staleWhileRevalidate({cacheName: CACHE_NAME}).handle({event}).catch((error) => {
console.log("Error staleWhileRevalidate");
return error;
});
}
);
index.html:
<!DOCTYPE html>
<html>
<head >
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title class="title">PWA</title>
</head>
<body>
<div class="container">
<img src="imgs/image.png">
</div>
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('service-worker.js').then(function(registration) {
console.log('ServiceWorker registration successful);
}, function(err) {
console.log('ServiceWorker registration failed: ', err);
});
});
}
</script>
</body>
</html>
Installing (not in localhost)
First Reload (not in localhost)
Second Reload (and more times)

Categories

Resources