When making a new XMLHttpRequest, like so
let http = new XMLHttpRequest();
There is a method (property ?) called onload. My question is, why we can assign a function to it? like this
http.onload = function(){};
If onload is a property in XMLHttpRequest, the value of it will change when we assign a new value to it, like a function, right?
What is the XMLHttpRequest.onload constructor looks like?
I am really confused about this.
When we first started writing HTML event handlers, we would write
<button onclick="alert('Hey you')"> Say Hi</button>
When you translate the HTML into the DOM, you get a reference to an object and you can also set that event handler by setting a property to a function. The browser will call that function for you when the user clicks the button. This is a poor man's event system using properties as callbacks.
Those were the two ways to set an event handler:
XML attribute
DOM element reference by setting a property
After a while, they realized that multiple listeners may need to be set (overwriting a property would override the previous listener). We created hacks to allow setting multiple handlers by creating function that called other functions and there was a need for a real event system. The DOM element became an EventTarget, and you can now use a more common Event interface.
buttonEl.addEventListener('click', () => console.log('clicked'));
buttonEl.addEventListener('click', () => console.log('second handler'));
So we have three different ways of setting events. XmlHttpRequest also implements its own XMLHttpRequestEventTarget event target, so you can set "events" in both ways, through callback properties and addEventListener.
In your question, you said: "What is the XMLHttpRequest.onload constructor looks like?" You probably meant how can we override the onload property because a property doesn't have a constructor, its value has a constructor, but we typically assign it using a literal. It's initially unset (undefined), if it's never set, it won't get called.
It uses XMLHttpRequest() in its program;
Everything works on the ChromeDev per-browser. However, when I try to run the page in other browsers this method is blocked.
[enter image description here][1]
[1]: https://i.stack.imgur.com/mfE0k.png
In the MDN documentation it is written that currently the method is supported by all browsers.
Does anyone know why I can't run my script in other browsers?
function loadDocumentCsv() {
const xhttp = new XMLHttpRequest();
xhttp.onload = function () {
const request = this.responseText.toString();
const allRecords = downloadElement("#allRecords");
const isofixTrue = downloadElement("#isofixTrue");
const brandSort = downloadElement("#brandSort");
const sortMileageAndIsofixFalse = downloadElement("#sortMileageAndIsofixFalse");
allRecords.innerHTML = "";
isofixTrue.innerHTML = "";
brandSort.innerHTML = "";
sortMileageAndIsofixFalse.innerHTML = '';
const arrayData = request.replace(/\n/g, ",").split(",");
const newArray = arrayData.map((element, index) => {
element.trim();
if (index > 4) {
if (index % 5 === 2) {
const cutLetters = element.replace(/[^0-9]+/, "");
element = Number(cutLetters.substring(cutLetters.length - 4, cutLetters.length));
if (element == 0) element = 2007;
} else if (index % 5 === 3) {
element = Number(element.replace(/[^0-9]+/, ""));
} else if (index % 5 === 4) {
element = element.trim() === "TRUE";
}
}
return element;
});
const arrayOfArrays = [];
while (newArray.length) {
const addArrayToArrays = newArray.splice(0, 5);
arrayOfArrays.push(addArrayToArrays);
}
//header table
const header = arrayOfArrays.splice(0, 1);
const firstRow = (table) =>
header.forEach((el) => {
const item = templateHtml(el, "font-weight-bold");
table.appendChild(item);
});
//ALL CARS
firstRow(allRecords);
arrayOfArrays.forEach((element, index) => {
const item = templateHtml(element);
allRecords.appendChild(item);
const item2 = templateHtml(element);
element[4] === true || index === 0 ? isofixTrue.appendChild(item2) : "";
});
//isofix == TRUE
firstRow(isofixTrue);
//sort Brand
firstRow(brandSort);
arrayOfArrays.sort(sortedBrand);
arrayOfArrays.forEach((element) => {
const item = templateHtml(element, "font-weight-normal");
brandSort.appendChild(item);
});
// sortMileageAndIsofixFalse
firstRow(sortMileageAndIsofixFalse);
arrayOfArrays.sort((prev, next) => prev[3]- next[3]);
arrayOfArrays.forEach((element) => {
const item = templateHtml(element, "font-weight-normal");
element[4] === false ? sortMileageAndIsofixFalse.appendChild(item) : "";
});
};
xhttp.open("GET", "Cars.csv");
xhttp.send();
}
<!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">
<title>Document</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#4.6.0/dist/css/bootstrap.min.css"
integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://unicons.iconscout.com/release/v4.0.0/css/solid.css">
<link rel="stylesheet" href="./css/style.css">
</head>
<body id="body">
<section class="container loadClick mb-5">
<button type="button" onclick="loadDocumentCsv()" class="btn loadDocument font-weight-bold">Wyświetl wszystkie tabele</button>
</section>
<section class="container">
<h2>1. Wszystkie samochody</h2>
<div id="allRecords"></div>
</section>
<section class="container mt-5">
<h2>2. Samochody gdzie Isofix === TRUE</h2>
<div id="isofixTrue"></div>
</section>
<section class="container mt-5">
<h2>3. Posortowane samochody wg Marki</h2>
<div id="brandSort"></div>
</section>
<section class="container mt-5">
<h2>4. Samochody gdzie Isofix === FALSE, posortowane wg przebiegu od najmniejszego do największego</h2>
<div id="sortMileageAndIsofixFalse"></div>
</section>
<div id="fixed">
<i class="uis uis-arrow-circle-up"></i>
</div>
<script src="./index.js"></script>
</body>
</html>
The CSV file looks like this:
Brand,Model,Year of production,Mileage,Isofix
Alfa Romeo,156,1998,600 000,TRUE
Chrysler,Voyager,2007,342 121,FALSE
Smart,Cabrio,2005,422122,TRUE
Fiat,500,2001 unkown,121333,FALSE
Chrysler,Voyager,2005,421 325,FALSE
Smart,Liftback,2015,534531,TRUE
Related
I'm attempting to create a simple to-do list and I've encountered two problems:
After refreshing the page, all the created elements are no longer visible on the page despite being in local storage.
After refreshing the page and submitting new values to the input, localStorage overwrites itself.
Despite that, the items displayed from the input fields are from the previous localStorage, which no longer exists (I really hope this makes sense).
const inputEl = document.getElementById("inputEl")
const submitBtn = document.getElementById("submit")
const clearBtn = document.getElementById("clearBtn")
const todoListContainer = document.getElementById("todoList")
const taskContainer = document.querySelector(".task")
const cancelBtn = document.querySelector(".cancelBtn")
const doneBtn = document.querySelector(".doneBtn")
const errorMsg = document.querySelector(".error")
let localStorageContent = localStorage.getItem("tasks")
let tasksItem = JSON.parse(localStorageContent)
let tasks = []
function createTask() {
if (inputEl.value.length != 0) {
const newDiv = document.createElement("div")
newDiv.classList.add("task")
const newParagraph = document.createElement("p")
const newCancelBtn = document.createElement("button")
newCancelBtn.classList.add("cancelBtn")
newCancelBtn.textContent = "X"
const newDoneBtn = document.createElement("button")
newDoneBtn.classList.add("doneBtn")
newDoneBtn.textContent = "Done"
todoListContainer.appendChild(newDiv)
newDiv.appendChild(newParagraph)
newDiv.appendChild(newCancelBtn)
newDiv.appendChild(newDoneBtn)
//^^ Creating a container for a new task, with all its elements and assigning the classes^^
tasks.push(inputEl.value)
inputEl.value = ""
for (let i = 0; i < tasks.length; i++) {
localStorage.setItem("tasks", JSON.stringify(tasks))
newParagraph.textContent = JSON.parse(localStorageContent)[i]
}
errorMsg.textContent = ""
} else {
errorMsg.textContent = "You have to type something in!"
errorMsg.classList.toggle("visibility")
}
}
submitBtn.addEventListener("click", () => {
createTask()
})
clearBtn.addEventListener("click", () => {
localStorage.clear()
})
HTML code below:
<!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">
<link rel="stylesheet" href="/style.css">
<script src="/script.js" defer></script>
<title>To-do list</title>
</head>
<body>
<h2 class="error visibility"></h2>
<div id="todoList">
<h1>To-Do List</h1>
<input type="text" name="" id="inputEl" placeholder="Add an item!">
<button type="submitBtn" id="submit">Submit</button>
<button id="clearBtn">Clear list</button>
<div class="task">
</div>
</div>
</body>
</html>
After refreshing the page, all the created elements are no longer visible on the page despite being in local storage
That is because you are rendering the HTML only after the click event and not on page load. To render the HTML for existing tasks stored in the localStorage you have to write a code that loops over your existing tasks in the tasksItem and applies the rendering logic to it.
I would suggest splitting the rendering code from your createTask() function and create a new function for it (for example renderTask()), then you can use it inside a loop on page load and also call the function once a new task is created in the createTask() function.
window.addEventListener('load', (event) => {
// Your read, loop and render logic goes here
})
After refreshing the page and submitting new values to the input, localStorage overwrites itself.
That's because you are actually overriding the tasks in the localStorage. To keep existing tasks, you have to use your tasksItem variable instead of the blank tasks array to create your tasks in and save them to the localStorage.
So, instead of:
tasks.push(inputEl.value)
You would use:
tasksItem.push(inputEl.value)
The same goes for:
for (let i = 0; i < tasksItem.length; i++) {
localStorage.setItem("tasks", JSON.stringify(tasksItem))
// …
}
I've been working on the Search CRUD using Google WebApp Script via watching a YouTube tutorial, I'm almost done but I'm stuck in a place I couldn't figure out to sort the issue.
I want to load the search field and the data on first page load. but based on this code I need to click on the Search Tab and then get the search field to find the data. How do I get rid of the Search Tab and get straight into the search bar and data.
On Page load
Second Occurrence (After the Click)
My code
<!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});
}
document.getElementById("search-link").addEventListener("click",loadSearchView);
function inputEventHandler(e){
if (e.target.matches("#searchinput")){
search();
}
}
document.getElementById("app").addEventListener("input",inputEventHandler);
</script>
</body>
</html>
Server Side Code
function getDataForSearch(){
const ss = SpreadsheetApp.getActiveSpreadsheet();
const ws = ss.getSheetByName("Array");
return ws.getRange(2, 1, ws.getLastRow(),8).getValues();
}
I need to type letters in order to data display.
Screen Shot 3
Issue:
There are some actions that are currently happening when the Search tab is clicked.
You want these actions to happen when the page loads.
Solution:
In the HTML you provided, there's a click event listener attached to the Search tab you mention (id="search-link"):
document.getElementById("search-link").addEventListener("click",loadSearchView);
This means the function loadSearchView is gonna execute when the Search tab is clicked.
If I understand you correctly, you want loadSearchView to execute when the page loads. In that case, you could just add the following event listener:
window.addEventListener("load", loadSearchView);
Notes:
Since you didn't provide server-side code, I cannot know whether loadSearchView will do what you intend it to do. This solution just makes sure loadSearchView is executed when the page loads.
If you want to get rid of the Search tab, just remove it from your HTML (<div class="nav-link"id="search-link">Search</div> and its container elements).
Reference:
Window: load event
it was a long time ago that I didn’t program in javascript so I decided to make a project of a "bookcase" to manage read books and that I want to read more I have difficulty with how to separate the elements to personalize the style because it selects all the results of the api in one just div.
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="script.js"></script>
<link rel="stylesheet" href="./css/bookcase.css">
<title>project</title>
</head>
<body>
<div id="content">
</div>
<script src="https://www.googleapis.com/books/v1/volumes?q=clean+code&callback=handleResponse></script>
</body>
</html>
js
function handleResponse(response) {
for (var i = 0; i < response.items.length; i++) {
var item = response.items[i];
var book = document.getElementById('content')
book.innerHTML += "<br>" + '<img src=' + response.items[i].volumeInfo.imageLinks.thumbnail + '>';
book..innerHTML += "<br>" + item.volumeInfo.title;
book..innerHTML += "<br>" + item.volumeInfo.authors;
Clean answer - you should use document.appendChild(child) instead of innerHTML method.
Also, there are few recently added js methods that can help you operate large JSON objects - map, reduce, filter.
I added example, how you can clean original object to smaller array, and insert items from that array into html-page.
function demo (obj) {
// getting all items from object
const book = Object.keys(obj).map(item => obj['items']).reduce(
(acc,rec, id, array) => {
// getting Cover, Title, Author from each item
let singleBookCover = rec[id].volumeInfo.imageLinks.thumbnail;
let singleBookTitle = rec[id].volumeInfo.title;
let singleBookAuthor = rec[id].volumeInfo.authors[0];
// Creating new array only with Cover, Title, Author
return [...acc, {singleBookCover, singleBookTitle, singleBookAuthor}]
},
[]
).forEach( item => {
// For each item on our array, we creating h1
let title = document.createElement('h1');
title.textContent = `${item.singleBookTitle} by ${item.singleBookAuthor}`;
// img
let img = document.createElement('img');
img.src = item.singleBookCover;
img.alt = `${item.singleBookTitle} by ${item.singleBookAuthor}`;
// and div wrapper
let container = document.createElement('div');
// adding our child elements to wrapper
container.appendChild(title).appendChild(img);
// adding our wrapper to body
document.body.appendChild(container);
})
return book
}
Hope my answer will help you)
function handleResponse(obj) {
const container = document.getElementById("container")
obj.items.forEach((rec, index) => {
let singleBookCover =
rec.volumeInfo.imageLinks && rec.volumeInfo.imageLinks.smallThumbnail;
let singleBookTitle = rec.volumeInfo.title;
let singleBookAuthor = rec.volumeInfo.authors[0];
let book = document.createElement("div");
book.className = "book"
book.innerHTML = `
<div><h1>${singleBookTitle}<h1>
<p>${singleBookAuthor}</p>
<img src="${singleBookCover}"></img>
</div>
`
content.appendChild(book)
});
}
<div id="content" class="books">
</div>
<script src="https://www.googleapis.com/books/v1/volumes?q=clean+code&callback=handleResponse"></script>
I'm following a tutorial and I made a button to show some content. However this button doesn't work and I'm at my wits end unable to figure out what could be causing this.
Can someone show why this doesn't work?
const users = document.querySelector('#user');
const getUsers = document.getElementById('getUsers');
getUsers.addEventListener('click', loadUsers);
var loadUsers = () => {
console.log('hello button clicked')
let xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.github.com/users', true);
xhr.onload = () => {
if (this.status == 200) {
let gusers = this.responseText
console.log(gusers);
}
}
xhr.send()
}
console.log(getUsers)
<h1>USER</h1>
<button id="getUsers">Get Users</button>
<div id="users"></div>
Order of your variable declarations matters in this scenario due to hoisting - move the loadUsers definition above the call.
JavaScript only hoists declarations, not initializations. If a
variable is declared and initialized after using it, the value will be
undefined.
The block-quote above from MDN explains why function declarations can be defined after they are called (reading code from top-to-bottom), but variables that are initialized after they are used would have a value of undefined.
const users = document.querySelector('#user');
const getUsers = document.getElementById('getUsers');
const loadUsers = () => {
console.log('Load users..');
}
getUsers.addEventListener('click', loadUsers);
<head>
<meta charset="UTF-8">
<title>Testing AJAX</title>
</head>
<body>
<h1>USER</h1>
<button id="getUsers">Get Users</button>
<div id="users"></div>
</body>
Or you could keep the function at the bottom but use a function declaration which will be hoisted:
const users = document.querySelector('#user');
const getUsers = document.getElementById('getUsers');
getUsers.addEventListener('click', loadUsers);
function loadUsers() {
console.log('Load users..');
}
<head>
<meta charset="UTF-8">
<title>Testing AJAX</title>
</head>
<body>
<h1>USER</h1>
<button id="getUsers">Get Users</button>
<div id="users"></div>
</body>
In addition to the correct answer have a look at your code that I have refactored below. Hope this helps.
// Get Elements
const usersList = document.querySelector('#usersList');
const usersBtn = document.querySelector('#usersBtn');
// Bind listener to usersButton
usersBtn.addEventListener('click', () => {
// XHR Request function
const xhr = new XMLHttpRequest();
xhr.open('GET','https://api.github.com/users')
xhr.send()
xhr.onload = function() {
if (xhr.status == 200) {
// Convert the response to JSON and assign it to data
const data = JSON.parse(xhr.responseText)
// Loop throug through data
for(let i = 0; i <data.length; i++) {
// Create LI element and append the user name
const listItem = document.createElement('li');
usersList.appendChild(listItem).innerHTML = data[i].login
}
}
}
})
<h1>USERS</h1>
<button id="usersBtn">Get Users</button>
<ul id="usersList"></ul>
I am trying to fetch information from TheMovieDB.org using API, I made a simple code to do that, but it works when I add click event to a button/hyperlink, then it displays all the NowPlayingMovies. I want the webpage should display now playing movies itself without any need to click on a button.
I tried to use the window.onload function and put the whole code in one function and remove the need to click on the hyperlink but I am unable to do it and code does not work and shows various errors. Can someone please help me fix it?
window.onload = function updateLatestMovies() {
const xhr = new XMLHttpRequest();
const nowPlayingButton = document.querySelector("#nowPlayingButton");
const endPoint = `https://api.themoviedb.org/3/movie/now_playing?api_key=6a879a78d6083b8f3ba308233e0de85b&language=en-US&page=1`;
xhr.open("GET", endPoint);
xhr.send();
xhr.addEventListener("readystatechange", updateLatestMovies);
const nowPlaying = document.querySelector("#nowPlaying");
if (xhr.readyState == 4) {
const response = JSON.parse(xhr.responseText);
const nowPlayingOutput = document.querySelector("#nowPlaying");
let nowPlayingA = response.results;
let output = "";
for (let i = 0; i < 15; i++) {
output += `
<div id="card">
<a onclick="movieSelected('${nowPlayingA[i].id}')" href="#"><img src="http://image.tmdb.org/t/p/w400/${nowPlayingA[i].poster_path}"></a>
<div class="cardContent">
<a onclick="movieSelected('${nowPlayingA[i].id}')" href="#"><h2>${nowPlayingA[i].title}</h2></a>
<p id="p_rating"><strong>Rating:</strong> <span>${nowPlayingA[i].vote_average} / 10 </span> </p>
<p><strong>Release date:</strong> <span>${nowPlayingA[i].release_date} </span></p>
</div>
</div>`;
}
nowPlayingOutput.innerHTML = output;
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Movies Database</title>
<link href="css/style.css" rel="stylesheet" type="text/css" />
</head>
<body>
See what's on Cinema!
<div id="nowPlaying">
</div>
</body>
</html>
And I got the following error:
Uncaught TypeError: Cannot read property 'addEventListener' of null at movie.js:4