Categories
JavaScript Tips

JavaScript Tips — Listeners, Sorting, and Nested Objects

Like any kind of apps, there are difficult issues to solve when we write JavaScript apps.

In this article, we’ll look at some solutions to common JavaScript problems.

addEventListener vs onclick

addEventListener and onclick are equivalent.

However, we can use addEventListener to listen to events from more than one DOM element.

For instance, if we have:

element.addEventListener('click', () => {
  //...
}, false);

Then we can listen to the click event of element .

We can also write:

element.onclick = () =>
  //...
}

which does the same thing.

We can use the event object to listen to multiple events.

For example, we can write:

element.addEventListener('click', (event) => {
  //...
}, false);

Then we can use the event object to get the event data from elements that’s a child of element and check for actions.

Strip all Non-Numeric Characters from String

We can strip all non-numeric characters from a string with the replace method.

For example, we can write:

const s = "123 abc".replace(/[^\d.-]/g, '');

We use the ^\d to look for all non-numeric characters.

Then we add the g tag to search for all instances of the pattern in the string.

How to Sort an Array by a Date Property

To sort an array by a Date property, we can use the sort method.

For instance, we can write:

array.sort((a, b) => {
  return new Date(b.date) - new Date(a.date);
});

We turn the date strings into Date instances, then we can subtract them to get the sort order.

We can do that since the subtraction operator will convert the Date instances into timestamps, which are integers.

Sorting Object Property by Values

To sort object properties by values, we can sort the keys by their values with the sort method.

For instance, we can write:

const list = {"baz": 200, "me": 75, "foo": 116, "bar": 15};
keysSorted = Object.keys(list).sort((a, b) => {
  return list[a] - list[b];
})
console.log(keysSorted);

We have the list object.

And we get the keys as an array with Object.keys .

Then we can call sort on the returned array.

Moment.js Transform to Date Object

We can use the toDate method to transform a moment object into a Date object.

For instance, we can write:

moment().toDate();

Test for Existence of Nested JavaScript Object Key

We can check for a key with the recursive function.

For instance, we can write:

const checkNested = (obj, level,  ...rest) => {
  if (obj === undefined) {
     return false;
  }

  if (rest.length === 0 && obj.hasOwnProperty(level)) {
    return true;
  }
  return checkNested(obj[level], ...rest)
}

We check if obj is undefined and return false if it is since it’s undefined before we got to the end of the path.

Otherwise, we check that there are no arguments left and check if the property with the key level exists.

If that exists, then we return true .

Otherwise, we call the checkNested function again by moving on to the lower level.

So we can call it by writing:

checkNested(foo, 'level1', 'level2', 'bar');

to check if foo.level1.level2.bar exists.

To make our lives easier, we can also use the ?. optional chaining operator:

const value = obj?.level1?.level2?.level3

It’ll just return undefined if any intermediate level doesn’t exist.

Playing Audio with Javascript

We can use the play method of an audio element to play audio with JavaScript.

For instance, we can write:

const audio = new Audio('audio.mp3');
audio.play();

or:

document.getElementById('audioPlayer').play();

Defining a Class in JavaScript

We can define a class in 2 ways.

We can create a constructor function or use a class syntax.

For instance, we can write:

function Person(name) {
  this.name = name;
}

to create a Person constructor.

Then to add methods, we write:

Person.prototype.greet = function() {
  console.log(`hello ${this.name}`);
}

We can use the class syntax to do the same thing:

class Person {
  constructor(name) {
    this.name = name;
  }

  greet``() {
    console.log(`hello ${ this.name }`);
  }
}``

We define instance methods in the class instead of adding a property to prototype .

It’s cleaner and static analysis can check its syntax.

It’s also easier to understand for people coming from class-based languages.

Both ways are the same.

Conclusion

We can define classes in multiple ways.

Also, we can test for the existence of nested object keys by using the optional chaining operator or our own function.

There are various ways to sort things.

Categories
JavaScript Tips

JavaScript Tips — Errors, Auto-Resizing Text Area, and More

