2
votes

Imagine to display with jsrender name and surname of a user inside header of a webapp. I pass to template an object that is "User" object. Then in template I display {{name}} and {{surname}}. But how can I check inside template if "User" object is null or undefinied? I can check only if name or surname are null (or empty).

And what is the right way to check for null values? For example an object 'Order' with another nested object 'Shipping' with 'id' and 'name' properties. Shippinig object exist and is not null, but are null its properties.

If I use '{{If shipping.id}}' in template I get always this error: {Error: TypeError: Cannot read property 'id' of null} It seems shipping is null even if it isn't

This should be useful also when returned object is null (for example when a search returns no result), and i want to display a template instead of another

Thanks

1
For the case '{{if shipping.id}}' you should not get the error message "{Error: TypeError: Cannot read property 'id' of null..." unless the shipping object is null or undefined. Did you have a type on "shipping", or similar? - BorisMoore

1 Answers

13
votes

Suppose you have:

var html = myTemplate.render(myOrder);

and your template is:

{{:shipping.id}}

Here are the results with the different versions of myOrder:

  • myOrder = {shipping: {name: "Jo", id: "J1"} }

    -> html: "J1

  • myOrder = {shipping: {name: "Jo"} }

    -> html: ""

  • myOrder = {}

    -> html: "{Error: TypeError: Unable to get property 'id' of undefined or null reference}"

So now, here are several ways to handle that last case - without outputting the error message:

1) Use onerror=... on the {{:}} tag to specify a fallback rendering of the tag in the case of error.

For example if you want to render the empty string when the shipping object is null or undefined, you can use the template:

{{:shipping.id onerror=''}}

Or you could write

{{:shipping.id onerror='no shipping info'}}

2) Test for the shipping object using {{if}} or {{if}} {{else}} {{/if}}

{{if shipping}}{{:shipping.id}}{{else}}no shipping info{{/if}}

3) Use {{for}} or {{for}} {{else}} {{/for}}

{{for shipping}}{{:id}}{{else}}no shipping info{{/for}}

4) Use a null check

{{:shipping && shipping.id}}

5) Use a ternary expression

{{:shipping ? shipping.id : 'no shipping info'}}

So to summarize, here is a template showing all of these alternatives:

Template

<script id="myTmpl" type="text/x-jsrender">
    1 {{:shipping.id onerror='no shipping info'}}<br/>
    2 {{if shipping}}{{:shipping.id}}{{else}}no shipping info{{/if}}<br />
    3 {{for shipping}}{{:id}}{{else}}no shipping info{{/for}}<br />
    4 {{:shipping && shipping.id}}<br />
    5 {{:shipping ? shipping.id : 'no shipping info'}}<br />
</script>

Script

var myOrder = {};
var html = myTemplate.render(myOrder);

Output:

1 no shipping info
2 no shipping info
3 no shipping info
4
5 no shipping info

Finally, if the order itself is null or undefined, or if you pass an array of orders, but some may be undefined, then you can wrap the whole template by an {{if #data}} or equivalently simply {{if}}, which tests for whether the current object, (the contextual data object that you are rendering this template against) is null.

Template

<script id="myTmpl" type="text/x-jsrender">
    {{if}}
        {{:shipping.id onerror='no shipping info'}}<br/>
    {{else}}
        no order<br/>
    {{/if}}
</script>

Script

var myOrders = [
  {shipping: {id: "J1"}},
  ,
  {},
  {shipping: {id: "J2"}},
];

var html = myTemplate.render(myOrders)

Output:

J1
no order
no shipping info
J2