How to pass Express response object to frontend JS

2020-07-28 11:14发布

问题:

My controller is sending lat/lng data to my Handlebars view via res.render.

res.render('coords', viewModel);

'viewModel' contains an array of objects, with each object containing a name of a location, lat, and lng. I want to take this information and plot markers on a Google map in my view. When I attempt to inject the data by way of Handlebars into an inline JS variable...

<script>
var viewMarkers = {{viewModel}};
console.log(viewMarkers);
</script>

I get this in my console...

<script>
var viewMarkers = [object Object],[object Object];
console.log(viewMarkers);
</script>

I'm only a beginner in the Node/Express realm and can't seem to comprehend how I can pass the viewModel data to the Google maps JS on the frontend. My thought is that I would need to do an AJAX request to access the data. Regardless, I've scoured the Internet, but have not come across an example of this yet and could use some community guidance.

I appreciate any knowledge/assistance.

回答1:

You must keep in mind that Handlebars' job is to return Strings. The mustache tags, {{}}, evaluate Object references as Strings so that the resultant text can be appended to the DOM or HTTP response body. The JavaScript inside your <script> tags does not get executed until it arrives on the client. There is no way for Handlebars to return an Object reference that could survive server-side rendering and eventually get assigned to a variable on the client.

[object Object],[object Object] is the result when an Array of two Objects is stringified (ie., it is the output of calling console.log(String([{}, {}])); in your browser's console.

In order to deliver JavaScript code to the client, you must construct your template to return a String with valid JavaScript in much the same way as a typical template returns valid HTML.

The long way of doing this would be something like the following:

<script>
    var viewMarkers = [
        {{#each viewModel}}
            {
                location: '{{location}}',
                lat: {{lat}},
                lng: {{lng}}
            }
            {{#unless @last}},{{/unless}}
        {{/each}}
    ];
</script>

The simpler way of achieving this would be to have JSON.stringify do the work of stringifying your Array:

res.render('coords', { viewModel: JSON.stringify(viewModel) });

Then to render the JavaScript you would need only do the following in your template:

var viewMarkers = {{{viewModel2}}};

Note that we must use triple mustaches in order not to have our quotes HTML-escaped by Handlerbars.

I have created a fiddle for your reference.