Like any kind of apps, there are difficult issues to solve when we write JavaScript apps.

In this article, we’ll look at some solutions to common JavaScript problems.

Replace All Commas in a String

We can replace all commas in a string with the replace method.

For instance, we can write:

const str = 'foo,bar,baz';
const newStr = str.replace(/,/g, '-');

Then newStr is “foo-bar-baz” .

Good Way to Extend Error in JavaScript?

We can extend the Error class with the extends keyword.

For instance, we can write:

class SpecialError extends Error {
  constructor(message) {
    super(message);
    this.name = 'special error';
  }
}

We created a SpecialError class which inherits from the Error class.

We can set our own name to distinguish it from the Error instance.

Convert String with Commas to Array

We can convert strings with commas to an array with the split method.

For instance, we can write;

const string = "1,2,3";
const array = string.split(",");
console.log(array);

We have a string that we call split on with a comma to split the string into an array.

Add or Update a Query String Parameter

To add or update a query string parameter, we can create a URLSearchParams instance with the query string.

Then we can call set on it with the key and value to set the parameter.

For instance, we can write:

const searchParams = new URLSearchParams(window.location.search)
searchParams.set("foo", "baz");
const newURL = `${window.location.pathname}?${searchParams.toString()}`;
history.pushState(null, '', newURL);

We get the query string in the browser search bar with window.location.search .

Then we call set with the key and value of it.

Next, we get the query string by calling toString on the URLSearchParams instance.

And we combine the pathname and query string together.

Then we call pushState to with the new URL to reload the page with the new query string.

Open a URL in a New Window Rather than a Tab

To always open a URL in a new window rather than a tab, we can pass in a 3rd argument to window.open with the width and height of the window.

For instance, we can write:

window.open(url, '_blank', "height=200,width=200");

The 3rd argument has the specifications of the window.

Check if a Variable is a Number

We can check if a variable is a number by using the isNaN and isFinite functions.

For instance, we can write:

!isNaN(parseFloat(num)) && isFinite(num);

We use parseFloat to try to parse num to a float.

Then we can check the returned value with isNaN .

We also pass num to isFinite to check that.

If both expressions are true then we know we got a finite number.

Creating a Text Area with Auto-Resize

To create a text area with auto-resize, we can listen to the input event.

Then we can set the height of the text area in the input event listener to the scrollHeight plus 12 pixels.

scrollHeight gets the full height of the text.

To do that we can write:

<textarea></textarea>

to create the text area.

Then we can write:

function resizeTextarea(ev) {
  this.style.height = 'auto';
  this.style.height = `${this.scrollHeight}px`;
}
const textArea = document.querySelector('textarea');
textArea.addEventListener('keyup', resizeTextarea);

'auto' resets the height to the original.

Then we set the height to the scrollheight to make it the height of the text.

Why Shouldn’t we use document.write?

We shouldn’t use document.write to render HTML on the screen.

It doesn’t work with XHTML.

It’s run after the page finishes loading and overwrites the page.

Also, it runs where it’s encountered.

It’s doesn’t write content like we do with DOM manipulating and can easily create bugs since we’re writing string’s content onto a page.

Therefore, we shouldn’t use document.write to write content onto the screen.

Check if the URL has a Given String

We can use the indexOf method on window.location.href to check if a URL contains a given string.

For instance, we can write:

window.location.href.indexOf("foo") > -1

to check if 'foo' is in the current page’s URL.

If the returned value is -1, that means it’s not in the URL.

Otherwise, it’s in the URL.

Conclusion

We can use the URLSearchParams constructor to parse and manipulate query strings.

window.open can open a new window.

The Error constructor can be extended with a child class.

Categories
JavaScript Tips

JavaScript Tips — bind and apply, Loops, and Nested Properties

Like any kind of apps, there are difficult issues to solve when we write JavaScript apps.

In this article, we’ll look at some solutions to common JavaScript problems.

JavaScript for…in vs for

for-in and for loops are different.

for-in is exclusively used for looping through the properties of an object.

