How to put two function calls in a HTML file? - javascript

I'm learning Solidity (for smart contracts) and now need to design a UI to interact with a deploy contract.
Note: If the question is not relevant to this forum, please kindly let me know (instead of downvoting) and I'll remove it.
My HTML and .js files are as below. The problem is that, when I include both "distribute()" and "update_exchange_rate()" functions in .js file, my HTML file would not work. But I wouldn't have any problem if I remove either of them from .js file.
Question: Why am I having this problem? How to solve the above problem? Can I have multiple functions (definitions) in window.app?
Edit: If I put both functions in .js files, I also get webpack error. But the error will disappear if I remove one of the functions.
<!DOCTYPE html>
<html>
<head>
<script src="./app.js"></script>
</head>
<body>
<h1>MetaCoin</h1>
<h2>Example Truffle Dapp</h2>
<br>
<br><label for="amountB">Exchange rate:</label><input type="text"
id="amountA" placeholder="e.g., 95"></input>
<br><label for="receiverA">ReceiverA:</label><input type="text"
id="receiverA" placeholder="e.g., 95"></input>
<br><label for="receiverB">ReceiverB:</label><input type="text"
id="receiverB" placeholder="e.g., 95"></input>
<br><br><button id="send1" onclick="App.distribute()">Send
MetaCoin</button>
<br><br>
<br><label for="amountB">Exchange rate:</label><input type="text"
id="amountB" placeholder="e.g., 95"></input>
<br><br><button id="send2"
onclick="App.update_exchange_Rate()">update_exchange_Rate</button>
<br><br>
<br>
</body>
</html>
and my js file is:
import "../stylesheets/app.css";
import { default as Web3} from 'web3';
import { default as contract } from 'truffle-contract'
import metacoin_artifacts from '../../build/contracts/MetaCo.json'
var MetaCo = contract(metacoin_artifacts);
var accounts;
var account;
window.App = {
start: function() {
MetaCo.setProvider(web3.currentProvider);
web3.eth.getAccounts(function(err, accs) {
if (err != null) {
alert("There was an error fetching your accounts.");
return;
}
if (accs.length == 0) {
alert("Couldn't get any accounts! Make sure your Ethereum client is
configured correctly.");
return;
}
accounts = accs;
account = accounts[0];
});
},
setStatus: function(message) {
var status = document.getElementById("status");
status.innerHTML = message;
},
distribute: function() { // XXX Here is where the problem occures!
var amountA = parseInt(document.getElementById("amountA").value);
var receiver1= document.getElementById("receiverA").value;
var receiver2 = document.getElementById("receiverB").value;
var meta;
MetaCo.deployed().then(function(instance2) {
meta = instance2;
return meta.distribute(receiver1,receiver2, amountA,{from: account});
})
}
update_exchange_Rate: function() { // XXX Here is where the problem occures!
var amountB = parseInt(document.getElementById("amountB").value);
var meta1;
MetaCo.deployed().then(function(instance3) {
meta1 = instance3;
return meta1.update_exchange_Rate(amountB,{from: account});
})
}
};
window.addEventListener('load', function() {
if (typeof web3 !== 'undefined') {
console.warn("Using web3 detected from external source. If you find
that your accounts don't appear or you have 0 MetaCoin, ensure you've
configured that source properly. If using MetaMask, see the following
link.
Feel free to delete this warning. :)
http://truffleframework.com/tutorials/truffle-and-metamask")
// Use Mist/MetaMask's provider
window.web3 = new Web3(web3.currentProvider);
} else {
console.warn("No web3 detected. Falling back to http://localhost:8545.
You should remove this fallback when you deploy live, as it's
inherently
insecure. Consider switching to Metamask for development. More info
here:
http://truffleframework.com/tutorials/truffle-and-metamask");
// fallback - use your fallback strategy (local node / hosted node +
in-dapp id mgmt / fail)
window.web3 = new Web3(new
Web3.providers.HttpProvider("http://localhost:8545"));
}
App.start();
});

Let's take only this button, the other has the exact same problem...
<button id="send2" onclick="App.update_exchange_Rate()">update_exchange_Rate</button>
The onclick attribute expects to receive a Function. That function is then called on every click. But the function does not return a function itself...
App.update_exchange_Rate() will get executed as soon as that part is seen by the browser, and it's return value used. But that's not what we want! We want that function to be executed... So we'd need to give the function, and not the call to the attribute, like so:
<button id="send2" onclick="App.update_exchange_Rate">update_exchange_Rate</button>
or
<button id="send2" onclick="function(){App.update_exchange_Rate();}">update_exchange_Rate</button>
Now, if you do that you'll certainly end up in a scope you are not expecting. You aren't using this in the function so I'll skip that scoping part, you can read about it later if need be.

Related

Why is google apps script changing my user property to some random code every time I save it?

I am creating an editor add-on for google sheets and I'm currently stumped on why my user property (MY_WEBHOOK) is being changed every time I try to save it with setProperty to this code:
function(){var L=h(fb(arguments));if(b&32)Vd(function(){a.apply(g||this,L)});else return m(a.apply(g||this,L))}
Here is the code I am using:
code.gs:
function saveSettings(url) {
PropertiesService.getUserProperties().setProperty('MY_WEBHOOK', url);
SpreadsheetApp.getUi().alert("Saved")
}
function getSettings() {
return PropertiesService.getUserProperties().getProperty('MY_WEBHOOK');
}
In my html file:
<body onload="get()">
<form>
<label>What is the URL?</label>
<input id="webhook-url" type="url" autofocus required placeholder="Webhook Here">
<br><br>
<input type="button" value="Save" onclick="save()">
<script>
function save() {
var url = document.getElementById('webhook-url').value
google.script.run.saveSettings(url)
alert(url)
alert(google.script.run.getSettings)
google.script.host.close()
}
function get() {
var settings = google.script.run.getSettings
document.getElementById('webhook-url').value = settings;
}
</script>
</form>
</body>
Modification points:
I think that there are 2 modification points in your script.
About google.script.run.getSettings, in this case, the function of getSettings is not run. Please add () like google.script.run.getSettings(). By this, the function is run.
I think that this is the reason of your issue.
About alert(google.script.run.getSettings) and var settings = google.script.run.getSettings, google.script.run returns no value. So in this case, withSuccessHandler is used.
google.script.run is run with the asynchronous process.
When above points are reflected to your script, it becomes as follows.
Modified script:
Please modify your Javascript as follows.
function save() {
var url = document.getElementById('webhook-url').value
google.script.run.withSuccessHandler(() => {
google.script.run.withSuccessHandler(e => {
alert(e);
google.script.host.close();
}).getSettings();
}).saveSettings(url);
}
function get() {
google.script.run.withSuccessHandler(settings => {
document.getElementById('webhook-url').value = settings;
}).getSettings();
}
When above script is used, at first, the value is retrieved from getSettings by get(), and when the value is inputted and click button, the value is put by saveSettings() and the current value is retrieved by getSettings() and alert() is run, and then, google.script.host.close() is run.
Note:
This is a simple modification. So please modify it for your actual situation.
Reference:
Class google.script.run

How to stop JavaScript from generating an HTML file with nothing but a JS function call in it

When using an EventListener in a javascript file to call a function
document.getElementById("messageSubmit").addEventListener("click", getKey)
however, when running my code, JS throws a ReferenceError saying that getKey() is not defined (it is) and, to show me where the error occurred, points me to index.html, which now only contains one line: getKey(). When looking at the files in Inspect Element, my original index.html is there, and fully intact. What on earth is happening, and how do I go about fixing it?
I have tried changing getKey to getKey() in the EventListener, and I have tried deleting the new file, however my IDE does not recognise that the new file exists, or has ever existed. (my IDE is WebStorm by JetBrains)
I won't post the entire JS file, as it's ~50000 lines, but here's the problematic function and call.
async function startChat(user, userkey, userPubKey, oUID, position) { //Will start an encrypted chat between two users FIXME: Needs rewriting
targetUID = oUID;
var localUID = user.uid;
console.log(position);
var order = position === "true" ? localUID + " " + targetUID : targetUID + " " + localUID;
console.log(order);
var accepted;
await database.ref("/chats/" + order + "/accepted/" + targetUID + "/").once('value', function(snapshot) {
if(snapshot.val() != null) {
accepted = snapshot.val();
}
});
if (accepted === "true") {
database.ref("/chats/" + order + "/" + localuuid + "/messages/").on("child_added", (data, prevChildKey) => {
var newpost = data.val();
console.log(newpost);
Object.keys(newpost).sort();
console.log(newpost);
const ordered = Object.keys(newpost).sort();
// Object.keys(newpost).map((key, index) => {
//
//
// }).catch( (error) => {
// console.log(error.message);
// console.log(error.code);
// });
console.log(newpost['message']); //{Prints encrypted message(all messages looped)
console.log(newpost['date']);//Prints date stamp(all messages looped)
console.log(newpost['time']);//Prints time stamp(all messages looped)
console.log(newpost['sender']);//Prints sender uid(all messages looped)
//var decrypt = cryptico.decrypt(newpost['message'], userkey).plaintext;
// noinspection JSJQueryEfficiency
$("#chatField").append("<span>" + newpost['sender'] + "</span>");
// noinspection JSJQueryEfficiency
$("#chatField").append("<span>" + newpost['time'] + "</span>");
// noinspection JSJQueryEfficiency
$("#chatField").append("<span>" + newpost['message'] + "</span>");
}).catch( (error) => {
console.log(error.message);
console.log(error.code);
});
} else {
var myRef = firebase.database().ref("/chats/" + order + "/accepted/" + oUID).set("false");
}
document.getElementById("listHere").addEventListener("click", startChat);
error:
index.html:1 Uncaught ReferenceError: getKey is not defined
at HTMLAnchorElement.onclick (index.html:1)
On clicking on the linked index.html file, it shows:
getKey();
and nothing else.
How do I fix this, or, if there is no way, is there a workaround?
EDIT: Someone asked for HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<meta charset="UTF-8">
<link rel="stylesheet" href="ChatLayoutStyleSheet.css">
<title>ChatLayout</title>
<script src="cryptico/cryptico-js-master/lib/cryptico.js"></script>
</head>
<body>
<ul>
<li><a class="active" href="index.html">Home</a></li>
<li>Information</li>
<li>Chat</li>
<li>Groupchat</li>
<li>Sign In</li> <!-- DON'T TOUCH THIS -->
<li>Sign Up</li> <!-- DON'T TOUCH THIS EITHER -->
</ul>
<h1 style = "color: white;" id= "title">Welcome To Your Private Chat Room!</h1>
<h3 style = "color: white;" id="chatName">Invite your friends to start chatting</h3>
<div class = center2 id="chatField">Display Text Here</div>
<div class= center>
<label for="sendmessage" id="messageLabel">Send Message</label>
<input id="sendmessage" type="text" name="Type" placeholder="Type Here"><br>
<button type="submit" value="Send" id="messageSubmit">Send</button>
</div>
<div id="newchat">
<label for="findEmail" class="findChat">Search Emails</label>
<input id="findEmail" type="email" class="findChat">
<input id="findEmailSubmit" class="findChat" onclick="//parseSearchedEmails()" type="submit">
<button id="listHere" onclick=""></button>
<!-- ENCRYPTION PASSPHRASE INPUT REMOVED. DO NOT ADD THAT BACK. THANK YOU. -->
</div>
</body>
<footer>
<script src="bundledCHATJS.js" type="text/javascript"></script>
</footer>
</html>
It sounds like a scope problem (but it cannot be confirmed and solved with elements provided). Here's a very basic example with a raw closure that exports to global scope (basic of a web app noawadays) to demonstrate :
// Simulate a bundle with some exports
(function(global) {
function t1() {
alert('Success : all is done in the closure scope');
}
function t2() {
alert('Fails : callback not available in event setter scope');
}
// Exports to global scope
global.t3 = function() {
alert('Success : callback is exported to event setter scope');
};
// This will be set up within closure scope. It works
document.getElementById('test1').addEventListener('click', t1);
})(window)
// This will be set up within window scope and t3 available. It works
document.getElementById('test3').addEventListener('click', t3);
// This will be called within window scope and t2 not available. It fails.
document.getElementById('test2').addEventListener('click', t2);
<button id="test1">test 1 (OK)</button>
<button id="test2">test 2 (KO)</button>
<button id="test3">test 3 (OK)</button>
t2 do exist but is not available in current scope when setting up event callback, therefore the not defined error. The only way to solve this is to check code structure.
I'm not used to Webstorm and the kinda fake index.html might simply be an artifact from the debugger. The JS code you've provided is useless, it's the wrong HTML element id (listHere instead of messageSubmit) and there's no getKey on sight.
By the way, if you use addEventListener('click', myFunc()) instead of addEventListener('click', myFunc), it will run the callback when setting up listener and not when the event occurs.

Saving checkboxes asynchronously in Google Apps Script

I'm new to asynchronous calls and I think this is the problem. However, i'm not too sure how to fix it since Google Apps Script does not support promises and I also don't know how to use them. I've heard that if HTML Service is used in GAS, then promises are possible and this is what I'm using. However, I'm at a loss on how to implement this. Here is what I have so far. The main PROBLEM IS THAT I need the data to show in the second Logger.log on the server-side (code.gs) below. The data gets to the function in the first logger.log (code.gs), but then the object is empty (not null), when displaying the user cache in the second logger.log (code.gs). Any keys/data can be used and problem can be replicated, so it has something to do with asynchronous calls, but how do I fix it in the GUI_JS code?
Server-side (code.gs):
// global variable to save into the cache
var userCache = CacheService.getUserCache();
// SAVE OPERATION - saves the checkboxes into the user cache
function processSavedValues(checkboxesObj){
Logger.log(checkboxesObj); // this line shows in Logger
userCache.putAll(checkboxesObj, 20);
var getCache = userCache.getAll(['key1','key2']);
Logger.log(getCache); // this line doesn't show in Logger
}
// Loads the HTML Service of Apps Script
function doGet(request) {
return HtmlService.createTemplateFromFile('index').evaluate();
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
Client-side (index.html):
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form>
<fieldset class="columnList">
<div>
<input type="checkbox" id="key1" name="fieldset[]" value="value1">
<label class="checkmark" for="key1">test1</label>
</div>
<div>
<input type="checkbox" id="key2" name="fieldset[]" value="value2">
<label class="checkmark" for="key2">test2</label>
</div>
</fieldset>
</form>
<button onclick="saveAllCheckboxValues()">test</button>
<?!= include('GUI_JS'); ?>
</body>
</html>
Client-side using HTML Service (GUI_JS.html):
<script>
// Saves all checkbox values into the cache
function saveAllCheckboxValues(){
// Select all checkboxes in the document
var allCheckboxes = document.querySelectorAll("input[type=checkbox]");
// Create a Key/Value pairs with the IDs and values of each checkbox
var checkboxesObj = {};
for (var i = 0; i < allCheckboxes.length; i++) {
checkboxesObj[allCheckboxes[i].id] = allCheckboxes[i].checked;
}
// sends the checkbox values server-side into the cache
google.script.run.withSuccessHandler(checkboxSaved).processSavedValues(checkboxesObj);
// displays successfully saved
function checkboxSaved(){
alert("Great Success!");
}
}
</script>
The result of Logger.log:
[19-03-14 18:28:38:913 PDT] {key1=true, key2=true}
[19-03-14 18:28:38:959 PDT] {}
I think that the reason of your issue is the boolean values in the object for putting to CacheService. At CacheService, the string value is used for putting. So how about this modification? Please think of this as just one of several answers. In my modification, the function of processSavedValues() was modified.
Modified script:
function processSavedValues(checkboxesObj){
Logger.log(checkboxesObj);
userCache.put("sampleKey", JSON.stringify(checkboxesObj), 20); // Modified
var getCache = userCache.get("sampleKey"); // Modified
getCache = JSON.parse(getCache); // Added
Logger.log(getCache);
}
References:
put(key, value)
get(key)
If this didn't work and this was not the result you want, I apologize.

Recaptcha.create works locally but not on server

I've got an Google Recaptcha it uses the Recaptcha.create. However for some reason the Recaptcha.create works locally but not on the server. Here is my html and js.
HTML
<script type="text/javascript" src="http://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script>
<div id="recaptcha"></div>
<div id="fError">Waiting for input.</div>
<script src="/assets/js/upload-flash.js"></script>
And this is the upload-flash.js
var captchaused = false;
function showRecaptcha() {
Recaptcha.create("6LfHYvgSAAAAAJ9G7fNYW5vwQkxUZDNSFhweiOPp", "recaptcha", {
theme: "clean",
callback: Recaptcha.focus_response_field});
}
function fileSelected() {
var file = document.getElementById('fileToUpload').files[0];
if (file) {
if(captchaused === false){
captchaused = true;
showRecaptcha();
} else {
Recaptcha.reload();
}
}
}
/*... and after this comes the uploading part. Removed it so that it doesn't become too long*/
Here are pictures
Local
Server
I made a mistake with the public and private keys I get from google and used the wrong ones. After changing the keys I used it started working perfectly again.

Why don't my Javascript prompts show up from my Express.IO .ejs file?

I am relatively new to JavaScript and subsequently Node + Express.IO. I am trying to build a page that will track in real time connections made by different 'users' to the server. Consequently, when I do include all the functions from the io module, my prompt() and alert do not work anymore. I am running nodemon app.js from my terminal and no compilation errors are showing up when I do so. The alert and prompt work again when I remove all the io functions.
These are the contents of my index.ejs <body> tag:
<body>
<h1>Chatroom</h1>
<script>
alert("Hello!");
var name = prompt("What is your name?");
io.connect();
io.emit.('got_a_new_user', {name: name});
io.on('new_user', function(data) {
//render this new info in the HTML
var users = data.users;
console.log(users);
if (users != undefined) {
console.log("\n\n\n" + users);
// if users is defined, append the new division containing the username
}
});
io.on('disconnect_user', function(data) {
var users = data.users;
if (users != undefined) {
// If users is defined remove the corresponding HTML element
}
});
</script>
<div id="container">
</div>
</body>
Any help would be much appreciated.
Adding example for the comment added by UKatz,
You will have to connect socket.io from the client as follows,
index.ejs
<script src="http://ip:port/socket.io/socket.io.js"></script>
<script type="text/javascript">
var socket = io.connect('http://ip:port');
socket.emit('got_a_new_user', {name: name});
</script>
Check socket.io documentation for how to connect socket.io with client.

Categories