Tari Ibaba

Tari Ibaba is a software developer with years of experience building websites and apps. He has written extensively on a wide range of programming topics and has created dozens of apps and open-source libraries.

How to Create a Video Element in JavaScript (Easy Way)

To create a video element using JavaScript:

  1. Use the document.createElement() method to create the video element
  2. Set various attributes of the video element, such as src, height, width, etc.
  3. Include the video element in the HTML using the appendChild() method.

Consider this sample HTML markup:

index.html

<!DOCTYPE html>
<html>
  <head>
    <title>Coding Beauty Tutorial</title>
  </head>
  <body>
    <div id="box"></div>

    <script src="index.js"></script>
  </body>
</html>

Here’s how we can create a video element from JavaScript:

index.js

// Create video element
const video = document.createElement('video');

// Use local file
// video.src = 'video.mp4';

// Use remote file
video.src =
  'https://archive.org/download/C.E.PriceCatWalksTowardCamera/cat_walks_toward_camera_512kb.mp4';


video.controls = true;
video.muted = false;
video.height = 240; // in px
video.width = 320; // in px

const box = document.getElementById('box');

// Include in HTML as child of #box
box.appendChild(video);

Now the video will be visible on the web page:

A video element created with JavaScript.

We can the controls to play the video if we want:

Playing the video.

The document.createElement() method creates an HTML element specified by a tag name and returns the element. By passing a video tag, we create a video element.

The video element comes with a number of attributes that we can use to customize its appearance and behavior. Here are some of the most commonly used ones:

  • src: The most important attribute, which is set to a URL or file path to determine the video to be played.
  • autoplay: This attribute specifies if the video should start playing automatically as soon as possible, without stopping to finish loading the data.
  • controls: The controls attribute determines if the browser should show controls that allow the user to control video playback, i.e., adjusting volume, moving to a new position in the video (seeking), pausing/resuming, etc.
  • poster: A URL for an image to be displayed while the image is still downloading.
  • muted: This is a boolean attribute used to specify if the video should be muted by default.
  • height: Sets the height of the video’s display area, in pixels.
  • width: Sets the width of the video’s display area, in pixels.

For a complete list of all attributes supported by the video element, visit the MDN docs on the video element.

The appendChild() method can add a DOM element to the end of the list of children of a specified parent node. After accessing the #box element from our HTML with getElementById(), we call the appendChild() method on it to include the video element in the HTML by adding it as a child of the #box.

Ensuring Cross-Browser Compatibility for the Video Element

As browsers don’t all support the same video formats, when embedding video we’ll need to specify different formats depending on the one the user’s browser supports.

To check if the browser supports a particular video type, we can use the canPlayType() method.

// Create video element
const video = document.createElement('video');

video.autoplay = false;
video.controls = true;
video.muted = false;
video.height = 240; // in px
video.width = 320; // in px

if (video.canPlayType('video/mp4')) {
  video.src = 'video.mp4';
} else if (video.canPlayType('video/ogg')) {
  video.src = 'video.ogg';
} else {
  // Provide video link to user
}

const box = document.getElementById('box');

// Include in HTML as child of box
box.appendChild(video);

If the browser doesn’t support any of the video formats, the best thing to do is to provide the user with the link to the video for them to download it and watch it offline. That way, every user will be able to watch your video, regardless of the level of video support their browser has.

How to Remove an Item from a State Array in React

In this article, we’re going to learn how to easily remove an item from a state array in React.

The Array filter() Method

To remove an item from a state array in React, call the filter() method on the array, specifying a test that every item in the array apart from the one to be removed will pass, then update the state with the result of filter() with setState.

import { useState } from 'react';

export default function App() {
  const initialState = [
    { id: 1, name: 'Banana', amount: 5 },
    { id: 2, name: 'Apple', amount: 6 },
  ];

  const removeSecond = () => {
    setFruits((current) =>
      current.filter((fruit) => fruit.id !== 2)
    );
  };

  const [fruits, setFruits] = useState(initialState);

  return (
    <div style={{ margin: '16px' }}>
      <button onClick={removeSecond}>Remove second</button>
      {fruits.map((fruit) => (
        <div key={fruit.id}>
          <h2>Name: {fruit.name}</h2>
          <h2>Amount: {fruit.amount}</h2>
          <hr />
        </div>
      ))}
    </div>
  );
}
Removing an item from a state array in React.

We remove the fruit object with the id 2 by returning a condition from the filter() callback that is true only for the items in the array that don’t have an id of 2. Doing this excludes the target item from the array returned from filter().

const initialState = [
  { id: 1, name: 'Banana', amount: 5 },
  { id: 2, name: 'Apple', amount: 6 },
];

const secondRemoved = initialState.filter((fruit) => fruit.id !== 2);

// [ { id: 1, name: 'Banana', amount: 5 } ]
console.log(secondRemoved);

Since App here is a functional component, we use the useState() React hook to create the initial state array. The first value useState() returns lets us access the state data. The second value is a function used to update the state (generically called setState). We pass a function to setState (named setFruits here) to ensure that we get the current/latest state.

const removeSecond = () => {
  // "current" contains the latest state array
  setFruits((current) =>
    current.filter((fruit) => fruit.id !== 2)
  );
};

Tip: Always pass a function to setState when the new state is computed from the current state data.

Don’t Modify State Directly in React

Note that trying to remove the item from the array by modifying it directly using a function like splice() will not work:

const removeSecond = () => {
  // Find the index of the object to be removed
  const secondIndex = fruits.findIndex((fruit) => fruit.id === 2);

  // Mutating the array like this will not update the view
  fruits.splice(secondIndex, 1);
};