For instance, we can write:

for (const key in obj){
  //...
}

key is the property name of an object.

A for loop can be used for anything.

For instance, we can write:

for (let i = 0; i < a.length; i++){
  //...
}

We loop through an array a with the loop.

But we can do anything else with it.

Use of .apply() with the ‘new’ Operator

We can use apply with any function.

To use them together, we create a new constructor with the bind and apply method together.

For instance, we can write:

function newCall(Cls, ...args) {
  return new (Function.prototype.bind.apply(Cls, args));
}

We created the newCall constructor get the class, we want to call apply with.

Then we get the args .

bind returns a new constructor function that calls apply with the Cls constructor function with the arguments args that we want.

Then we can use the constructor by writing:

const s = newCall(Foo, a, b, c);

We pass the Foo constructor into newCall with arguments a , b , and c .

Then we get a Foo instance created with those arguments.

Use of <script type = “text/template”> … </script>

A script tag with type text/template is used for some libraries as templates.

For instance, jQuery can get the template from this script tag.

If we have:

<script id="hello" type="text/template">
  hello world
</script>
<script>
  console.log($('#hello').html());
</script>

Then jQuery gets the script tag with ID hello and return the HTML content from it by calling html .

So we get 'hello world' logged in the console log.

Get All Properties Values of a JavaScript Object without Knowing the Keys

We can get all property values of a JavaScript object without knowing the keys in a few ways.

One way is to use the for-in loop:

for(var key in obj) {
  const value = obj[key];
  //...
}

We can also use the Object.key method to get an array of all the property keys.

So we can write:

const keys = Object.keys(obj);

for (const key of keys) {
  const val = obj[key];
}

We use the for-of loop to loop through the array of keys returned from Object.keys .

Object.values returns all the values from an array.

So we can loop through the values without getting the keys:

const values = Object.values(obj);

for (const val of values) {
  //...
}

Accessing Nested JavaScript Objects and Arrays by String Path

There are a few ways to get the value of a nested property in an object.

One way is to write a function from scratch:

const resolve(path, obj = {}, separator = '.') {
  const properties = Array.isArray(path) ? path : path.split(separator);
  return properties.reduce((prev, curr) => prev && prev[curr], obj)
}

We created the resolve method to get the property of each level.

The property path is split by the separator.

Then we go through all the properties to get to the nested property’s value with reduce .

Then we can call it by writing:

resolve("style.width", document.body)

to get an object’s properties.

If there’s an array, we write:

resolve("part.0.size", obj)

where 0 is an index of an array.

To make our lives easier, we can use the Lodash get method.

Then we can write:

_.get(object, 'a[0].b.c');

to get the property by the path.

Response to Preflight Request doesn’t Pass Access Control Check Error

This error means that the options request that’s made before the actual request failed.

To fix this issue, we can turn off CORS.

Also, we can use a proxy like Nginx to handle the options request.

We can also enable CORS properly by making sure the options request responds with a successful response.

Conclusion

The for-in loop is different from a for loop.

To make sure that cross-domain requests succeed, we should make sure that we should configure our server properly.

There are some ways to access the nested path of an object.

We can use bind and apply together.

Categories
JavaScript Tips

JavaScript Tips — Arrow Keys, Array Checks, and More

As with many kinds of apps, there are difficult issues to solve when we write apps for JavaScript. In this article, we’ll look at some solutions to common JavaScript problems.

Check if Arrow Keys are Pressed

We can check if an arrow key is pressed with the which property of the event object.

To do that, we can write:

document.onkeydown = (e) => {  
  switch(e.which) {  
    case 37:   
      break;  
    case 38:  
      break;  
    case 39:  
      break;  
    case 40:  
      break;  
    default:   
      return;   
  }  
  e.preventDefault();  
};

We watch the key down event by setting an event handler to the onkeydown method of document .

Then inside the function, we get the which property to check the key code.

37 is the left key.

38 is the up key.

39 is the right key.

40 is the down key.

We also have to call preventDefault() to prevent the default action, which is scrolling and moving the cursor.

