I am practicing creating a weather app and I want to fetch data using async await. But before that, I need to read the city name that user provides in search bar. In my current code, the async function tries to fetch data without the city being set in the query.
How can I handle this with best practices, such that this weather api call is made only after citname is retrieved?
Please find my code below:
'use strict';
(function() {
const inputEl = document.querySelector(".search-placholder");
let cityName = '';
const debounce = (func, wait, immediate) => {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
const handleSearchText= debounce(function(e) {
cityName = e.target.value;
console.log(cityName);
inputEl.placeholder = cityName;
}, 250);
inputEl.addEventListener("keyup", handleSearchText);
// make request to openweatherapi & make api call
async function getWeatherdata(event) {
const url = `http://api.openweathermap.org/data/2.5/weather?q=${cityName}&appid=2489ed561dc99d173a2f394574bc107e`;
const response = await fetch(url);
console.log(url)
return response.json();
event.preventDefault();
}
inputEl.addEventListener('submit', () => getWeatherdata());
})();
'use strict';
(function() {
const inputEl = document.querySelector(".search-placholder");
// Get the form element.
const formEl = document.querySelector('form.weatherdata-form');
let cityName = '';
const debounce = (func, wait, immediate) => {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
const handleSearchText = debounce((e) => {
cityName = e.target.value;
inputEl.placeholder = cityName;
}, 250);
inputEl.addEventListener("keyup", handleSearchText);
// make request to openweatherapi & make api call
async function getWeatherdata(event) {
const form = event.target.form;
const formData = new FormData(form);
let cityName = formData.get('city-name');
console.log(cityName)
const url = `http://api.openweathermap.org/data/2.5/weather?q=${cityName}&appid=2489ed561dc99d173a2f394574bc107e`;
const response = await fetch(url, {
method: 'POST',
body: formData
});
event.preventDefault();
return response.json();
}
const weatherDetails = formEl.addEventListener('submit', getWeatherdata);
console.log(weatherDetails)
})();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>My cool weather app</title>
<link href="https://fonts.googleapis.com/css?family=Raleway&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="index.css">
</head>
<body>
<main>
<div class="search-container">
<div class="search-bar">
<form class="weatherdata-form">
<i class="fa fa-search fa-3x" id="icon"></i>
<input type="text" class="search-placholder" placeholder="Type city to find weather..." name="city-name"/>
<!-- <button type="submit">Submit</button> -->
</form>
</div>
</div>
</main>
<script src="index.js"></script>
</body>
</html>
Add your submit event listener to the form element instead of the button directly. This will give you the posibility to extract all the values of form elements from your form with the FormData API.
Make sure that your input fields have the name attribute as we will use this to get the values you need.
<form class="weatherdata-form">
<input class="search-placholder" type="text" name="city-name"/>
<button type="submit">Submit</button>
</form>
// Get the form element.
const formEl = document.querySelector('form.weatherdata-form');
Modify your getWeatherdata function to extract the target property of the current Event. This will give us information which form this is that has been submitted. This opens up the possibility to make this function applicable to other forms.
Create an instance of FormData with the form as argument to create an extraction of your inputs with their names and values. With the FormData.get() method you can pick a single value from the form by giving its name. Inject that value in to your URL string and you're done here.
Edit
The form constant came up undefined and should have been event.target; No form was found and so no values were found. I've also added a check that if cityName is an empty string it will stop the function and not call the fetch. Remove the if statement if you want to call fetch without conditions.
async function getWeatherdata(event) {
const form = event.target;
const formData = new FormData(form);
const cityName = formData.get('city-name');
if (cityName === '') return;
event.preventDefault();
const url = `http://api.openweathermap.org/data/2.5/weather?q=${cityName}&appid=2489ed561dc99d173a2f394574bc107e`;
const response = await fetch(url);
const json = await response.json();
console.log(json);
}
Add the event listener to the form element and set the listener callback directly to the getWeatherdata function. Now the form will submit the event and open up all the values of the form to use.
formEl.addEventListener('submit', getWeatherdata);
Hope this helps you out, friend. If this didn't solve your question or you have more questions, please let me know.
Cheers!
Related
I have a todo html element whose inner html i want to save in localstorage through use of html but i am unable to figure out how i would do it.
My javascript code
// Load everything
// get DOM Elements
let to_do_input = document.getElementById("todo-input");
let addBtn = document.getElementById("addBtn");
let display = document.getElementsByClassName("display")[0];
// Event Listeners
addBtn.addEventListener("click", () => {
// Add DOM ELements
let list = document.createElement("ul");
let todos = document.createElement("li");
let deleteBtn = document.createElement("button");
deleteBtn.innerText = "Delete";
// let saveBtn = document.createElement("button");
// saveBtn.innerText = "Save";
display.appendChild(list);
list.appendChild(todos);
list.appendChild(deleteBtn);
// list.append(saveBtn);
// Class names
list.classList.add("list");
todos.classList.add("todos");
deleteBtn.classList.add("deleteBtn");
// saveBtn.classList.add("saveBtn");
// Set values
todos.innerHTML = to_do_input.value;
to_do_input.value = null;
// delete todo
deleteBtn.addEventListener("click", () => {
list.innerHTML = null;
});
// SAVE todo
// saveBtn.addEventListener("click", () => {
// // let arr = [];
// let savedTodo = arr.push(todos.innerHTML);
// localStorage.setItem("todo", JSON.stringify(savedTodo));
// });
// Set saved todo
});
and my html
<!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.0" />
<meta name="description" content="This web app provides you with accessibility of todo list" />
<title>Simple To-Do-List</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="container">
<h2>A Reliable To-Do-App</h2>
<div class="text-input center">
<input type="text" id="todo-input" placeholder="Write you task here.." />
<button type="button" id="addBtn" )>Add</button>
</div>
<div class="display"></div>
</div>
<script src="app.js"></script>
</body>
</html>
I have reviewed from other sites on how to do it but when i tried the array method , it returned numbers or when i tried to push todos into empty array , it didnt do anything. Also i dont know how i will convert the html element into an object to use it while making todo. Rest all the things work fine.
You need to set a array to save list,
So just edit your JS code to :
// Load everything
// get DOM Elements
let to_do_input = document.getElementById('todo-input')
let addBtn = document.getElementById('addBtn')
let display = document.getElementsByClassName('display')[0]
let todoArray = []
// Event Listeners
addBtn.addEventListener('click', () => {
// Add DOM ELements
let list = document.createElement('ul')
let todos = document.createElement('li')
let deleteBtn = document.createElement('button')
deleteBtn.innerText = 'Delete'
// let saveBtn = document.createElement("button");
// saveBtn.innerText = "Save";
display.appendChild(list)
list.appendChild(todos)
list.appendChild(deleteBtn)
// list.append(saveBtn);
// Class names
list.classList.add('list')
todos.classList.add('todos')
deleteBtn.classList.add('deleteBtn')
// saveBtn.classList.add("saveBtn");
// Set values
todos.innerHTML = to_do_input.value
todoArray.push(to_do_input.value)
to_do_input.value = null
// delete todo
deleteBtn.addEventListener('click', () => {
list.innerHTML = null
})
// SAVE todo
// saveBtn.addEventListener("click", () => {
// // let arr = [];
// let savedTodo = arr.push(todos.innerHTML);
// localStorage.setItem("todo", JSON.stringify(savedTodo));
// });
// Set saved todo
localStorage.setItem('todo', JSON.stringify(todoArray))
})
I received this code from another user in this forum.
Issue: As seen in the below screenshot, the search results (or data) starts to appear when you click or start typing in the search box or else only the search box loads without the data.
Requirement: I want to display the results (or data) as the page loads.
The code is given below
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<style>
.nav-link {
cursor: pointer;
}
</style>
</head>
<body>
<div class="container">
<ul class="nav nav-tabs">
<li class="nav-item">
<div class="nav-link"id="search-link">Search</div>
</li>
</ul>
<div id="app"></div>
<!-- Content here -->
</div>
<!-- Option 1: jQuery and Bootstrap Bundle (includes Popper) -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#4.5.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx" crossorigin="anonymous"></script>
<script>
var data;
function loadView(options){
var id = typeof options.id === "undefined" ? "app" : options.id;
var cb = typeof options.callback === "undefined" ? function(){} : options.callback;
google.script.run.withSuccessHandler(function(html){
document.getElementById("app").innerHTML = html;
typeof options.params === "undefined" ? cb() : cb(options.params);
})[options.func]();
}
function setDataForSearch(){
google.script.run.withSuccessHandler(function(dataReturned){
data = dataReturned.slice();
}).getDataForSearch();
}
function search(){
var searchinput = document.getElementById("searchinput").value.toString().toLowerCase().trim();
var searchWords = searchinput.split(/\s+/);
var searchColumns = [0,1,2,3,4,5,6,7];
// and or
var resultsArray = data.filter(function(r){
return searchWords.every(function(word){
return searchColumns.some(function(colIndex){
return r[colIndex].toString().toLowerCase().indexOf(word) !== -1
});
});
});
var searchResultsBox = document.getElementById("searchResults");
var templateBox = document.getElementById("rowTemplate");
var template = templateBox.content;
searchResultsBox.innerHTML = "";
resultsArray.forEach(function(r){
var tr = template.cloneNode(true);
var hinmokuColumn = tr.querySelector(".hinmoku");
var buhinCodeuColumn = tr.querySelector(".buhinCode");
var buhinNameColumn = tr.querySelector(".buhinName");
var hitsuyoColumn = tr.querySelector(".hitsuyo");
var genkaColumn = tr.querySelector(".genka");
var kobaiColumn = tr.querySelector(".kobai");
var sagakuColumn = tr.querySelector(".sagaku");
var kenshoColumn = tr.querySelector(".kensho");
hinmokuColumn.textContent = r[0];
buhinCodeuColumn.textContent = r[1];
buhinNameColumn.textContent = r[2];
hitsuyoColumn.textContent = r[3];
genkaColumn.textContent = r[4];
kobaiColumn.textContent = r[5];
sagakuColumn.textContent = r[6];
kenshoColumn.textContent = r[7];
searchResultsBox.appendChild(tr);
});
}
function loadSearchView(){
loadView({func:"loadSearchView", callback: setDataForSearch});
}
window.addEventListener("load", loadSearchView);
function inputEventHandler(e){
if (e.target.matches("#searchinput")){
search();
}
}
document.getElementById("app").addEventListener("input",inputEventHandler);
document.getElementById("app").addEventListener("click",inputEventHandler);
</script>
</body>
</html>
server-side code
function getDataForSearch(){
const ss = SpreadsheetApp.getActiveSpreadsheet();
const ws = ss.getSheetByName("TableData");
return ws.getRange(2, 1, ws.getLastRow(),8).getValues();
}
I need to know what modification needs to be done in the code?
I tried document.getElementById("app").addEventListener("load",inputEventHandler);
but it didn't work.
is there any other event listeners available that will load the search results (or data) (without taking any action on the site, i mean without clicking or typing in the search box)?
Thanks in advance.
Edit: loadsearchview function file code
function loadSearchView(){
return loadPartialHTML_("search");
}
You could use addEventListener with DOMContentLoaded to call a function when all the HTML is loaded and the DOM tree is built. For your particular situation, here's how I managed:
First I need to load data into data variable and call the loadSearchView() function when the page loads:
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", function () {
google.script.run.withSuccessHandler(function (r) {
data = r;
loadSearchView();
}).getDataForSearch();
});
} else {
google.script.run.withSuccessHandler(function (r) {
data = r;
loadSearchView();
}).getDataForSearch();
}
Then I need to load the search view, but instead of calling setDataForSearch, I implemented another function to call functions after this view is loaded. This might be useful if you want to call more than one function after the searchView loads. So basically the code would be like this:
function loadSearchView() {
loadView({ func: "loadSearchView", callback: afterSearchViewLoads });
}
function afterSearchViewLoads(){
loadDataWhenPageLoads();
}
function loadDataWhenPageLoads(){
var resultArray = data;
var searchResultsBox = document.getElementById("searchResults");
var templateBox = document.getElementById("rowTemplate");
var template = templateBox.content;
searchResultsBox.innerHTML = "";
resultsArray.forEach(function (r) {
var tr = template.cloneNode(true);
var hinmokuColumn = tr.querySelector(".hinmoku");
var buhinCodeuColumn = tr.querySelector(".buhinCode");
var buhinNameColumn = tr.querySelector(".buhinName");
var hitsuyoColumn = tr.querySelector(".hitsuyo");
var genkaColumn = tr.querySelector(".genka");
var kobaiColumn = tr.querySelector(".kobai");
var sagakuColumn = tr.querySelector(".sagaku");
var kenshoColumn = tr.querySelector(".kensho");
hinmokuColumn.textContent = r[0];
buhinCodeuColumn.textContent = r[1];
buhinNameColumn.textContent = r[2];
hitsuyoColumn.textContent = r[3];
genkaColumn.textContent = r[4];
kobaiColumn.textContent = r[5];
sagakuColumn.textContent = r[6];
kenshoColumn.textContent = r[7];
searchResultsBox.appendChild(tr);
});
}
Hope this can solve your problem!
AddEventListener when you click enter key in keyboard will help you. Link: EventListener Enter Key
Also addEventListener "change" will help you.
edit
If you want your data to load when page is loaded use one of those ways:
window.onload = function() {
Search();
} // way one
window.onload = Search(); //way two
<body onclick="Search()"> // way three
please am trying to integrate sending any trc20 token using tronlink by clicking a button on my website. I was able to send TRX using the JavaScript code below but I want to be able to send trc-20 like USDT, any help will be highly appreciated. Thanks
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div>
<input type="text" name="numb" id="numb">
<button onclick="sendtron()">Can you get tronweb from tronlink?</button>
</div>
<script>
function sendtron(){
var obj = setInterval(async ()=>{
if (window.tronWeb && window.tronWeb.defaultAddress.base58) {
clearInterval(obj)
var tronweb = window.tronWeb
var amount = document.querySelector('#numb').value;
var tokens = amount * 1000000
var tx = await tronweb.trx.sendTransaction("TWs2Z7dLMcPnXi9pnWqCUPzAnqUv6T54dy", tokens)
var signedTx = await tronweb.trx.sign(tx)
var broastTx = await tronweb.trx.sendRawTransaction(signedTx)
console.log(broastTx);
}
});
}
</script>
</body>
</html>
TRC20 are actually smart contracts. tronscan USDT link To transfer TRC20 from your address to another address, you will be calling TRC20's transfer function, below is a snippet of Tron USDT's code.
function transfer(address _to, uint256 _value) public returns (bool) {
require(_to != address(0));
require(_value <= balances[msg.sender]);
// SafeMath.sub will throw if there is not enough balance.
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
Transfer(msg.sender, _to, _value);
return true;
}
TronWeb TRC20 Contract Interaction documentation. You can use tronWeb's triggerSmartContract function to create a raw transaction, sign and broadcast.
create raw transaction
var senderAddress = tronweb.defaultAddress.base58;
var receiverAddress = "TV3nb5HYFe2xBEmyb3ETe93UGkjAhWyzrs";
var amount = 100;
var parameter = [{type:'address',value:receiverAddress},{type:'uint256',value:amount}]
var options = {
feeLimit:100000000
}
const transactionObject = await tronWeb.transactionBuilder.triggerSmartContract(
tronweb.address.toHex(contractAddress),
"transfer(address,uint256)",
options,
parameter,
tronweb.address.toHex(senderAddress)
);
Note: address are all in base58 format, we need to convert it to hex format using tronweb.address.toHex(address) at transactionObject. The parameter variable is where we set the receiver address and amount.
Sign
var signedTransaction = await tronWeb.trx.sign(transactionObject.transaction);
Broadcast
var broadcastTransaction = await tronWeb.trx.sendRawTransaction(signedTransaction);
console.log(broadcastTransaction);
Super new to all of this so this might be some beginner troubleshooting. The list seems to be working where I'm adding a list element to the UL with a checkbox and delete button. When checkbox is checked it puts a line through the text and when the delete button is clicked it deletes the list element. The assignment asks to save to localStorage so that when refreshed, the list items still remain, and I'm getting super confused by this. What I have now seems to be saving my list elements to an array but I don't understand how to get them to save and stay on the page.
const form = document.querySelector('form');
const input = document.querySelector('#todoInput');
const newElement = document.querySelector('ul');
const savedToDos = JSON.parse(localStorage.getItem('todos')) || [];
newElement.addEventListener('click', function(e) {
if(e.target.tagName === 'BUTTON') {
e.target.parentElement.remove()
}
})
function addToList(text) {
const li = document.createElement('li');
const checkbox = document.createElement('input');
const button = document.createElement('button');
button.innerText = "Delete";
checkbox.type = 'checkbox';
checkbox.addEventListener('change', function() {
li.style.textDecoration = checkbox.checked ? 'line-through' : 'none';
})
li.innerText = text;
li.insertBefore(checkbox, li.firstChild);
li.appendChild(button);
return li;
};
form.addEventListener('submit', function(e) {
e.preventDefault();
const newListItem = addToList(input.value);
input.value = '';
newElement.append(newListItem);
savedToDos.push(newListItem.innerText);
localStorage.setItem('todos', JSON.stringify(savedToDos));
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ToDo App</title>
<link rel="stylesheet" href="app.css">
</head>
<body>
<div>
<h1>Todo List</h1>
<form action="">
<input type="text" id="todoInput" placeholder="Add To Todo List">
<button class="add-button">Add</button>
</form>
<ul id="todoList">
</ul>
</div>
<script src="app.js"></script>
</body>
</html>
It looks like you're failing to populate the DOM when the page loads.
After you retrieve the items from local storage (which you're already doing), loop through the list and add each of them to the DOM:
// After this line, which you've already written:
const savedToDos = JSON.parse(localStorage.getItem('todos')) || [];
// Loop through savedToDos, and for each one, insert a new list:
savedToDos.forEach(function(value) {
const newListItem = addToList(value);
newElement.append(newListItem);
});
Every browser has local storage where we can store data and cookies. just go to the developer tools by pressing F12, then go to the Application tab. In the Storage section expand Local Storage.
this piece of code might help you
// Store Task
function storeTaskInLocalStorage(task) {
let tasks;
if(localStorage.getItem('tasks') === null){
tasks = [];
} else {
tasks = JSON.parse(localStorage.getItem('tasks'));
}
tasks.push(task);
localStorage.setItem('tasks', JSON.stringify(tasks));
}
I don't have coding experience, am in the process of learning.
I'm very very confuse as to what/how I should proceed setItem to localStorage and getItem from localStorage . So when webpage refresh, saved todo items would still be there.
I seen quite a few youtube videos and blog posts, but cant quite seem to understand .
I know I need to
-push input value into an array
-save that to localStorage with JSON.stringify
-when page refresh, check if there's data in localStorage
-if true, getItem from localStorage with JSON.parse
-if false, do nothing.
Can someone please explain like I'm five.
const toDoForm = document.querySelector('#todo-form');
const toDoInput = document.querySelector('#todo');
const ulList = document.querySelector('#ulList');
let dataArray = [];
toDoForm.addEventListener('submit', function (e) {
//stop submit event from refreshing
e.preventDefault();
//when submit -> create a element <li> link it with variable newLi
//Fill new <li>innerText</li> with toDoInput's value
const newLi = document.createElement('li');
newLi.innerText = toDoInput.value;
//when submit -> create a element <button></button> link it with variable btn
//<button>x</button>
//append <button>x</button> to newLi <li><button>x</button></li>
const btn = document.createElement('button');
btn.innerText = 'x';
newLi.appendChild(btn);
//add newLi <li><button>x</button></li> to ulList<ul></ul>
ulList.appendChild(newLi);
//push input into an empty array called dataArray
dataArray.push(toDoInput.value);
localStorage.setItem('localData', JSON.stringify(dataArray));
//when submit -> after all the above is done, we will set the input field to empty string
toDoInput.value = '';
});
ulList.addEventListener('click', function (e) {
if (e.target.tagName === 'BUTTON') {
e.target.parentElement.remove();
} else if (e.target.tagName === 'LI') {
e.target.classList.toggle('line');
}
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>TO DO LIST</h1>
<ul id="ulList">
</ul>
<form action="" id="todo-form">
<label for="todo">Write down things to do</label>
<input type="text" id="todo" name="todo">
<input type="submit">
</form>
<script src="app.js"></script>
</body>
</html>
You can extract the code to add a TODO item to a function and then call that function for each element in the array stored in localStorage if it is found.
let dataArray = localStorage.getItem('localData') ? JSON.parse(localStorage.getItem('localData')): [];
dataArray.forEach(addTodo);
function addTodo(todo){
const newLi = document.createElement('li');
newLi.innerText = todo;
//when submit -> create a element <button></button> link it with variable btn
//<button>x</button>
//append <button>x</button> to newLi <li><button>x</button></li>
const btn = document.createElement('button');
btn.innerText = 'x';
newLi.appendChild(btn);
//add newLi <li><button>x</button></li> to ulList<ul></ul>
ulList.appendChild(newLi);
}
toDoForm.addEventListener('submit', function (e) {
//stop submit event from refreshing
e.preventDefault();
addTodo(toDoInput.value);
dataArray.push(toDoInput.value);
localStorage.setItem('localData', JSON.stringify(dataArray));
//when submit -> after all the above is done, we will set the input field to empty string
toDoInput.value = '';
});
Demo