1

I am trying to use template/string literals for templates, I've been watching several videos about the subject and been following this great tutorial.

I thought it would be quite cool with reusable chunks because some of the elements occur several times.

Template function

function templater(strings, ...keys) {

    return function(data) {
        let temp = strings.slice();
        keys.forEach((key, i) => {
            temp[i] = temp[i] + data[key];
        });
        return temp.join('');
    }
};

Example chunks

let contentHead = `
    <header>
        ${'myHeader'}
    </header>
`

let contentFooter = `
    <footer>
        ${'myFooter'}
    </footer>
`

The template which is being packed with all the necessary chucks

let contentTemplate = templater`
    <div>
        ${'contentHead'}
        ${'contentFooter'}
    </div>
    `

This is where I set the data for the template

const content = {
    myHeader: 'This is my header',
    myFooter: 'This is my footer',
    contentHead: contentHead,
    contentFooter: contentFooter,
}

This is how I test the code

const myTemplate = contentTemplate(content);
console.log(myTemplate);

The output will be

<div>
   <header>
       myHeader
   </header>
   <footer>
       myFooter
   </footer>
</div>

If i do it without calling the variables like this

let contentTemplate = templater`
    <div>
         <header>
             ${'myHeader'}
         </header>
         <footer>
             ${'myFooter'}
        </footer>
    </div>


const content = {
    myHeader: 'This is my header',
    myFooter: 'This is my footer'
}

The output will be correct

<div>
   <header>
       This is my header
   </header>
   <footer>
       This is my footer
   </footer>
</div>

So why does this not work, I call in two string literal variables in the JSON Object which is then used in the templater function, does it not work because the two chunks are passed in outside the tagged template function and then switched into the template without its own content being done anything with?

How can I fix this the best possible way? :)

2
  • 1
    Template literals are evaluated in the scope in which they are defined, not where you assign them or use them. You can't use them the way you were trying to. You can investigate tagged template literals and see if they might help you. Commented Sep 26, 2019 at 18:12
  • You could also put the template in a function that returns a string, make the tags in the template literal refer to function parameters and then call the function, passing the arguments you want to be inserted into the template literal string and then use the returned string. This would allow you to share the template literal definition while filling it with different values upon demand. Commented Sep 26, 2019 at 18:18

1 Answer 1

1

Your example chunks don't use the templater, they are normal template strings and immediately interpolated. contentHead and contentFooter are just two strings, they get inserted exactly like myHeader and myFooter get inserted by your function in your working example.

Instead, use the templater on the chunks as well, and have it recursively pass the data to chunk functions:

function templater(parts) {
    return (data) => {
        let res = parts[0];
        for (let i=1; i<parts.length; i++) {
            const val = arguments[i];
            if (typeof val == "function") {
                res += val(data);
            } else {
               res += data[val];
            }
            res += parts[i];
        }
        return res;
    }
};

You would use it like this:

const contentHead = templater`
    <header>
        ${'myHeader'}
    </header>
`;
const contentFooter = templater`
    <footer>
        ${'myFooter'}
    </footer>
`;
const contentTemplate = templater`
    <div>
        ${contentHead}
        ${contentFooter}
    </div>
`;

console.log(contentTemplate({
    myHeader: 'This is my header',
    myFooter: 'This is my footer',
}));

If you want to reference chunks by their name in data, not directly through a variable reference during the contentTemplate construction, you can also check whether data[key] is a function.

Sign up to request clarification or add additional context in comments.

3 Comments

Hi Bergi, sorry for the late check but I did not have time before now, I get undefined in the console from your sample, I also see that you use some jQuery functionality which I do not use, I cannot, however, make it work with that either: jsfiddle.net/vkx18whe
@iiiml0sto1 Oops, I can't use arguments in the returned function closure to refer to the arguments of the outer function. Either use arrow notation for the closure, or rest parameters to declare the arguments.
lol that worked right away :) went with the arrow function, thank you once again :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.