State is meant to be immutable in React, so we can’t update the array by mutating it. It has to be replaced with a new array returned from filter() for the view to update.

Remove Items from a State Array Based on Multiple Conditions

If you need to remove an item from the state array based on multiple conditions, you can use the logical AND (&&) or logical OR (&&) operator.

Using the Logical OR (||) Operator

Here is an example of using the logical OR (||) operator to remove an item from a state array.

const initialState = [
  { id: 1, name: 'Banana', amount: 5 },
  { id: 2, name: 'Apple', amount: 6 },
  { id: 3, name: 'Orange', amount: 10 },
  { id: 4, name: 'Watermelon', amount: 1 },
];

const [fruits, setFruits] = useState(initialState);

const remove = () => {
  setFruits((current) =>
    current.filter(
      (fruit) =>
        fruit.name === 'Orange' || fruit.name === 'Apple'
    )
  );
};

Combining a set of operands with the || operator will result in true if at least one of the operands evaluates to true. By using this operator with the filter() method, we return a new array containing only the fruit objects with a name equal to 'Orange' or 'Apple'.

Using the Logical AND (&&) Operator

Here is an example of using the logical AND (&&) operator to remove an item from a state array:

const initialState = [
  { id: 1, name: 'Banana', amount: 5 },
  { id: 2, name: 'Apple', amount: 6 },
  { id: 3, name: 'Orange', amount: 10 },
  { id: 4, name: 'Watermelon', amount: 1 },
];

const [fruits, setFruits] = useState(initialState);

const remove = () => {
  setFruits((current) =>
    current.filter(
      (fruit) => fruit.id !== 2 && fruit.id !== 4
    )
  );
};

Combining operands with the && operator will result in true only if all the operands are true.

By combining the filter() method with the && operator, we are able to specify a compound boolean expression that removes the fruit objects with ids of 2 and 4.

Simplifying Compound Boolean Expressions with De Morgan’s Laws

We can use one of De Morgan’s laws to convert the AND condition from our previous example to an OR condition and reduce the number of negations.

const remove = () => {
  setFruits((current) =>
    current.filter(
      (fruit) => !(fruit.id === 2 || fruit.id === 4)
    )
  );
};

This transformation could make the expression easier to read and understand.

3 Easy Ways to Swap 2 Array Elements in JavaScript

In this article, we’ll learn multiple ways to easily swap the values of two array elements in JavaScript.

1. Temporary Variable

To swap two array elements in JavaScript:

  1. Create a temporary variable to store the value of the first element.
  2. Set the first element to the value of the second element.
  3. Set the second element to value in the temporary variable.

For example:

function swapElements(arr, i1, i2) {
  // Step 1
  let temp = arr[i1];

  // Step 2
  arr[i1] = arr[i2];

  // Step 3
  arr[i2] = temp;
}

const arr = [1, 2, 3, 4];

swapElements(arr, 0, 3);

console.log(arr); // [ 4, 2, 3, 1 ]

2. Array Destructuring Assignment

To swap two array elements with this method:

  1. Create a new array, containing both elements in a particular order.
  2. Use the JavaScript array destructing syntax to unpack the values from the array into a new array that contains both elements in a reversed order.

With this method, we can create a concise one-liner to do the job.

function swapElements(arr, i1, i2) {
  [arr[i1], arr[i2]] = [arr[i2], arr[i1]];
}

const arr = [1, 2, 3, 4];

swapElements(arr, 0, 3);

console.log(arr); // [ 4, 2, 3, 1 ]

3. Array splice() Method

An alternative approach to swapping two array elements is to use the splice() method, like this:

function swapElements(arr, i1, i2) {
  arr[i1] = arr.splice(i2, 1, arr[i1])[0];
}

const arr = [1, 2, 3, 4];

swapElements(arr, 0, 3);

console.log(arr); // [ 4, 2, 3, 1 ]

The Array splice() method changes the contents of an array by removing existing elements, while possibly adding new elements in their place.

const arr1 = ['a', 'b', 'c'];

// Removing elements
arr1.splice(1, 2);
console.log(arr1); // [ 'a' ]

// Removing and adding new elements
const arr2 = ['a', 'b', 'c'];
arr2.splice(1, 2, 'd', 'e');
console.log(arr2); // [ 'a', 'd', 'e' ]

In order to swap the array elements, we specify certain arguments for three of the parameters that splice() has:

  1. start: This specifies the index from which to start changing the array from. We use the index of the second element for this as the argument for the parameter.
  2. deleteCount: This is a number that indicates the number of elements to remove from start. Our passing 1 means that only the element at the start index (the second element to be swapped) will be removed.
  3. item1, …, itemN: These are a variable number of arguments to add to the array. We only pass one value for this – the first element to be swapped.

So the three arguments we pass to splice() replace the first element with the second.

To complete the swap, we take advantage of the fact that splice() returns an array containing removed elements.

const arr2 = ['a', 'b', 'c'];

const removed = arr2.splice(1, 2, 'd', 'e');

console.log(removed); // [ 'b', 'c' ]
console.log(arr2); // [ 'a', 'd', 'e' ]

So for our scenario, the second element to be swapped will be in this array, hence we access it from the array and assign its value to the first element.

How to Add a Space Between Characters in JavaScript

In this article, we’ll learn how to easily include spaces between the characters of a string in JavaScript.

1. The String split() and Split join() Methods

To add a space between characters of a string, call the split() method on the string to get a character array, then call the join() method on the array to join the characters with a space separator.

For example:

function addSpace(str) {
  return str.split('').join(' ');
}

const str1 = 'coffee';
const str2 = 'banana';

