I have a NodeJS/Express app that is using Handlebars for templates.
All of the templates and partials load fine except where I am returning data from an Express API.
The data is returned and I can see it in the Chrome debugger.
In this template, I am defining the HTML in a script and compiling it in JS.
Here is the template HTML:
<script id="search-result-template" type="text/x-handlebars">
<div>String</div>
{{#each patient}}
<div>
{{cp_first_name}}
</div>
{{!-- {{> searchresultpartial}} --}}
{{/each}}
</script>
The actual page is quite a bit more structured but I've narrowed it down to this for debugging.
Here is the code that compiles the template:
let patientSearchButton = document.getElementById('patient-search-execute');
patientSearchButton.addEventListener("click", async function (e) {
e.preventDefault();
let patientSearchFirstname = document.getElementById('patient-search-firstname')
let cp_first_name = patientSearchFirstname.value;
let url = baseURL + 'patientsearchquery/' + cp_first_name;
const response = await fetch(url, {
method: 'get',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
}
});
var data = response.json();
let patientList = await data;
patient = patientList;
if (response.status === 200) {
let patientSearchResultTemplate = document.querySelector("#search-result-template").innerHTML;
let patientSearchResultTemplateFunction = Handlebars.compile(patientSearchResultTemplate);
let patientSearchResultTemplateObject = patientSearchResultTemplateFunction(patient);
let contentPartial = document.getElementById('patient-search-table');
contentPartial.innerHTML = patientSearchResultTemplateObject;
if (Handlebars.Utils.isArray(patient)) {
console.log("Array");
} else {
console.log("Not");
}
console.log(patient);
} else {
alert("HTTP-Error: " + response.status);
}
});
I can see the data from the API and I'm verifying that Handlebars sees it as an Array.
It seems to break when it enters the #each helper.
I've tried to shift the context with ../ and I've tried every variation I can think of the coax the data into the template.
I was concerned that being in an event handler tied to a button click, that the "this" context was breaking. I moved the code outside of the event handler and "this" seemed to be correct in Chrome but the behavior did not change.
Here is the array data in Chrome:
When paused on a breakpoint in Chrome, I can see that the patient data is present when being passed to the template.
I know it's something dumb but my head hurts from banging it against the wall.
This has happened on two different templates. Granted, they were similar, but I've tried numerous variations and it still isn't loading.
Thanks for any help you might offer.
Does anybody see anything obvious?
Addendum:
I changed the code to pass the property and I can see it in Chrome now.
It still doesn't show up in Handlebars.
this.patients shows the data in the console. Why won't it render the variable?
The {{#each patient}}
in your template anticipates that the data that you pass to your template function has a property named patient
and that the value of this property is iterable - like an Array.
However, it appears that you are simply passing an Array directly to your template function, and that Array does not have a patient
property, and so the #each
loop never executes.
One way to make this work would be to pass an Object to your template function and to assign to that Object a key, patient
, with its value being your Array of patients.
This would require changing:
let patientSearchResultTemplateObject = patientSearchResultTemplateFunction(patient);
to:
let patientSearchResultTemplateObject = patientSearchResultTemplateFunction({ patient: patient });
Or use the shorthand:
let patientSearchResultTemplateObject = patientSearchResultTemplateFunction({ patient });
Note: As patient
is an Array of Patient Objects, if I were on your team, I would urge you to add an "s" to its name to make it plural.