Categories
Uncategorized

What’s New in JavaScript — ES2019

Ever since ES2015 released, which was a great leap forward in itself, JavaScript has been improving at a fast pace. Every year since, there have been new features added to the JavaScript specification. Features have been consistently added, like new syntax and new methods for built in JavaScript.

In ES2016 and 2017, the Object object has had methods like Object.values and Object.entries added. String methods like padStart and padEnd were added in ES2017. async and await , a shorthand syntax for chaining promises, were also added in ES2017. The includes methods for arrays were added in ES2016. ES2018 was another release with lots of new features. With ES2018, the spread syntax is now available for object literals. Rest parameters were also added. The for await...of loop, which is a loop syntax iterating through promises sequentially, was added. The SharedArrayBuffer object for representing raw binary data that cannot become detached was added. A finally function was also added to the Promise object.

In 2019, even more new JavaScript features have been added. 2019’s release brings more new methods to arrays and strings. The catch clause no longer needs to have a binding added to it — that is, the variable enclosed in parentheses after the catch keyword is longer required.

The description method has been added to the Symbol . The toString method of the Function object now preserves all characters of the function, so that it shows like it’s in your code, and now JSON.stringify will always encode in UTF-8.

Array.flat()

The Array.flat() function converts items in nested arrays to items in top level of the array. It does this recursively up to the given depth. To call the flat function on an array, we just have to path in the depth of the level that you want to flatten up to, which defaults to 1. It returns a new array with the sub-array elements concatenated into it. To flatten all levels of nested arrays, we can pass in Infinity .

For example, we can write:

const arr1 = [5, 6, [7, 8]];
console.log(arr1.flat());
// [5, 6, 7, 8]

const arr2 = [5, 6, [7, 8, [9, 10]]];
console.log(arr2.flat());
// [5, 6, 7, 8, [9, 10]]

const arr3 = [5, 6, [7, 8, [9, 10]]];
console.log(arr3.flat(2));
//  [5, 6, 7, 8, 9, 10]

const arr4 = [6, 7, [8, 9, [10, 11, [12, 13, [14, 15]]]]];
console.log(arr4.flat(Infinity));
//  [6, 7, 8, 9, 10, 11, 12, 13, 14, 15]

As you can see, this is a very handy method for removing nesting from a nested array. This is very valuable since it’s hard work to write our own function to recursively flatten nested arrays into a flattened array less nesting or without any nesting.

Empty slots in arrays are removed after Array.flat is ran. For example:

const arr = [1, 2, , 3, 4];
arr.flat();
// [1, 2, 3, 4]

The empty slot is removed from the arr .

Array.flatMap()

The flatMap method maps an array’s entries into another array and then flatten the results. It’s equivalent to calling map on an array followed by flat with depth 1. It’s a great shorthand for mapping and then flattening which has some use cases since lots of arrays aren’t nested too deeply. The flatMap function take callback function on how to map the array. The callback function takes the current value of the array, index, and the originally array that the flatMap method is called on as parameters.

For example, we can use flatMap as in the following examples:

let arr = [1, 2, 3];

arr.map(x => [x * 10]);
// [[10], [20], [30]]]

arr.flatMap(x => [x * 10]);
// [10, 20, 30]

arr.flatMap(x => [[x * 2]]);
// [[2], [4], [6]]

As you can see, flatMap only flattens one level of the array. If we want to flatten more than one level after mapping we have to call map and flat separately.

Function.toString() Changes

Function objects always have the toString() method to get the string representation of a function. In ES2019, the toString() function now preserves comments and whitespaces to get the exact string representation of the function as we defined it.

For example, if we have the following:

function fn() {
  /* comment */
}

console.log(fn.toString())

We would now get the exactly the same thing as the code if we run toString() on the function. This means that this is logged:

function fn() {
  /* comment */
}

JSON.stringify() Fix

JSON.stringify now returns the correct characters for special unicode characters since now all characters are now UTF-8 encoded. The characters affected range from code U+D800 to U+DFF.

Now, if we call JSON.stringify on an object with those characters, we no longer get malformed characters back. If we call JSON.stringify then call JSON.parse on the string returned by JSON.parse , we get the same character back before we stringify it.