console.log(addSpace(str1)); // c o f f e e
console.log(addSpace(str2)); // b a n a n a

The String split() method splits a string in an array of substrings, using the specified separator.

const str1 = 'coffee,milk,tea';
const str2 = 'sun-moon-star';

console.log(str1.split(',')); // [ 'coffee', 'milk', 'tea' ]
console.log(str2.split('-')); // [ 'sun', 'moon', 'star' ]

By using an empty string ('') as the separator, we split up all the string characters into separate array elements.

const str1 = 'coffee';
const str2 = 'banana';

// Passing an empty string ('') to the split method

// [ 'c', 'o', 'f', 'f', 'e', 'e' ]
console.log(str1.split(''));

// [ 'b', 'a', 'n', 'a', 'n', 'a' ]
console.log(str2.split(''));

The String join() method combines each string in an array with a separator. It returns a new string containing the concatenated array elements.

const arr = ['a', 'b', 'c', 'd'];

console.log(arr.join(' ')); // a b c d
console.log(arr.join('-')); // a-b-c-d
console.log(arr.join('/')); // a/b/c/d

So passing a space character to join() separates the characters by a space in the resulting concatenation.

There will be instances where the string already contains spaces between some characters. In such cases, our approach would add even more spaces between the characters.

function addSpace(str) {
  return str.split('').join(' ');
}

// These strings have spaces between some characters
const str1 = 'co  ffee';
const str2 = 'bana  na';

console.log(addSpace(str1)); // c o     f f e e
console.log(addSpace(str2)); // b a n a     n a

This is because a space (' ') is a character too, like a letter, and calling split() would make it a separate element in the array that will be combined with additional spaces.

// These strings have spaces between some characters
const str1 = 'co  ffee';
const str2 = 'bana  na';

// The space characters are separate elements of the
// array from split()
/**
 * [
  'c', 'o', ' ',
  ' ', 'f', 'f',
  'e', 'e'
]
 */
console.log(str1.split(''));

/**
 * [
  'b', 'a', 'n',
  'a', ' ', ' ',
  'n', 'a'
]
 */
console.log(str2.split(''));

If we want to avoid the multiple spacing of the characters, we can insert a call to the filter() method between split() and join().

function addSpace(str) {
  return str
    .split('')
    .filter((item) => item.trim())
    .join(' ');
}

// The strings have spaces between some characters
const str1 = 'co  ffee';
const str2 = 'bana  na';

console.log(addSpace(str1)); // c o f f e e
console.log(addSpace(str2)); // b a n a n a

The Array filter() method returns a new array containing only the elements from the original array for which a truthy value is returned from the testing callback function passed to filter(). Calling trim() on a space (' ') results in an empty string (''), which is not a truthy value in JavaScript. So the spaces are excluded from the resulting array returned from filter().

Tip

In JavaScript, there are only six falsy values: false, null, undefined, 0, ' ' (the empty string), and NaN. Every other value is truthy.

2. for…of Loop

For a more imperative approach, we can use the JavaScript for...of loop to add a space between the characters of a string.

function addSpace(str) {
  // Create a variable to store the eventual result
  let result = '';

  for (const char of str) {
    // On each iteration, add the character and a space
    // to the variable
    result += char + ' ';
  }

  // Remove the space from the last character
  return result.trimEnd();
}

const str1 = 'coffee';
const str2 = 'banana';

console.log(addSpace(str1)); // c o f f e e
console.log(addSpace(str2)); // b a n a n a

To handle the scenario discussed earlier, where the string has spaces between some characters, call trim() on the character of each iteration, and add an if check to ensure that it is truthy, before adding it and the space to the accumulating result:

function addSpace(str) {
  // Create a variable to store the eventual result
  let result = '';

  for (const char of str) {
    // On each iteration, add the character and a space
    // to the variable

    // If the character is a space, trim it to an empty
    // string, then only add it if it is truthy
    if (char.trim()) {
      result += char + ' ';
    }
  }

  // Remove the space from the last character
  return result.trimEnd();
}

const str1 = 'co  ffee';
const str2 = 'bana  na';

console.log(addSpace(str1)); // c o f f e e
console.log(addSpace(str2)); // b a n a n a

How to Get an Input Value in Vue

After taking input from users with a text field, there has to be a way to retrieve the data and do something with it. In this article, we’ll learn how to easily get the value of an input field in Vue.

The v-model Directive

To get an input value in Vue, we can use the v-model directive to set up a two-way binding between the value and a variable.

For example:

<template>
  <div id="app">
    <input
      type="text"
      v-model="text"
      placeholder="Text"
    />
    <br />
    You typed: <b>{{ text }}</b>
  </div>
</template>

<script>
export default {
  data() {
    return {
      text: '',
    };
  },
};
</script>

Every time the user changes the text in the input field, the text variable will be updated automatically. We can then use this variable to perform an action or display information. In this example, we simply display the value of the input below it.

Using v-model to get the value of an input field in Vue

Using Vue Computed Properties with an Input Value

Instead of just displaying the value in the input field as it is, we could use a computed property to show information derived from the value.

For example, we could display the number of characters the value has:

<template>
  <div id="app">
    <input
      type="text"
      v-model="text"
      placeholder="Text"
    />
    <br />
    Character count: <b>{{ count }}</b>
  </div>
</template>

<script>
export default {
  data() {
    return {
      text: '',
    };
  },
  computed: {
    // Computed property named "count", depending on the
    // "text" variable
    count() {
      return this.text.length;
    },
  },
};
</script>
Using Vue computed properties with an input value.

How to Get an Input Value on Change

