JavaScript
Basics
Load after html loading via defer
<script src="main.js" defer></script>
HTML Form Elements
Function of button click
<button id="submit" onclick="myFunction()">Anmelden</button>
Function on enter
<input type="number" id="threshold" name="threshold" min="50" max="500" step="1" value="300"> var input_threshold = document.getElementById("threshold"); input_threshold.addEventListener("keydown", function (e) { // Enter is pressed if (e.keyCode === 13) { event.preventDefault(); myFunction(); } }, false);
Variables
Declaration
const var = 123; // constant: no change possible let var = 123; // block-bound, perferred to var var var = 123; // old style, better use let instead
Clone/Copy Object
// from https://www.samanthaming.com/tidbits/70-3-ways-to-clone-objects/ const myObject2 = Object.assign({}, myObject);
Arrays
Loop over all elements
var rows = table.getRows(); for (var i = 0; i < rows.length; i++) { var row = rows[i]; ... }
Loop over array of objects
for (let i = 0; i < Object.keys(array).length; i++) { const key = Object.keys(array)[i]; const value = array[key]; } NOTE: do not use for (const key in array) { ... } as this results in this problem "The body of a for-in should be wrapped in an if statement to filter unwanted properties from the prototype"
Element in Array
if(myArray.indexOf(myItem) > -1) {...}
Last element of array
my_data.slice(-1)[0]
or
my_data.slice(-1)[0]["myKey"]
Array of Objects
delete some object properties
// delete not needed object properties const allowedKeys = new Set(["type", "name", "x_date", "x_url", ...Object.keys(measures)]); data.forEach((obj) => { Object.entries(obj).forEach(([key]) => { if (!allowedKeys.has(key)) { delete obj[key]; } }); // extract year from x_date and add as property obj.year = parseInt(obj.x_date.substr(0, 4)); });
Extract distinct list/set list for property 'type' values
const act_types = [...new Set(data.map((obj) => obj.type))].sort();
Sort by object property "measure" DESC
data = data.sort((a, b) => b[measure] - a[measure]);
Async fetching via JQuery
in HTML
<script src="lib/jquery-3.5.0.min.js"></script>
in JS
// array of promises for async fetching const promises = []; // ref dictionary to be fetched: Country Code -> Country Name var mapCountryNames = {}; // fetch countries-latest-all.json containing country reference data like code and continent function fetch_mapRefCountryData(mapCountryNames) { const url = "https://entorb.net/COVID-19-coronavirus/data/int/countries-latest-all.json"; return $.getJSON(url, function (data) { console.log("success: mapCountryNames"); }) .done(function (data) { console.log("done: mapCountryNames"); $.each(data, function (key, val) { mapCountryNames[data[key].Code] = data[key].Country; }); }) .fail(function () { console.log("fail: mapCountryNames"); }); } // Start the async fetching promises.push(fetch_mapRefCountryData(mapCountryNames, mapContinentCountries)); // Wait for all async promises to be done (all data is fetched), then print message Promise.all(promises).then(function () { console.log("All data fetched"); });
Date handling
// calculate date via offset const daysOffset = 7; const s_data_last_date = "2020-04-01" const ts_last_date = Date.parse(s_data_last_date) var minDate = new Date(ts_last_date); minDate.setDate(minDate.getDate() + daysOffset);
Helper Functions
from [https://love2dev.com/blog/javascript-remove-from-array/
function arrayRemove(arr, value) { return arr.filter(function (ele) { return ele != value; }); }
from [1]
function removeAllOptionsFromSelect(select) { var i, L = select.options.length - 1; for (i = L; i >= 0; i--) { select.remove(i); } } // Formats value "Something_Is_HERE" to "Something is here" like sentence // value: The value to format // separator: the separator string between words function formatValueToSentenceLike(value, separator) { const allLowerCaseValue = value.split(separator).join(" ").toLowerCase(); return allLowerCaseValue[0].toUpperCase() + allLowerCaseValue.substr(1); }
// modifies array of objects by removing if value == keys function arrayRemoveValueTextPairByValue(arr, key) { for (let i = arr.length - 1; i >= 0; i--) { if (arr[i].value == key) { arr.splice(i, 1); } } }
Local Storage
// read browser's local storage for last session data localStorageData = window.localStorage.getItem("my_data"); if (localStorageData) { var my_data = JSON.parse(localStorageData); } else { var my_data = []; }
Export and Import / Download and Upload data to Variable
HTML
<a id="downloadAnchor" style="display:none"></a> <button id="download_data" onclick="download_data()">Export</button> and Import: <input id="upload_data" type="file" onchange="upload_data(this)">
JS
// download data function download_data() { const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify([settings, data])); let html_dl_anchor = document.getElementById("downloadAnchor"); html_dl_anchor.setAttribute("href", dataStr); html_dl_anchor.setAttribute("download", "eta.json"); html_dl_anchor.click(); } // upload data function upload_data(input) { // from https://javascript.info/file let file = input.files[0]; let reader = new FileReader(); reader.readAsText(file); reader.onload = function () { const uploaded_data = JSON.parse(reader.result); settings = uploaded_data[0]; data = uploaded_data[1]; }; reader.onerror = function () { console.log(reader.error); }; }
Hide/remove HTML elements
HTML
< div id="text_intro" >...< /div >
JS
function hide_intro() { // from https://stackoverflow.com/questions/1070760/javascript-href-vs-onclick-for-callback-function-on-hyperlink const html_text_intro = document.getElementById('text_intro'); html_text_intro.remove(); }
Internet Explorer Backward Compatibility
Error: Object doesn't support property or method 'includes'
variant 1:
replace:
if(myarray.includes(key)) {
by:
if(myarray.indexOf(key) > -1) {
variant 2: polyfile
if (!String.prototype.includes) { String.prototype.includes = function(search, start) { 'use strict'; if (search instanceof RegExp) { throw TypeError('first argument must not be a RegExp'); } if (start === undefined) { start = 0; } return this.indexOf(search, start) !== -1; }; }
Tabulator
// wait for tableBuilt event table.on("tableBuilt", function () { myUpdateTableFnc(); });
eCharts
Jest Unittests
install jest and jsdom for testing browser features like window.localStorage
npm install --save-dev jest jest-environment-jsdom
in package.json set
"scripts": {"test": "jest --coverage","testc": "jest --coverage"}, "jest": { "testEnvironment": "jsdom" }
run jest
npm test npm run testc
In the file I want to test here `helper.js`
var module = module || {}; module.exports = { zeroPad, ... }
The testcasefile `helper.test.js`
describe("Testing zeroPad", () => { const { zeroPad } = require("./helper"); test("1->01", () => { expect(zeroPad(1, 2)).toEqual("01"); }); });
test.each
To test many cases use
describe("zeroPad()", () => { const { zeroPad } = require("./helper"); const cases = [ // arg1, arg2, expectedResult [1, 2, "01"], [6, 3, "006"], ]; test.each(cases)( "given '%p', '%p' it shall return %p", (arg1, arg2, expectedResult) => { expect(zeroPad(arg1, arg2)).toEqual(expectedResult); } ); });
ignore Test Coverage for missing else etc
place such a comment before the non-relevant line
/* istanbul ignore else */ /* istanbul ignore next */