String.trimStart()

The string object now has a trimStart() function to trim the beginning whitespace of a string. There’s also a trimLeft() method which is an alias to this method.

For example, we can write:

let message = '   Hi! How's it going?   ';

console.log(message);

// We get '   Hi! How's it going?   '

let message = '   Hi! How's it going?   ';
console.log(message.trimStart());

// We get 'Hi! How's it going?   '

As we can see, the whitespace on the left side is gone. We can do the same thing with trimLeft() :

let message = '   Hi! How's it going?   ';
console.log(message.trimLeft());

// We get 'Hi! How's it going?   '

Note that a new string if returned with trimStart or trimLeft , so the original string stays intact. This prevents us from mutating the original string, which is handy for preventing mistakes from accidentally mutating objects.

String.trimEnd()

The trimEnd method removes whitespace from the right end of the string. trimRight is an alias of the trimEnd method. For example, we write:

let message = '   Hi! How's it going?   ';
console.log(message);
// We get '   Hi! How's it going?   '

let message = '   Hi! How's it going?';
console.log(message.trimEnd());
// We get '   Hi! How's it going?'

Note that a new string if returned with trimEnd or trimRight , so the original string stays intact. This prevents us from mutating the original string, which is handy for preventing mistakes from accidentally mutating objects.

Optional Catch Binding

With ES2019, the catch clause does not have to have a binding added to it. That is, the variable enclosed in parentheses after the catch keyword is longer required. This means that now we can write this:

try {
    ···
} catch {
    ···
}

Now we do not have to write this:

try {
    ···
} catch (error) {
    ···
}

This means that if we don’t have to use the error object, we don’t have to add the binding into the catch clause. It’s useful for ignoring the error, or if we don’t care what the error is. However, the error object is still handy for logging and checking for property inputs — and handling errors gracefully will prevent exceptions from being thrown.

For example, we can use it to catch any kind of exception, like with JSON.parse :

try {
  return JSON.parse(str);
} catch {
  return {}
}

We can handle errors with invalid JSON strings gracefully. The only issue with that is that we are just swallowing all exceptions, so it might be a better idea to catch some kinds of errors.

We can also use it to use browser features that aren’t supported in all browsers. For instance:

try {
  navigator.geolocation
} catch {
  return false;
}

Symbol.description

Symbols is a primitive data type that has its own type. There are some static properties and methods of its own that expose the global symbol registry. It’s like a built-in object, but it doesn’t have a constructor, so we can’t write new Symbol to construct a Symbol object with the new keyword. It’s mainly used for unique identifiers in an object. It’s a Symbol’s only purpose.

To create new symbols, we can write this:

const fooSymbol = Symbol('foo')

Note that each time we call the Symbol function, we get a new Symbol — this expression would be false:

Symbol('sym') === Symbol('sym')

With ES2019, we have a description property which is read only. It returns a string that has the parameter that we pass into the Symbol function or the object property path of well-known symbols.

If we use the example above and use the description property, we get this:

const fooSymbol = Symbol('foo');
console.log(fooSymbol.description);

We get foo logged.

With ES2019, we get more new features that we can use for developing JavaScript apps.

2019’s release brings more new methods to arrays and strings. The catch clause no longer has to have a binding added to it. That is, the variable enclosed in parentheses after the catch keyword is longer required.

The descrption method has been added to the Symbol .

The toString method of the Function object now preserves all characters of the function so that it shows like it’s in your code.

JSON.stringify will always encode in UTF-8, so now we don’t have malformed characters when we try to stringify characters ranging from code U+D800 to U+DFF.

Finally, arrays now can be flattened without writing our own code with the flat and flatMap methods.

Categories
Uncategorized

How to Use the React useEffect Hook with Debounce?

Sometimes, we may not want to run the code in the useEffect hook immediately after a state update.

In this article, we’ll look at how to use the useEffect hook with the code inside the useEffect callback debounced.

Use the React useEffect Hook with Debounce

We can create our own hook that uses the useEffect hook to run code with the useEffect callback debounced.

To do this, we can write:

import React, { useEffect, useRef, useState } from "react";