We can create a handler for the input event of the input component to perform an action with the input value when it is changed. We can listen for the event using the v-on directive (v-on:input), which can be shortened to the @ symbol (@input).

In the following example, we use the input event to log the new input value in the developer console when it changes.

<template>
  <div id="app">
    <input
      type="text"
      v-model="text"
      placeholder="Text"
      @input="handleInput"
    />
    <br />
  </div>
</template>

<script>
export default {
  data() {
    return {
      text: '',
    };
  },
  methods: {
    handleInput(event) {
      console.log(event.target.value);
    },
  },
};
</script>
How to get an input value on change in Vue.

We can also the input event to implement a custom one-way binding between the input field value and a variable. Instead of v-model, we can use the value prop to set the text in the input manually.

In the following example, we use the input event and the value prop to space out the digits of the card number entered in the input field and provide a better user experience.

<template>
  <div id="app">
    <input
      type="text"
      :value="cardNo"
      placeholder="Card number"
      @input="handleInput"
      @keypress="handleKeyPress"
    />
    <br />
  </div>
</template>

<script>
export default {
  data() {
    return {
      cardNo: '',
    };
  },
  methods: {
    handleInput(event) {
      this.cardNo = event.target.value
        // Remove spaces from previous value
        .replace(/\s/g, '')
        // Add a space after every set of 4 digits
        .replace(/(.{4})/g, '$1 ')
        // Remove the space after the last set of digits
        .trim();
    },
    handleKeyPress(event) {
      const num = Number(event.key);
      const value = event.target.value;
      // Only allow 16 digits
      if ((!num && num !== 0) || value.length >= 16 + 3) {
        event.preventDefault();
      }
    },
  },
};
</script>
Spacing out the entered card number
Spacing out the entered card number

How to Get an Input Value with a Ref

In most scenarios, v-model and @input/value will be sufficient for reading or updating the value of an input field. However, we can also use the ref attribute to get the input value. We can set this attribute on any DOM element and use the $refs property of the Vue instance to access the object that represents the element.

For example:

<template>
  <div id="app">
    <!-- Create new ref by setting "ref" prop -->
    <input
      type="text"
      placeholder="Text"
      ref="inputField"
    />
    <button @click="handleShout">Shout</button>
    <br />
    <b>{{ shout }}</b>
  </div>
</template>

<script>
export default {
  data() {
    return {
      shout: '',
    };
  },
  methods: {
    handleShout() {
      // Access ref with "$refs" property
      const message = this.$refs.inputField.value;
      this.shout = `${message.toUpperCase()}!!!`;
    },
  },
};
</script>
How to get an input value with a Vue ref

How to Quickly Use a Button as a Link in React

To use a button as a link in React, wrap the button in an anchor (<a>) element. Clicking a link button will make the browser navigate to the specified URL.

JavaScript
export default function MyComponent() { return ( <div> <a href="/posts"> <button>Posts</button> </a> </div> ); }

If you’re using React Router, then wrap the button in the Link component instead, to make the browser navigate to the specified route without refreshing the page when the button is clicked.

JavaScript
import { Link } from 'react-router-dom'; export default function MyComponent() { return ( <div> <Link to="/posts"> <button>Posts</button> </Link> </div> ); }

The react-router-dom Link component renders an anchor element, so it works similarly to the first example.

We can also use custom button components as links by wrapping them with an anchor element or Link component. For example:

JavaScript
import { Link } from 'react-router-dom'; function MyCustomButton({ children }) { return <button>{children}</button>; } export default function MyComponent() { return ( <div> <Link to="/posts"> <MyCustomButton>Posts</MyCustomButton> </Link> </div> ); }

When using Material UI, we can specify a link for the Button component using the href prop.

JavaScript
import { Button } from '@mui/material'; export default function MyComponent() { return ( <div> <Button href="/posts">Posts</Button> </div> ); }

To use as a React Router Link, we can use the component prop of the Button.

JavaScript
import { Button } from '@mui/material'; import { Link } from 'react-router-dom'; export default function MyComponent() { return ( <div> <Button component={Link} to="/posts"> Posts </Button> </div> ); }

Other Material UI components like IconButton also have a component prop. Setting this prop is useful when we want the button component to inherit its color from its parent.

In this scenario, if we wrap the component with a Link, it will inherit its color from the Link instead of the intended parent. For example:

JavaScript
import { IconButton, Box, Typography } from '@mui/material'; import { Link } from 'react-router-dom'; import { Photo } from '@mui/icons-material'; export default function MyComponent() { return ( // We want the IconButton to inherit its parent color (white) <Box sx={{ backgroundColor: 'black', color: 'white', padding: 2 }}> <Typography>Lorem Ipsum</Typography> {/* But this wrapping makes it inherit from this Link */} <Link to="/photos"> <IconButton color="inherit"> <Photo /> </IconButton> </Link> </Box> ); }
The IconButton inherits its color from the Link(blue) instead of the Box (white).
The IconButton inherits its color from the Link (blue) instead of the Box (white).

We can fix this issue by setting the component prop to a Link instead of wrapping:

JavaScript
import { IconButton, Box, Typography } from '@mui/material'; import { Link } from 'react-router-dom'; import { Photo } from '@mui/icons-material'; export default function MyComponent() { return ( <Box sx={{ backgroundColor: 'black', color: 'white', padding: 2 }}> <Typography>Lorem Ipsum</Typography> {/* Setting the "component" prop to a "Link" component */} <IconButton component={Link} to="/photos" color="inherit"> <Photo /> </IconButton> </Box> ); }
The IconButton inherits its color from the Box.
The IconButton inherits its color from the Box.

How to Build an Advanced Space Remover Tool With React

In this article, we’re going to learn how to build a web app that will let us easily remove leading and trailing spaces from any text, with the ability to optionally preserve the indentation of the text. We’ll be using the React.js library to build this tool, let’s get started.

Setting up the Project

Let’s begin by creating a new React app using Create React App. We’ll be using Yarn.

yarn create-react-app remove-spaces

We’ll also be using a bit of TypeScript, you can set it up using the instructions here.

Writing the removeSpaces() Function

The core part of the app will be a removeSpaces() function that takes a string as input and returns a new string with the spaces removed. Let’s write this function in a new remove-spaces.ts file.

src/remove-spaces.ts

export default function removeSpaces(params: {
  text: string;
  leading: boolean;
  trailing: boolean;
  preserveIndent: boolean;
}) {
  let regex: RegExp;
  const { text, leading, trailing, preserveIndent } = params;
  let spaceCountPattern: string | undefined;

  let leadingMatch: string;
  if (leading) {
    if (preserveIndent) {
      const firstSpacePattern = new RegExp(String.raw`^(\s*).+?((\r\n)|\n|$)`);
      const firstSpaces = text.match(firstSpacePattern)?.[1];
      const spaceCount = firstSpaces?.length;
      spaceCountPattern = `{0,${spaceCount}}`;
    } else {
      spaceCountPattern = '*';
    }
    leadingMatch = String.raw`\s${spaceCountPattern}`;
  } else {
    leadingMatch = '';
  }

  const trailingMatch = trailing ? String.raw`\s*?` : '';
  regex = new RegExp(String.raw`((()((\r\n)|\n))|(.*?((\r\n)|\n|$)))`, 'g');
  const lines = text.match(regex);
  const lineRegex = new RegExp(
    String.raw`^${leadingMatch}(.*?)${trailingMatch}((\r\n)|\n|$)`,
    'g'
  );

  const result = lines
    ?.map((line) => {
      if (line === '\r\n' || line === '\n') return line;
      return line.replace(lineRegex, '$1$2');
    })
    .join('');
  return result;
}

Apart from the input string, the function accepts options that will allow the user to customize how the spaces are removed.

When leading is true and preserveIndent is false, the leading spaces are removed from the text, apart from the spaces that add indentation.

When leading is true and preserveIndent is false, all the leading spaces are removed from the text.

When trailing is true, all the trailing spaces are removed from the text.

The function creates a regular expression from the combination of these options. It uses the String replace() method to replace each line of the text with captured groups from the regex.

Testing the removeSpaces() function

We can test this function to be sure it works as intended. Let’s install the Jest testing framework to do this.

yarn add --dev jest ts-jest @types/jest

Initialize ts-jest with the following command:

yarn ts-jest config:init

Let’s write some tests for the function in a new remove-spaces.test.ts file:

src/remove-spaces.test.ts

import removeSpaces from './remove-spaces';

const s2 = '  ';
const s4 = '    ';

const text = `${s4}<div>${s4}
${s4}${s2}<p></p>${s4}
${s4}</div>${s4}`;

it('removes leading spaces without preserving indent', () => {
  const expectation = `<div>${s4}
<p></p>${s4}
</div>${s4}`;
  const result = removeSpaces({
    text,
    leading: true,
    trailing: false,
    preserveIndent: false,
  });
  expect(result).toBe(expectation);
});

it('removes leading spaces and preserves indent', () => {
  const expectation = `<div>${s4}
${s2}<p></p>${s4}
</div>${s4}`;
  const result = removeSpaces({
    text,
    leading: true,
    trailing: false,
    preserveIndent: true,
  });
  expect(result).toBe(expectation);
});

it('removes trailing spaces', () => {
  const expectation = `${s4}<div>
${s4}${s2}<p></p>
${s4}</div>`;
  const result = removeSpaces({
    text,
    leading: false,
    trailing: true,
    preserveIndent: false,
  });
  expect(result).toBe(expectation);
});

it('removes leading and trailing spaces', () => {
  const expectation = `<div>
<p></p>
</div>`;
  const result = removeSpaces({
    text,
    leading: true,
    preserveIndent: false,
    trailing: true,
  });
  expect(result).toBe(expectation);
});

The function should pass all these tests if it was written correctly.

Creating the Text Inputs

It’s time for us to start creating the user interface with React. We’ll begin with the text inputs. We’ll create two – one will take will user input, and the other will be readonly and display the output.

We’ll be using the Material UI framework to make the app look great, you can set it up using the instructions here.

src/App.js

import { Box, Typography, TextField } from '@mui/material';
import { useState } from 'react';

function App() {
  const [input, setInput] = useState('');
  const [output, setOutput] = useState('');

  const handleInputChange = (event) => {
    setInput(event.target.value);
  };

  return (
    <Box
      sx={{
        height: '100%',
        display: 'flex',
        flexDirection: 'column',
        padding: 2,
        boxSizing: 'border-box',
      }}
    >
      <Box
        sx={{
          display: 'grid',
          gridTemplateColumns: 'repeat(auto-fit, minmax(400px, 1fr))',
          justifyContent: 'stretch',
          marginTop: 2,
          rowGap: '16px',
        }}
      >
        <Box sx={{ flex: 1, marginRight: 1, textAlign: 'left' }}>
          <Typography>Input</Typography>
          <TextField
            sx={{ width: '100%', marginTop: 1, minWidth: '300px' }}
            multiline
            value={input}
            minRows={10}
            inputProps={{
              style: { maxHeight: '300px', overflow: 'auto' },
            }}
            onChange={handleInputChange}
          ></TextField>
        </Box>
        <Box sx={{ flex: 1, marginLeft: 1, textAlign: 'right' }}>
          <Typography>Output</Typography>
          <TextField
            sx={{
              width: '100%',
              marginTop: 1,
              minWidth: '300px',
            }}
            multiline
            value={output}
            readOnly
            minRows={10}
            inputProps={{
              style: { maxHeight: '300px', overflow: 'auto' },
            }}
          ></TextField>
        </Box>
      </Box>
    </Box>
  );
}

export default App;
Creating the text inputs.

Pasting Input from the Clipboard

Let’s create a button that will paste text from the system clipboard to the input text field when clicked.

src/App.js

// ...
import { Box, Typography, TextField, Stack, Button } from '@mui/material';
import { ContentPaste } from '@mui/icons-material';

function App() {
  // ...

  const pasteInput = async () => {
    setInput(await navigator.clipboard.readText());
  };

  const handlePasteInput = async () => {
    await pasteInput();
  };

  return (
    <Box
      sx={{
        height: '100%',
        display: 'flex',
        flexDirection: 'column',
        padding: 2,
        boxSizing: 'border-box',
      }}
    >
      <Stack
        direction="row"
        spacing={2}
        justifyContent="center"
        sx={{ flexWrap: 'wrap', marginTop: 2 }}
      >
        <Box>
          <Button
            onClick={handlePasteInput}
            variant="outlined"
            startIcon={<ContentPaste />}
          >
            Paste input
          </Button>
        </Box>
      </Stack>
      {/* ... */}
    </Box>
  );
}

export default App;
Pasting input from the clipboard.

Adding Options

Let’s create the options that will let the user decide how the spaces will be removed from the text. There will be three boolean options, each represented with a checkbox:

  1. Remove leading spaces
  2. Remove trailing spaces
  3. Preserve indent

We’ll pass the options directly to the removeSpaces() function when the user decides to remove the spaces.

import {
  Box,
  Typography,
  TextField,
  Stack,
  Button,
  FormControlLabel,
  Checkbox,
} from '@mui/material';
import { useState } from 'react';
import { ContentPaste } from '@mui/icons-material';

function App() {
  // ...

  const [leading, setLeading] = useState(true);
  const [trailing, setTrailing] = useState(true);
  const [preserveIndent, setPreserveIndent] = useState(true);

  const handleLeadingChange = (event) => {
    setLeading(event.target.checked);
  };

  const handleTrailingChange = (event) => {
    setTrailing(event.target.checked);
  };

  const handlePreserveIndentChange = (event) => {
    setPreserveIndent(event.target.checked);
  };

  return (
    <Box
      sx={{
        height: '100%',
        display: 'flex',
        flexDirection: 'column',
        padding: 2,
        boxSizing: 'border-box',
      }}
    >
      <Box sx={{ display: 'flex', justifyContent: 'center' }}>
        <FormControlLabel
          control={
            <Checkbox checked={leading} onChange={handleLeadingChange} />
          }
          label="Remove leading spaces"
        />
        <FormControlLabel
          control={
            <Checkbox
              checked={preserveIndent}
              onChange={handlePreserveIndentChange}
            />
          }
          label="Preserve indent"
        />
        <FormControlLabel
          control={
            <Checkbox checked={trailing} onChange={handleTrailingChange} />
          }
          label="Remove trailing spaces"
        />
      </Box>
     {/* ... */}
    </Box>
  );
}

export default App;
Adding options.

Removing the Spaces

Now let’s add a button that will cause the spaces to be removed from the input text when clicked.


// ...
import removeSpaces from './remove-spaces';

function App() {
  const handleRemoveSpaces = () => {
    setOutput(removeSpaces({ text: input, leading, trailing, preserveIndent }));
  };

  return (
    <Box
      sx={{
        height: '100%',
        display: 'flex',
        flexDirection: 'column',
        padding: 2,
        boxSizing: 'border-box',
      }}
    >
      <Box sx={{ display: 'flex', justifyContent: 'center' }}>
        {/* ... */}
        
        <Box>
          <Button
            onClick={handlePasteInput}
            variant="outlined"
            startIcon={<ContentPaste />}
          >
            Paste input
          </Button>
        </Box>

        {/* Button to remove spaces */}
        <Box>
          <Button
            onClick={handleRemoveSpaces}
            variant="outlined"
            startIcon={<RemoveCircle />}
          >
            Remove spaces
          </Button>
        </Box>
      </Stack>
      {/* ... */}
      </Box>
    </Box>
  );
}

export default App;
Removing the spaces.

Copying Output to Clipboard

Let’s create another button that will copy the text in the output text field to the system clipboard when clicked.


// ...
import { ContentCopy, ContentPaste, RemoveCircle } from '@mui/icons-material';
import removeSpaces from './remove-spaces';

function App() {
  // ...

  const handleCopyOutput = () => {
    navigator.clipboard.writeText(output);
  };

  return (
    <Box
      sx={{
        height: '100%',
        display: 'flex',
        flexDirection: 'column',
        padding: 2,
        boxSizing: 'border-box',
      }}
    >
      {/* ... */}
      <Stack
        direction="row"
        spacing={2}
        justifyContent="center"
        sx={{ flexWrap: 'wrap', marginTop: 2 }}
      >
        {/* ... */}
        <Box>
          <Button
            onClick={handleRemoveSpaces}
            variant="outlined"
            startIcon={<RemoveCircle />}
          >
            Remove spaces
          </Button>
        </Box>

        {/* Button to copy output */}        
        <Box>
          <Button
            startIcon={<ContentCopy />}
            onClick={handleCopyOutput}
            variant="outlined"
          >
            Copy output
          </Button>
        </Box>
      </Stack>
          
    </Box>
  );
}

export default App;
Copying output to clipboard.

Combining Paste, Remove, and Copy Actions

It’s quite likely that users will use this tool by performing the following actions in order:

  1. Click the Paste Input button to put the text from the clipboard in the input text field
  2. Click the Remove Spaces button to remove the spaces from the input text and put the result in the output text field
  3. Click the Copy Output to copy the text from the output text field to the clipboard.

To make things easier, we’ll create a button that will let the user perform these three actions at once:

// ...

function App() {
  // ...

  const handlePasteRemoveCopy = async () => {
    const input = await navigator.clipboard.readText();
    const output = removeSpaces({
      text: input,
      leading,
      trailing,
      preserveIndent,
    });
    navigator.clipboard.writeText(output);
    setInput(input);
    setOutput(output);
  };

  return (
    <Box
      sx={{
        height: '100%',
        display: 'flex',
        flexDirection: 'column',
        padding: 2,
        boxSizing: 'border-box',
      }}
    >
      <Box sx={{ display: 'flex', justifyContent: 'center' }}>
        {/* ... */}
        <FormControlLabel
          control={
            <Checkbox checked={trailing} onChange={handleTrailingChange} />
          }
          label="Remove trailing spaces"
        />
      </Box>

      {/* Button to perform past, remove, and copy actions at once */}
      <Box sx={{ display: 'flex', justifyContent: 'center', marginTop: 2 }}>
        <Button onClick={handlePasteRemoveCopy} variant="contained">
          Paste + Remove + Copy
        </Button>
      </Box>

      <Stack
        direction="row"
        spacing={2}
        justifyContent="center"
        sx={{ flexWrap: 'wrap', marginTop: 2 }}
      >
        <Box>
          <Button
            onClick={handlePasteInput}
            variant="outlined"
            startIcon={<ContentPaste />}
          >
            Paste input
          </Button>
        </Box>
        {/* ... */}
      </Stack>
    </Box>
  );
}

export default App;

Our space remover app is complete! We’ve been able to build a handy utility for removing leading and trailing spaces from any text and preserving indentation if necessary.

What Can This Tool Be Used for?

At Coding Beauty, we found this tool useful when creating code snippets displaying a portion of code from an HTML or JSX markup that was indented by some amount. For example, in our Material UI button tutorial, there were times when the file for an example contained markup like this:

The complete source code for an example in the tutorial.
The complete source code for an example in the tutorial.

But we would only want to show the section of the file relevant to the example:

Explaining contained buttons in the Material UI button tutorial.
Explaining contained buttons in the Material UI button tutorial.

This tool helped format the relevant section properly by removing the spaces.

What about String trim()?

We couldn’t use the trim() or trimStart() string methods because then it wouldn’t be possible to preserve the indent of the entire text. These methods can only remove all the leading spaces in a given string.

How to Get a Month Number from Month Name in JavaScript

In this article, we’ll learn how to use JavaScript to get the position of a month in the list of the 12 months from its name. That is, we’ll get 1 from January, 2 from February, 3 from March, and so on.

To do this, create a date string from the name and pass this string to the Date() constructor. Then use the getMonth() method to get the month number. For example:

function getMonthNumberFromName(monthName) {
  return new Date(`${monthName} 1, 2022`).getMonth() + 1;
}

console.log(getMonthNumberFromName('January')); // 1
console.log(getMonthNumberFromName('February')); // 2
console.log(getMonthNumberFromName('March')); // 3

We interpolate the month into a string that can be parsed by the Date() constructor to create a new Date object. Then we use the getMonth() method to get the month of the date.

The getMonth() method returns a zero-based index of the month, i.e., 0 for January, 1 for February, 2 for March, etc.

const month1 = new Date('January 1, 2022').getMonth();
console.log(month1); // 0

const month2 = new Date('February 1, 2022').getMonth();
console.log(month2); // 1

This is why we add 1 to it and return the sum from as the result.

Our function will also work for abbreviated month names, as the Date() constructor can also parse date strings with them.

function getMonthNumberFromName(monthName) {
  return new Date(`${monthName} 1, 2022`).getMonth() + 1;
}

console.log(getMonthNumberFromName('Jan')); // 1
console.log(getMonthNumberFromName('Feb')); // 2
console.log(getMonthNumberFromName('Mar')); // 3

If the month name is such that the resulting date string can’t be parsed by the Date() constructor, an invalid date will be created and getMonth() will return NaN.

const date = new Date('Invalid 1, 2022');

console.log(date); // Invalid Date
console.log(date.getMonth()); // NaN

This means our function will return NaN as well:

function getMonthNumberFromName(monthName) {
  return new Date(`${monthName} 1, 2022`).getMonth() + 1;
}

console.log(getMonthNumberFromName('Invalid')); // NaN

It might be better if we return -1 instead. We can check for an invalid date with the isNaN() function.

function getMonthNumberFromName(monthName) {
  const date = new Date(`${monthName} 1, 2022`);

  if (isNaN(date)) return -1;

  return date.getMonth() + 1;
}

console.log(getMonthNumberFromName('Invalid')); // -1

Alternatively, we could throw an error:

function getMonthNumberFromName(monthName) {
  const date = new Date(`${monthName} 1, 2022`);

  if (isNaN(date)) {
    throw new Error('Invalid month name.');
  }

  return date.getMonth() + 1;
}

// Error: Invalid month name.
console.log(getMonthNumberFromName('Invalid'));

How to Add 1 Year to a Date in JavaScript

Let’s look at some ways to easily add 1 year to a Date object in JavaScript.

1. Date setFullYear() and getFullYear() Methods

To add 1 year to a date, call the getFullYear() method on the date to get the year, then call the setFullYear() method on the date, passing the sum of getFullYear() and 1 as an argument, i.e., date.setFullYear(date.getFullYear() + 1).

For example:

function addOneYear(date) {
  date.setFullYear(date.getFullYear() + 1);
  return date;
}

// April 20, 2022
const date = new Date('2022-04-20T00:00:00.000Z');

const newDate = addOneYear(date);

// April 20, 2023
console.log(newDate); // 2023-04-20T00:00:00.000Z

Our addOneYear() function takes a Date object and returns the same Date with the year increased by 1.

The Date getFullYear() method returns a number that represents the year of a particular date.

The Date setFullYear() method sets the year of a date to a specified number.

Avoiding Side Effects

The setFullYear() method mutates the Date object it is called on. This introduces a side effect into our addOneYear() function. To avoid modifying the passed Date and create a pure function, make a copy of the Date and call setFullYear() on this copy, instead of the original.

function addOneYear(date) {
  // Making a copy with the Date() constructor
  const dateCopy = new Date(date);

  dateCopy.setFullYear(dateCopy.getFullYear() + 1);

  return dateCopy;
}

// April 20, 2022
const date = new Date('2022-04-20T00:00:00.000Z');

const newDate = addOneYear(date);

// April 20, 2023
console.log(newDate); // 2023-04-20T00:00:00.000Z

// Original not modified
console.log(date); // 2022-04-20T00:00:00.000Z

Functions that don’t modify external state (i.e., pure functions) tend to be more predictable and easier to reason about. This makes it a good practice to limit the number of side effects in your programs.

2. date-fns addYears() Function

Alternatively, we can use the pure addYears() function from the date-fns NPM package to quickly add 1 year to a date.

import { addYears } from 'date-fns';

// April 20, 2022
const date = new Date('2022-04-20T00:00:00.000Z');

const newDate = addYears(date, 1);

// April 20, 2023
console.log(newDate); // 2023-04-20T00:00:00.000Z

// Original not modified
console.log(date); // 2022-04-20T00:00:00.000Z

This function takes a Date object and the number of years to add as arguments, and returns a new Date object with the newly added years. It does not modify the original date passed to it.

How to Check if a String is a URL in JavaScript

In this article, we’ll be looking at multiple ways to easily check if a string is a valid URL in JavaScript.

1. Catch Exception from URL() Constructor

To check if a string is a URL, pass the string to the URL() constructor. If the string is a valid URL, a new URL object will be created successfully. Otherwise, an error will be thrown. Using a try...catch block, we can handle the error and perform the appropriate action when the URL is invalid.

For example:

function isValidUrl(string) {
  try {
    new URL(string);
    return true;
  } catch (err) {
    return false;
  }
}

console.log(isValidUrl('https://codingbeautydev.com')); // true
console.log(isValidUrl('app://codingbeautydev.com')); // true
console.log(isValidUrl('Coding Beauty')); // false

To check for a valid HTTP URL, we can use the protocol property of the URL object.

function isValidHttpUrl(string) {
  try {
    const url = new URL(string);
    return url.protocol === 'http:' || url.protocol === 'https:';
  } catch (err) {
    return false;
  }
}

console.log(isValidHttpUrl('https://codingbeautydev.com')); // true
console.log(isValidHttpUrl('app://codingbeautydev.com')); // false
console.log(isValidHttpUrl('Coding Beauty')); // false

The URL protocol property returns a string representing the protocol scheme of the URL, including the final colon (:). HTTP URLs have a protocol of either http: or https:.

2. Regex Matching

Alternatively, we can check if a string is a URL using a regular expression. We do this by calling the test() method on a RegExp object with a pattern that matches a string that is a valid URL.

function isValidUrl(str) {
  const pattern = new RegExp(
    '^([a-zA-Z]+:\\/\\/)?' + // protocol
      '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
      '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address
      '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path
      '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string
      '(\\#[-a-z\\d_]*)?$', // fragment locator
    'i'
  );
  return pattern.test(str);
}

console.log(isValidUrl('https://codingbeautydev.com')); // true
console.log(isValidUrl('app://codingbeautydev.com')); // true
console.log(isValidUrl('Coding Beauty')); // false

The RegExp test() method searches for a match between a regular expression and a string. It returns true if it finds a match. Otherwise, it returns false.

To check for a valid HTTP URL, we can alter the part of the regex that matches the URL protocol:

function isValidHttpUrl(str) {
  const pattern = new RegExp(
    '^(https?:\\/\\/)?' + // protocol
      '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
      '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address
      '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path
      '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string
      '(\\#[-a-z\\d_]*)?$', // fragment locator
    'i'
  );
  return pattern.test(str);
}

console.log(isValidHttpUrl('https://codingbeautydev.com')); // true
console.log(isValidHttpUrl('app://codingbeautydev.com')); // false
console.log(isValidHttpUrl('Coding Beauty')); // false

The https?: pattern will only match either http: or https:.

3. is-url and is-url-http NPM Packages

We can also use the is-url NPM package to quickly check if a string is a valid URL.

import isUrl from 'is-url';

console.log(isUrl('https://codingbeautydev.com')); // true
console.log(isUrl('app://codingbeautydev.com')); // true
console.log(isUrl('Coding Beauty')); // false

To quickly check if a string is a valid HTTP URL, we can use the is-url-http package from NPM.

import isUrlHttp from 'is-url-http';

console.log(isUrlHttp('https://codingbeautydev.com')); // true
console.log(isUrlHttp('app://codingbeautydev.com')); // false
console.log(isUrlHttp('Coding Beauty')); // false