JS helper functions
A collection of some helpful JS helper functions.
1. Sorts an array of objects based on a specified key, order (ascending or descending), and case sensitivity
typescriptconst sort = (
array: Array<any>,
key: string,
order: string = "asc",
ignoreCase: boolean = true,
) => {
return key && array && Array.isArray(array)
? array.sort((a: any, b: any) => {
let aValue = a[key];
let bValue = b[key];
if (
ignoreCase &&
typeof aValue === "string" &&
typeof bValue === "string"
) {
aValue = aValue.toLowerCase();
bValue = bValue.toLowerCase();
}
if (aValue > bValue) {
return order === "asc" ? 1 : -1;
}
if (aValue < bValue) {
return order === "asc" ? -1 : 1;
}
return 0;
})
: array;
};2. Formats an address string by capitalizing the first letter of each word, except for certain lowercase words (e.g. "og", "i", "på") and house numbers (e.g. "14E", "43A", "12-14B")
typescriptconst formatAddress = (address: string) => {
const lowercaseWords = [
// Norwegian
"og",
"i",
"på",
"av",
"gate",
"veien",
"vei",
"gata",
"veg",
"industrivei",
"industriveg",
"allé",
// Swedish
"och",
"i",
"på",
"av",
"gatan",
"vägen",
"väg",
// Danish
"og",
"i",
"på",
"af",
"gade",
"vej",
// Finnish
"ja",
];
return address
.toLocaleLowerCase("sv-SE")
.split(/\s+/)
.map((word, index) => {
// House numbers like 14E, 43A, 12-14B
if (/\d/.test(word)) {
return word.toUpperCase();
}
// Keep words from lowercaseWords list in lowercase, except if it's the first word in the address
if (index !== 0 && lowercaseWords.includes(word)) {
return word;
}
// Capitalize the first letter of each word
return word
.split("-")
.map(
(part) => part.charAt(0).toLocaleUpperCase("sv-SE") + part.slice(1),
)
.join("-");
})
.join(" ")
.trim();
};3. Truncates a string to a specified length and adds "..." at the end if it exceeds that length
typescriptconst truncateString = (str: string, num: number) => {
if (str) {
if (str.length <= num) {
return str;
}
return str.slice(0, num) + "\u2026";
}
return "";
};4. Formats a date string to "YYYY-MM-DD" format, e.g. "2024-06-01T12:00:00Z" becomes "01.06.2024" or "01.06.2024 12:00"
typescriptconst formatDate = (date: string, withTime: boolean = false) => {
let newDate = new Date(date);
let dateString = newDate.toLocaleDateString("nb-NO", {
day: "2-digit",
month: "2-digit",
year: "numeric",
});
if (withTime) {
let timeString = newDate.toLocaleTimeString("nb-NO", {
hour: "2-digit",
minute: "2-digit",
});
return `${dateString} ${timeString}`;
}
return dateString;
};5. Formats a date string to "YYYY-MM-DD HH:mm:ss" format, e.g. "2024-06-01T12:00:00Z" becomes "2024-06-01 12:00:00"
typescriptconst dateAndTimeWithoutTimeZone = (dateAndTime: string) => {
let date = new Date(dateAndTime);
return date
.toISOString()
.replace("T", " ")
.replace(/\.\d{3}Z$/, "");
};6. Formats a number with spaces as thousand separators, e.g. 1000000 becomes "1 000 000"
typescriptconst numberWithSpaces = (value: number) => {
return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ");
};7. Validates an object by checking for missing or empty values, and optionally validating email formats. It can also ignore specified keys and print logs of the validation process.
javascriptconst validateObject = (
obj: Record<string, any>,
options: {
path?: string,
ignoreKeys?: string[],
printLogs?: boolean,
setErrors?: React.Dispatch<React.SetStateAction<string[]>>,
collectedErrors?: string[]
} = {}
) => {
const { path = '', ignoreKeys = [], printLogs = false, setErrors, collectedErrors = [] } = options;
const validateEmail = (val:string) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(val)
}
for (const key in obj) {
const value = obj[key]
const currentPath = path ? `${path}.${key}` : key
if (typeof value === 'object' && value !== null) {
validateObject(value, { path: currentPath, ignoreKeys, printLogs, setErrors, collectedErrors })
} else {
if (printLogs) {
console.log(`👀 Validating ${currentPath}: ${value}`)
}
const isEmptyString = typeof value === 'string' && value.trim() === ''
const isMissing = value === undefined || value === null || isEmptyString
if (isMissing && !ignoreKeys.includes(currentPath)) {
if (printLogs) {
console.error(`❌ Validation failed for: ${currentPath}: value is required`)
}
collectedErrors.push(currentPath)
} else if (key.toLowerCase().endsWith('email') && !validateEmail(value) && !ignoreKeys.includes(currentPath)) {
if (printLogs) {
console.error(`❌ Validation failed for: ${currentPath}: invalid email format`)
}
collectedErrors.push(currentPath)
}
}
}
setErrors && setErrors(collectedErrors)
if (collectedErrors.length > 0) return false
if (printLogs) {
console.log('✅ Validation passed: ', collectedErrors.length === 0)
}
return collectedErrors.length === 0
}