Handlebars error after migration
-
I'm migrating a report from a self-hosted JsReport server (version 2.6.0) to JsReport Studio.
During testing all of my scripts appear to run properly from what I can tell from the profiler:Here are the error details:
name.indexOf is not a function (system-helpers.js line 1570:42) 1568 | 1569 | const jsreport = require('jsreport-proxy') > 1570 | const assetVal = await jsreport.assets.read(path, encoding) | ^ 1571 | return assetVal 1572 | } 1573 | TypeError: name.indexOf is not a function at readAsset (/app/node_modules/@jsreport/jsreport-assets/lib/assetsShared.js:52:34) at Object.read (/app/node_modules/@jsreport/jsreport-assets/lib/worker.js:112:25) at Object.asset (system-helpers.js:1570:42) at Object.<anonymous> (/app/node_modules/@jsreport/jsreport-core/lib/worker/render/executeEngine.js:311:27) at Object.wrapper (/app/node_modules/handlebars/dist/cjs/handlebars/internal/wrapHelper.js:15:19) at Object.main (eval at compile (/app/node_modules/@jsreport/jsreport-handlebars/lib/handlebarsEngine.js:35:30), <anonymous>:231:192) at main (/app/node_modules/handlebars/dist/cjs/handlebars/runtime.js:208:32) at ret (/app/node_modules/handlebars/dist/cjs/handlebars/runtime.js:212:12) at Object.execute (/app/node_modules/@jsreport/jsreport-handlebars/lib/handlebarsEngine.js:80:14) at Object.execute (/app/node_modules/@jsreport/jsreport-handlebars/lib/worker.js:27:43)
I'm not really sure where to begin troubleshooting this given that the error appears to be how JsReport Studio is handling this portion of the code.
I'd be thankful for support or even pointing me in the right direction!
-
what is the invoice-main template code? perhaps the asset call you are making there is passing wrong type of argument (first argument to asset should be string).
-
Thanks for the quick response!
Template code below. It's identical to what is running on the version 2.6.0 server without issue.
I believe the only asset calls that are being made are to a style sheet and an image, but are encoded as such. (Line 3 and 15).
Also note that we also use{{asset}}
to pass a variable from an API call based on an actual physical asset, in case this is now causing some kind of conflict (line 48).<html> <style> {#asset invoice-styles.css @encoding=utf8} </style> <div class="invoice-box-main"> <table cellpadding="0" cellspacing="0"> <tr class="top"> <td colspan="2"> <table> <tr> <td class="title"> <div class="company-logo-wrapper" > <img src='{#asset logo.jpg @encoding=dataURI}'/> </div> </td> <td> Work Order #: {{number}} <br> Created: {{now}} <br> Technician: {{technician}} </td> </tr> </table> </td> </tr> <tr class="information "> <td colspan="2 "> <table class = "addresses"> <tr> <td> Our Company<br> 123 Main Street<br> Springfield, IL 24680 </td> <td> {{buyer.name}}<br> {{buyer.road}}<br> {{buyer.country}} </td> </tr> </table> </td> </tr> </table> <div > <p>Machine: {{asset}}</p> </div> </div> <div class = "invoice-box-container"> <div class="invoice-box"> <table> <tr> <td>Description of Problem</td> </tr> <tr class="para"> <td> {{{problem}}} </td> </tr> </table> </div> </div> <div class = "invoice-box-container"> <div class="invoice-box"> <table> <tr> <td>Work Performed</td> </tr> <tr class="para"> <td> {{{workPerformed}}} </td> </tr> </table> </div> </div> <div class = "invoice-box-container"> <div class="invoice-box"> <table> <tr> <td>General Recommendations</td> </tr> <tr class="para"> <td> {{{generalRecommendations}}} </td> </tr> </table> </div> </div> <div style='page-break-before: always;'></div> <div class = "invoice-box-container"> <div class="invoice-box"> <br /> <table id="recommendedParts"> </table> <br /> <table id="partsUsed"> </table> <br /> <br /> <table id="rmaParts"> </table> <br /> <table> <tr class ="table-header"> <td colspan="7">Travel Hours</td> </tr> <tr class="heading "> <td>Monday</td> <td>Tuesday</td> <td>Wednesday</td> <td>Thursday</td> <td>Friday</td> <td>Saturday</td> <td>Sunday</td> </tr> <tr class="dates"> <td>{{MoDate}}</td> <td>{{TuDate}}</td> <td>{{WeDate}}</td> <td>{{ThDate}}</td> <td>{{FrDate}}</td> <td>{{SaDate}}</td> <td>{{SuDate}}</td> </tr> <tr class="dates"> {{#if MoTravelHrs}} <td>{{MoTravelHrs}}</td> {{else}} <td>0</td> {{/if}} {{#if TuTravelHrs}} <td>{{TuTravelHrs}}</td> {{else}} <td>0</td> {{/if}} {{#if WeTravelHrs}} <td>{{WeTravelHrs}}</td> {{else}} <td>0</td> {{/if}} {{#if ThTravelHrs}} <td>{{ThTravelHrs}}</td> {{else}} <td>0</td> {{/if}} {{#if FrTravelHrs}} <td>{{FrTravelHrs}}</td> {{else}} <td>0</td> {{/if}} {{#if SaTravelHrs}} <td>{{SaTravelHrs}}</td> {{else}} <td>0</td> {{/if}} {{#if SuTravelHrs}} <td>{{SuTravelHrs}}</td> {{else}} <td>0</td> {{/if}} </tr> <tr class="total"> <td colspan=7>Total Travel Hours: {{TotalTravelHrs}}</td> </tr> </table> <br /> <table> <tr class ="table-header"> <td colspan="7">Labor Hours</td> </tr> <tr class="heading "> <td>Monday</td> <td>Tuesday</td> <td>Wednesday</td> <td>Thursday</td> <td>Friday</td> <td>Saturday</td> <td>Sunday</td> </tr> <tr class="dates"> <td>{{MoDate}}</td> <td>{{TuDate}}</td> <td>{{WeDate}}</td> <td>{{ThDate}}</td> <td>{{FrDate}}</td> <td>{{SaDate}}</td> <td>{{SuDate}}</td> </tr> <tr class="dates"> {{#if MoLaborHrs}} <td>{{MoLaborHrs}}</td> {{else}} <td>0</td> {{/if}} {{#if TuLaborHrs}} <td>{{TuLaborHrs}}</td> {{else}} <td>0</td> {{/if}} {{#if WeLaborHrs}} <td>{{WeLaborHrs}}</td> {{else}} <td>0</td> {{/if}} {{#if ThLaborHrs}} <td>{{ThLaborHrs}}</td> {{else}} <td>0</td> {{/if}} {{#if FrLaborHrs}} <td>{{FrLaborHrs}}</td> {{else}} <td>0</td> {{/if}} {{#if SaLaborHrs}} <td>{{SaLaborHrs}}</td> {{else}} <td>0</td> {{/if}} {{#if SuLaborHrs}} <td>{{SuLaborHrs}}</td> {{else}} <td>0</td> {{/if}} </tr> <tr class="total"> <td colspan=7>Total Labor Hours: {{TotalLaborHrs}}</td> </tr> </table> <br /> </div> </div> </div> <div style='page-break-before: always;'></div> <div class="invoice-box"> <br /> <div class="invoice-box"> <table id= "images"> </table> </div> <script> //Create Recommended Parts Table if({{recommendedParts.length}} > 0 ) { var table = document.getElementById("recommendedParts"); var header = table.insertRow(-1); header.className = "table-header"; var headerCell = header.insertCell(-1); headerCell.setAttribute("colspan","3"); headerCell.innerHTML = "Recommended Parts"; var columnTitles = table.insertRow(-1); columnTitles.className = "heading"; var partNumber = columnTitles.insertCell(-1) var description = columnTitles.insertCell(-1) var serialNumber = columnTitles.insertCell(-1) partNumber.innerHTML = "Part Number"; description.innerHTML = "Description"; serialNumber.innerHTML = "Serial Number"; {{#each recommendedParts}} var row = table.insertRow(-1); row.className = "dates"; var partNumberCell = row.insertCell(-1); var descriptionCell = row.insertCell(-1); var serialNumberCell = row.insertCell(-1); partNumberCell.innerHTML = "{{this.partNumber}}"; descriptionCell.innerHTML = "{{this.description}}"; serialNumberCell.innerHTML = "{{this.serialNumber}}"; {{/each}} } </script> <script> //Create Parts Used Table if({{partsUsed.length}} > 0 ) { var table = document.getElementById("partsUsed"); var header = table.insertRow(-1); header.className = "table-header"; var headerCell = header.insertCell(-1); headerCell.setAttribute("colspan","3"); headerCell.innerHTML = "Parts Used During Visit"; var columnTitles = table.insertRow(-1); columnTitles.className = "heading"; var partNumber = columnTitles.insertCell(-1) var description = columnTitles.insertCell(-1) var serialNumber = columnTitles.insertCell(-1) partNumber.innerHTML = "Part Number"; description.innerHTML = "Description"; serialNumber.innerHTML = "Serial Number"; {{#each partsUsed}} var row = table.insertRow(-1); row.className = "dates"; var partNumberCell = row.insertCell(-1); var descriptionCell = row.insertCell(-1); var serialNumberCell = row.insertCell(-1); partNumberCell.innerHTML = "{{this.partNumber}}"; descriptionCell.innerHTML = "{{this.description}}"; serialNumberCell.innerHTML = "{{this.serialNumber}}"; {{/each}} } </script> <script> //Create RMA Parts Table if({{rmaParts.length}} > 0 ) { var table = document.getElementById("rmaParts"); var header = table.insertRow(-1); header.className = "table-header"; var headerCell = header.insertCell(-1); headerCell.setAttribute("colspan","4"); headerCell.innerHTML = "Parts To Be Returned (RMAs)"; var columnTitles = table.insertRow(-1); columnTitles.className = "heading"; var partNumber = columnTitles.insertCell(-1) var description = columnTitles.insertCell(-1) var serialNumber = columnTitles.insertCell(-1) var rmaNumber = columnTitles.insertCell(-1) partNumber.innerHTML = "Part Number"; description.innerHTML = "Description"; serialNumber.innerHTML = "Serial Number"; rmaNumber.innerHTML = "RMA Number"; {{#each rmaParts}} var row = table.insertRow(-1); row.className = "dates"; var partNumberCell = row.insertCell(-1); var descriptionCell = row.insertCell(-1); var serialNumberCell = row.insertCell(-1); var rmaNumberCell = row.insertCell(-1); partNumberCell.innerHTML = "{{this.partNumber}}"; descriptionCell.innerHTML = "{{this.description}}"; serialNumberCell.innerHTML = "{{this.serialNumber}}"; rmaNumberCell.innerHTML = "{{this.rmaNumber}}"; {{/each}} } </script> <script> //Create Images Table var createNewRow = true; var firstImage = true {{#each images}} var i = {{2}} if(createNewRow){ var table = document.getElementById("images"); var row = table.insertRow(-1); var cell1 = row.insertCell(-1); cell1.innerHTML = "<img src= '{{this}}' /> <p>{{2}}</p> "; if(firstImage){ createNewRow = false; firstImage = false } else if(i % 2 == 0){ createNewRow = false; } else{ createNewRow = true; } } else{ var rowIndex = Math.ceil(i / 2) - 1; var newCell = document.getElementById("images").rows[rowIndex].insertCell(-1); newCell.innerHTML = "<img src='{{this}}' /><p>{{2}}</p>"; createNewRow = true; } {{/each}} var dataEl = document.getElementById('data-serialized'); var mainData = JSON.parse(dataEl.innerText); document.getElementById("content").innerText = mainData.MoDate </script> </html>
-
hmm i see, since jsreport v3 asset is now a handlebars helper too, so when handlebars see this it thinks your are trying to call the helper, when handlebars find that both data and helper have the same name (
asset
in this case) it gives more priority to the helper.there is easy fix for this, just change your template from
{{asset}}
to{{./asset}}
this will disambiguate the case and will let handlebars know that you want the data.
-
Yep. That was it. Many thanks!