DataLens

Template literals and string handling

Build strings with template literals, clean and inspect text with trim, case, includes, startsWith, slice, split, join, replaceAll and padStart, and format numbers for Indonesian users.

Level: Intermediate · 8 min read

Practise this module

The questions for this lesson run in your browser and check your answer straight away.

The idea

So much of a web app is text: product names, prices with thousands separators, messages built from data, search terms typed with stray spaces and capital letters. JavaScript strings come with a toolbox of methods for exactly these jobs, and template literals make building text from data readable.

Template literals

The cart page needs a line like "Total for 2 × Arabica Gayo: Rp 190.000", built from a quantity, a name and a calculated total. The old way glues it together with +, which gets messy fast. Compare it with a template literal, which lets you write the sentence and drop the values straight into it:

const name = "Arabica Gayo";
const price = 95000;
const qty = 2;

console.log("Total for " + qty + " × " + name + ": Rp " + (price * qty).toLocaleString("id-ID"));
console.log(`Total for ${qty} × ${name}: Rp ${(price * qty).toLocaleString("id-ID")}`);
console.log(`${qty > 1 ? "items" : "item"} in your cart`);
Total for 2 × Arabica Gayo: Rp 190.000
Total for 2 × Arabica Gayo: Rp 190.000
items in your cart

Same output, but the template literal reads like the sentence it produces. Use them whenever you combine text with values. (When inserting user data into HTML, remember module 5: build elements with textContent instead.)

Cleaning and comparing

When someone types " Arabica GAYO " into the search box, they mean the same thing as "arabica gayo". But to JavaScript those are completely different strings, and a search that compares them directly finds nothing. Cleaning the input before you compare fixes most of these problems:

const typed = "   Arabica GAYO  ";
console.log(`[${typed.trim()}]`);
console.log(typed.trim().toLowerCase());
console.log(typed.toLowerCase().includes("gayo"));
console.log("NG-0018".startsWith("NG-"), "photo.JPG".toLowerCase().endsWith(".jpg"));
console.log("kopi" === "Kopi", "kopi" === "Kopi".toLowerCase());
[Arabica GAYO]
arabica gayo
true
true true
false true

Strings are compared exactly, character by character, so normalise user input first: trim() removes surrounding spaces, toLowerCase() makes comparisons case-insensitive. These two calls prevent most "the search finds nothing" bugs.

Strings are immutable: every method returns a new string and leaves the original unchanged. typed.trim() doesn't change typed; you have to use or store the result.

Taking strings apart

A product code like NG-0018-BLK packs several facts into one string: the brand, the number and the colour. And a tag list typed by a person, like "arabica, aceh , single origin", needs to become separate tags. These methods cut strings into pieces and join pieces back together:

const sku = "NG-0018-BLK";
console.log(sku.length, sku[0], sku.at(-1));
console.log(sku.slice(3, 7), sku.slice(-3));
console.log(sku.indexOf("-"), sku.split("-"));

const tags = "arabica, aceh , single origin";
console.log(tags.split(",").map((t) => t.trim()));
console.log(["Gayo", "Toraja", "Kintamani"].join(" · "));
11 N K
0018 BLK
2 ["NG", "0018", "BLK"]
["arabica", "aceh", "single origin"]
Gayo · Toraja · Kintamani

Replacing and padding

Prices often arrive as text like "Rp 1.250.000", which you can't do maths with until the "Rp" and the dots are gone. And order numbers often need a fixed width, like 0007 instead of 7. These methods handle both jobs:

console.log("Rp 1.250.000".replaceAll(".", "").replace("Rp ", ""));
console.log(Number("Rp 1.250.000".replace(/[^\d]/g, "")));
console.log(String(7).padStart(4, "0"), "Total".padEnd(10, ".") + "Rp 95.000");
console.log("ha".repeat(3));
1250000
1250000
0007 Total.....Rp 95.000
hahaha

Formatting numbers for people

The opposite problem: you have a number like 1250000.5 and need to show it to an Indonesian customer as "1.250.000,5" or "Rp 95.000". JavaScript has built-in formatting that knows each country's conventions, so you don't have to add the dots yourself:

const amount = 1250000.5;
console.log(amount.toLocaleString("id-ID"));
console.log(amount.toLocaleString("en-US"));
console.log(Math.round(amount).toLocaleString("id-ID"));
console.log((0.1234).toFixed(2), (12.5).toFixed(0));

const rupiah = new Intl.NumberFormat("id-ID", { style: "currency", currency: "IDR", maximumFractionDigits: 0 });
console.log(rupiah.format(95000).replace(/\s/, " "));
1.250.000,5
1,250,000.5
1.250.001
0.12 13
Rp 95.000
Key idea

Build text with template literals ( `${value}` ); normalise input with trim() and toLowerCase() before comparing; use includes, startsWith, slice, split/join and replaceAll to inspect and reshape; format numbers with toLocaleString("id-ID") or Intl.NumberFormat.

Why this matters for clean code

Put formatting in one place: a formatRupiah(amount) helper used everywhere, rather than "Rp " + x.toLocaleString(...) scattered across the codebase. When the format changes (adding decimals, a different locale for an English page), you change one function. The same goes for normalising search terms: one normalise(text) function, used by every comparison.

Recap

Practise this module

The questions for this lesson run in your browser and check your answer straight away.

Next: Array methods (map, filter, reduce, forEach) →