Check if an Element Exists in the Visible DOM

We can check if an element exists by selecting it in the DOM.

If it’s visible then the element will be returned.

To do that, we can use document.getElementById to get an element by ID.

document.querySelector gets an element by any selector.

document.querySelectorAll gets a group of elements by any selector.

documebt.getElementsByClassName gets a group of elements by class name.

document.getElementsByName gets a group of elements by their name attribute value.

The ones that return groups have a length property, so we can use that to check if there is anything.

For instance, we can write:

const foo = document.querySelector('#foo');

to get an element with the ID foo if it’s visible.

Converting a JavaScript Object to an Array

We can convert a JavaScript object to an array with the Object.keys and map methods.

For instance, we can write:

const obj = { 1: 'foo', 2: 'bar' };  
const arr = Object.keys(obj).map((key) => obj[key]);

We call the Object.keys to get the keys. Then we return the value in the map callback.

Also, we can use the Object.values method to get the values as an array:

const arr = Object.values(obj);

Underscore and Lodash also have the values method:

const arr = _.values(obj);

Contains Case Insensitive

We can check if a substring is in a string in a case-insensitive way by using the toLowerCase and indexOf methods.

For example, we can write:

if (str.toLowerCase().indexOf("foo") === -1) {  
  //...  
}

We can also use regex to do the check:

if (!/Foo/i.test(str)) {  
  //...  
}

i means case insensitive.

We can replace the indexOf method with the includes method:

if (str.toLowerCase().includes("foo")) {  
  //...  
}

or:

if (str.toLowerCase().includes("foo".toLowerCase())) {  
  //...  
}

How to Append Data to div

To append data to a div, we can append it using the innerHTML property.

For instance, we can write:

const div = document.getElementById('div');  
div.innerHTML += 'more data';

We get the div and append more data toinnerHTML .

We can also create a text node and call appendChild to append it to the div:

const div = document.getElementById("div");  
const content = document.createTextNode("more stuff");  
div.appendChild(content);

Get the Rendered Height of an Element

We can get the height of an element with the clientHeight property.

It’s the total of the height of the element, padding, and height of the horizontal scrollbar if it exists.

Then we can write:

document.getElementById('div').clientHeight;

There’s also the offsetHeight property.

It includes the CSS height, borders, padding, and horizontal scrollbar if it exists.

For example, we write:

document.getElementById('div').offsetHeight;

Check if an Array Contains any Element of Another Array

To check if an array has an element of another array, we can use the some and includes methods.

For example, we can write:

const hasElement = arr1.some(r => arr2.includes(r))

We use the some method to check if any element in arr1 meets the condition returned in the callback.

arr2.includes(r) checks if an item in arr2 is included in arr1 .

Conclusion

We can check if an array has an entry of another array with the some and includes methods. We can check if arrow keys are pressed by checking a few key codes. Also, we can use a few methods to convert an object to an array.

Categories
JavaScript Tips

Useful JavaScript Tips — Semicolons, Dates, and Logging Objects

Like any kind of apps, JavaScript apps also have to be written well.

Otherwise, we run into all kinds of issues later on.

In this article, we’ll look at some tips we should follow to write JavaScript code faster and better.

Semicolon

Semicolons can be automatically inserted in JavaScript.

It inserts semicolons on the next line after code that breaks the current one.

Also, when the next line starts with a } , a semicolon is inserted.

When the end of the source code file is reached, then the semicolon is added.

Semicolons are also inserted after the break keyword.

It’s also added after the throw and continue keywords.

If we don’t add it ourselves, then the interpreter will insert it for us.

Manipulating Dates Easily with Moment.js

To make date manipulating easier, we can use moment.js

We can install it by adding a script tag or installing the package.

We can write:

<script src="https://unpkg.com/moment" />

or:

npm install moment

If we use the package, we can write:

import moment from 'moment'

To get the current date and time, we can write:

const date = moment();

To parse a date, we can write:

const date = moment(string);