const useDebounce = (value, delay) => {
  const [debouncedValue, setDebouncedValue] = useState("");
  const firstDebounce = useRef(true);

  useEffect(() => {
    if (value && firstDebounce.current) {
      setDebouncedValue(value);
      firstDebounce.current = false;
      return;
    }

    const handler = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);

    return () => clearTimeout(handler);
  }, [value, delay]);

return debouncedValue;
};

export default function App() {
  const value = useDebounce("abc", 1000);

  useEffect(() => {
    console.log(value);
  }, [value]);

  return <div>{value}</div>;
}

We create the useDebounce hook with the value and delay parameters.

value is the value we want to set.

delay is the denounce delay for the useEffect callback code.

We have the firstDebounce ref to keep track of whether the denounced code is running the first time.

In the useEffect callback, we set firstDebounce.current to false so that we know that it’s not the first time that the denounced code is run it.

Then we call the setTimeout function with a callback with the denounced code.

In the callback, we call setDebouncedValue to set the debouncedValue state value.

Then we return the call that runs clearTimeout which runs when the component is unmounted.

In App , we call useDebounce with the value we want to set and the delay.

Then we log the value in the useEffect callback when the value value changes.

And we also render the value below that.

Now we should see the 'abc' string rendered and logged after 1 second.

Conclusion

We can create our own hook to run code that we want to denounce within the useEffect callback.

Categories
Uncategorized

BootstrapVue — Table Filtering and Loading

To make good looking Vue apps, we need to style our components.

To make our lives easier, we can use components with styles built-in.

We look at how to customize table contents, including filtering.

Filtering

BootstrapVue table contents can be filtered.

To add built-in filtering features, we can add the filter prop.

For example, we can write:

<template>
  <div id="app">
    <b-table :items="items" filter="may"></b-table>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      items: [
        { id: 1, firstName: "alex", lastName: "green" },
        {
          id: 2,
          firstName: "may",
          lastName: "smith"
        },
        { id: 3, firstName: "james", lastName: "jones" }
      ]
    };
  }
};
</script>

We just pass in a string into the filter prop and it’ll find the rows with the word 'may' in it by searching all properties.

Also, we can pass in a regex to filter by a pattern.

Pagination

We can use the b-pagination component with b-table to control pagination.

For example, we can write:

<template>
  <div id="app">
    <b-table :items="items" :per-page="perPage" :current-page="currentPage"></b-table>
    <b-pagination v-model="currentPage" :total-rows="items.length" :per-page="perPage"></b-pagination>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      currentPage: 1,
      perPage: 2,
      items: [
        { id: 1, firstName: "alex", lastName: "green" },
        {
          id: 2,
          firstName: "may",
          lastName: "smith"
        },
        { id: 3, firstName: "james", lastName: "jones" }
      ]
    };
  }
};
</script>

We set the per-page and current-page props to perPage and currentPage respectively.

perPage is fixed to 2.

currentPage is updated when we click on the button rendered by b-pagination .

b-pagination also has the total-rows prop so that it can render the right number of buttons.

v-model is bound to currentPage so that it’s updated when we click the buttons.

Now we get pagination in our table.

Items Provider Functions

We can add an items provider function to provide items.

It can be synchronous or async.

For example, we can make a synchronous one by writing:

function provider() {
  let items = [];
  return items || [];
}

To make an async provider function, we can write:

function provider(ctx, callback) {
  this.fetchData(`/some/url?page=${ctx.currentPage}`)
    .then(data => {
      const items = data.items;
      callback(items)
    })
    .catch(() => {
      callback([])
    })
  return null
}

We return null or undefined to tell b-table that a callback is being used.

The data that we use to fetch the data is in the ctx parameter.

ctx comes from the props.

callback is called with the fetched items to display it with b-table .

We can also use an async function:

async function provider(ctx) {
  try {
    const response = await axios.get(`/some/url?page=${ctx.currentPage}`)
    return response.items;
  } catch (error) {
    return []
  }
}

They can be set as the value of the items prop:

<template>
  <div id="app">
    <b-table :items="provider"></b-table>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {

};
  },
  methods: {
    provider(){
      return [
        { id: 1, firstName: "alex", lastName: "green" },
        {
          id: 2,
          firstName: "may",
          lastName: "smith"
        },
        { id: 3, firstName: "james", lastName: "jones" }
      ]
    }
  }
};
</script>

Refresh Table Data

We can force the refresh of data table by emitting the bv::refresh::table event.

For example, we can write:

this.$root.$emit('bv::refresh::table', 'table')

to refresh the table with ref table .

Also, we can write:

this.$refs.table.refresh()

Detection of Sorting Change

The b-table component can handle the sort-changed event if we set an event handler for it.

For example, we can write:

<b-table @sort-changed="sortingChanged" ... ></b-table>

Then we can write:

export default {
  methods: {
    sortingChanged(ctx) {
      // ...
    }
  }
}

The ctx parameter is an object with the sortBy with the key that the rows are sorted by.

It also has the sortDesc boolean property which is true if we sort in descending order.

Light Weight Tables

b-table-lite is a light version of the b-table component.

It’s great for creating a simple table.

It doesn’t have most of the features of b-table like filtering, sorting, pagination, and other dynamic features.

Conclusion

We can add filtering to our table with the filter prop.

Also, we can force refresh a table and add provider functions to load data instead of assigning the data directly to it.

Categories
Node.js Tips Uncategorized

Node.js Tips — Express Requests and Response

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

In this article, we’ll look at some solutions to common problems when writing Node apps.

Return JSON Using Node or Express

We can render a JSON response with the http package by setting the Content-Type header and the res.end method.

For instance, we can write:

const http = require('http');

const app = http.createServer((req, res) => {
  res.setHeader('Content-Type', 'application/json');
  res.end(JSON.stringify({
    a: 1
  }));
});

app.listen(3000);

We call createServer to create an HTTP server.

In the callback, we set the Content-Type response header to application/json to set the response data to JSON.

Then we call res.end with the stringified JSON to render the response.

With Express, we just have to write:

res.json({
  foo: "bar"
});

in our middleware.

res.json sets the headers and render the JSON.

Enable HTTPS with Express

We can enable HTTPS with Express by reading the certificate data and use http.createServer to create the server.

For instance, we can write;

const fs = require('fs');
const http = require('http');
const https = require('https');
const privateKey = fs.readFileSync('sslcert/server.key', 'utf8');
const certificate = fs.readFileSync('sslcert/server.crt', 'utf8');
const credentials = {
  key: privateKey,
  cert: certificate
};
const express = require('express');
const app = express();

const httpServer = http.createServer(app);
const httpsServer = https.createServer(credentials, app);
httpServer.listen(3000);
httpsServer.listen(3443);

We read the private key and certificate files from the server.

Then we pass them all in an object and that object is passed to https.createServer to create the server.

Then we call listen on the httpsServer to create the server.

We still have to create the HTTP server to listen to non-secure HTTP requests.

Fix ‘Error: request entity too large’ Error from Express

We can fix the ‘request entity too large’ error by increasing the allowed size of requests.

For instance, we can write:

const bodyParser = require('body-parser');
app.use(bodyParser.json({
  limit: '50mb'
}));
app.use(bodyParser.urlencoded({
  limit: '50mb',
  extended: true
}));

We set limit in the object that we passed in as the argument to set the max size of the request payload.

'50mb' is 50 megabytes.

Download a File from Node Server Using Express

We can send a file download response to the client with res.download .

For instance, we can write:

app.get('/download', (req, res) => {
  const file =  path.join(__dirname, '/upload-folder/movie.mp4');
  res.download(file);
});

The res.download requires the absolute path to the file, so we need to combine __dirname with the rest of the path.

res.download will set the Content-Disposition and other headers automatically and send the file to the client.

Server Static Files with Express

We can serve static files with Express using the express.static middleware.

For instance, we can write:

app.use(express.static(path.join(__dirname, '/public')));

We serve the folder we want to serve as the static folder with the absolute path.

express.static will expose the folder to the client.

Get the JSON POST Data in an Express Application

We can get the JSON data from a POST request by using the req.body property.

For instance, we can write:

const express = require('express');
const bodyParser = require('body-parser');
const app = express.createServer();

app.use(`bodyParser`.`json`());

app.post('/', (req, res) => {
  console.log(req.body);
  response.send(req.body);
});

app.listen(3000);

req.body has the JSON request payload.

The req.body property is available if we ran the bodyParser.json() middleware.

We did that with:

app.use(bodyParser.json());

Remove Documents Using Node.js Mongoose

We can remove a document with Mongoose by using the remove method on the model class.

For example, we can write:

Model.remove({
  _id: id
}, (err) => {
  if (err) {
    console.log(err);
  }
});

Get Uploaded Files with Express

To get uploaded files with Express, we can use the express-fileupload package.

For example, we can write:

const fileupload = require("express-fileupload");
app.use(fileupload());

app.post("/upload", (req, res) => {
  if (!req.files) {
    res.send("File not found");
    return;
  }
  const file = req.files.photo;
  res.send("File Uploaded");
});

We used the fileupload middleware from the express-fileupload package.

To use it, we write:

app.use(fileupload());

The req.files should be available when we upload one or more files.

We can get the files by using the req.files object.

photo is the field name of the file input.

We can replace that with the correct name.

Conclusion

There are a few ways to render JSON response to the client.

We can get file uploads with a middleware package.

Also, we can return a file download response with res.download .

We’ve to use body-parser to parse JSON request payloads.

Categories
Uncategorized Vue 3

Vue 3 — v-model

Vue 3 is in beta and it’s subject to change.

Vue 3 is the up and coming version of Vue front end framework.

It builds on the popularity and ease of use of Vue 2.

In this article, we’ll look at how to use the Vue 3 v-model directive.

Multiline Text

v-model also works with multiline text.

For instance, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <textarea v-model="message" placeholder="message"></textarea>
      <p style="white-space: pre-line;">{{ message }}</p>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            message: ""
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

And when we type in multiple lines of text, it’ll be displayed with the same formatting.

This is because we have the white-space: pre-line; style.

We shouldn’t use interpolation for text areas.

Instead, we always use v-model .

Checkbox

v-model also works with checkboxes.

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <input type="checkbox" v-model="checked" />
      <label for="checkbox">{{ checked }}</label>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            checked: true
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

to bind the checked value of the checkbox to the checked state.

We can also have multiple checkboxes bound to the same array:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <input type="checkbox" value="apple" v-model="checkedFruits" />
      <label>apple</label>
      <input type="checkbox" value="orange" v-model="checkedFruits" />
      <label>orange</label>
      <input type="checkbox" value="grape" v-model="checkedFruits" />
      <label>grape</label>
      <p>{{checkedFruits}}</p>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            checkedFruits: []
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

v-model is smart enough to populate the checkedFruits array with the checked choices.

All we have to do is set the value attribute value and the array variable to bind to v-model and we’re set.

Now when we check or uncheck the checkboxes, the checkedFruits array will change automatically.

Radio

Like checkboxes, Vue 3’s v-model directive can bind to radio button choices.

All we need to have is the value attribute and the v-model directive on each checkbox and Vue will do the selection binding automatically.

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <input type="radio" value="apple" v-model="selected" />
      <label>apple</label>
      <input type="radio" value="orange" v-model="selected" />
      <label>orange</label>
      <input type="radio" value="grape" v-model="selected" />
      <label>grape</label>
      <p>{{selected}}</p>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            selected: ""
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

We pass in the selected property returned from data as the value of the v-model directive.

The value attribute as the value of each radio button.

Now when we click on the radio button, we’ll see the value displayed below it.

We can only click one since they’re all bound to the same variable.

Select

v-model also works with select elements.

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <select v-model="selected">
        <option disabled value="">Please select one</option>
        <option>apple</option>
        <option>orange</option>
        <option>grape</option>
      </select>
      <p>{{ selected }}</p>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            selected: ""
          };
        }
      }).mount("#app");
    </script>
  </body>
</html>

We passed the selected value to the v-model so it’ll be updated if we select a value.

If there’s no value attribute in the option, then the text between the option tags will be used as the value.

Conclusion

v-model lets us bind various form control values to Vue instance states.