Search code examples
javascriptecmascript-6string-interpolationtemplate-strings

String to template string for array of object mapping


somewhere from the API data I am getting normal string like, “Hi ${person[0].name}” now this string I am converting into template string and getting replace its variables from array of object.

Here is snippet which I am trying to execute, and I am not getting expected output

const getObjPath = (path, obj, fallback = `$\{${path}}`) => {
    if (path && obj) return path.split('.').reduce((res, key) => res[key] || fallback, obj);
    return path;
};
const interpolate = (template, variables, fallback) => {
    const regex = /\${[^{]+}/g;
    if (template && variables) {
        return template.replace(regex, (match) => {
            let path = match.slice(2, -1).trim();
            path = path.split('|').map((item) => item.trim());
            const fieldValue = getObjPath(path[0], variables, fallback);
            if (fieldValue) return fieldValue;
            return path[1] || fallback;
        });
    }
    return template;
};

const data = { person: [{ name: 'John', age: 18 }] };
const a = interpolate('Hi ${person?.[0]?.name | text} (${person?.[0]?.age | text})', data);
console.log(a);

output: "Hi ${person?.[0]?.name} (${person?.[0]?.age})"

expected output: "Hi John 18"

Can someone tell me what I am doing wrong here?


Solution

  • The problem is that your path splitting in getObjPath does not deal with square brackets in the path.

    So replace this

    path.split('.')
    

    with:

    path.match(/[^.[\]]+/g)
    

    const getObjPath = (path, obj, fallback = `$\{${path}}`) => {
        if (path && obj) return path.match(/[^.[\]]+/g).reduce((res, key) => res[key] || fallback, obj);
        return path;
    };
    const interpolate = (template, variables, fallback) => {
        const regex = /\${[^{]+}/g;
        if (template && variables) {
            return template.replace(regex, (match) => {
                let path = match.slice(2, -1).trim();
                path = path.split('|').map((item) => item.trim());
                const fieldValue = getObjPath(path[0], variables, fallback);
                if (fieldValue) return fieldValue;
                return path[1] || fallback;
            });
        }
        return template;
    };
    
    const data = { person: [{ name: 'John', age: 18 }] };
    const a = interpolate('Hi ${person[0].name | text} (${person[0].age | text})', data);
    console.log(a);