It takes various formatting codes. They are:

  • YYYY — 4 digits year
  • YY — 2 digits year
  • M — 2 digits month number without the 0
  • MM — 2 digits month number
  • MMM — 3 letters month name
  • MMMM — full month name
  • dddd — full day name
  • gggg — 4 digits week year
  • gg — 2 digits week year
  • w — week of the year without leading zero
  • ww — week of the year with leading zero
  • e — day of week that starts with 0
  • D — 2 digits day number without the leading 0
  • DD — 2 digits day number
  • Do — day number with ordinal
  • T — start of the time part
  • HH — 2 digit hours from 0 to 23
  • H — 2 digit hours from 0 to 23 without the leading 0
  • kk — 2 digit hours from 1 to 24
  • k — 2 digit hours from 1 to 24 without leading 0
  • a/A — am or pm
  • hh — 2 digit hours (12 hours time)
  • mm — 2 digit minutes
  • ss — 2 digits seconds
  • s — 2 digits seconds without leading 0
  • S — 1 digit milliseconds
  • SS — 2 digit milliseconds
  • SSS — 3 digits milliseconds
  • Z — timezone
  • x — UNIX timestamp in milliseconds

For instance, we can format date by writing:

moment().format("YYYY-MM-DD")

Moment.js comes with a few constants.

They are the following:

  • moment.HTML5_FMT.DATETIME_LOCAL — ‘YYYY-MM-DDTHH:mm’
  • moment.HTML5_FMT.DATETIME_LOCAL_SECONDS — ‘YYYY-MM-DDTHH:mm:ss’
  • moment.HTML5_FMT.DATETIME_LOCAL_MS — ‘YYYY-MM-DDTHH:mm:ss.SSS’
  • moment.HTML5_FMT.DATE — ‘YYYY-MM-DD’
  • moment.HTML5_FMT.TIME — ‘HH:mm’
  • moment.HTML5_FMT.TIME_SECONDS — ‘HH:mm:ss’
  • moment.HTML5_FMT.TIME_MS — ‘HH:mm:ss.SSS’
  • moment.HTML5_FMT.WEEK — ‘YYYY-[W]WW’
  • moment.HTML5_FMT.MONTH — ‘YYYY-MM’

We can validate a date with the isValid method.

For instance, we can write:

moment('2020-13-32').isValid()

which returns false , or:

moment('2020-01-23').isValid()

which returns true .

Get the Relative Time String

We can use the fromNow method to get the relative from the current date and time.

For instance, we can write:

moment("2020-11-23").fromNow()

and get ‘in 6 months’ .

We can pass true to fromNow , then it shows the difference without reference to the future or past.

So if we write:

moment("2020-11-23").fromNow(true)

Then we get ‘6 months’ .

Manipulating Dates

We can use the Moment.js add and subtract methods to add or subtract amounts from a date.

For instance, we can write:

moment('2020-11-23').add(1, 'days');  
moment('2020-11-23').subtract(1, 'days');

The 2nd argument can have the following values:

  • years
  • quarters
  • months
  • weeks
  • days
  • hours
  • minutes
  • seconds
  • milliseconds

Inspect a JavaScript Object

There are various ways to inspect objects in JavaScript.

We can use the console.log method to log an expression and get its return value.

For instance, we can write:

console.log(dog)

There’s also the console.dir method to let us inspect any object.

For instance, we can write:

console.dir(dog)

JSON.stringify is another way to let us inspect an object.

It’ll return a string.

For instance, given that we have:

const dog = {  
  color: 'white',  
  breed: 'poodle'  
}

we can write:

console.log(JSON.stringify(dog))

which creates an unprettified string.

Then we get:

{"color":"white","breed":"poodle"}

logged.

To pretty-print the string, we can pass in 2 more arguments.

We write:

console.log(JSON.stringify(dog, null, 2))

and we get:

{  
  "color": "white",  
  "breed": "poodle"  
}

Conclusion

Moment.js makes date manipulating easier than with the Date constructor.

We can inspect expression values with console and JSON.stringify.