Skip to content
This repository

No value rendered for zero (0) numbers #31

Closed
skenny opened this Issue December 01, 2011 · 20 comments

6 participants

Boris Moore Dave Parsons Rupert Key josher19 Adam Patridge

JSON number values that are 0 are not rendered. For example:

input:
{"quantity":0}

template:
Quantity: {{=quantity}}

output:
Quantity:

Boris Moore
Owner

Yes, thanks, I was aware of this issue, and will fix it soon...

Deleted user

The content you are editing has changed. Reload the page and try again.

I have same problem any luck with this issue?
Right now I can only use the code like: {{=$itemNumber-1 undef 0}}

Sending Request…

Attach images by dragging & dropping or selecting them. Octocat-spinner-32 Uploading your images… Unfortunately, we don't support that file type. Try again with a PNG, GIF, or JPG. Yowza, that's a big file. Try again with an image file smaller than 10MB. This browser doesn't support image attachments. We recommend updating to the latest Internet Explorer, Google Chrome, or Firefox. Something went really wrong, and we can't process that image. Try again.

Boris Moore
Owner

I'm planning to include a fix for this, but it may have to wait until some bigger changes that are in the pipeline, since it relates to other issues like #7 - and to make both that issue and this one satisfied has to be compatible with maintaining current perf optimization. If you have a workaround, then best to stay with that in the meantime...

Dave Parsons

+1, but workaround does work

Rupert Key

+1 but couldn't get workaround to work with an encoder (new workaround using a function below).

Pre-workaround, I started with {{=shopping.change.amount!currency}} where "currency" is a custom formatter (encoder) registered with...

  $.views.encoders["currency"] = function currency(number) {
    //alert("typeof "+ number +": "+ typeof number);
    try {
      return number.toFixed(2);
    } catch(e) {
      // supplied something other than a number
      return number +"(NaN)";
    }
  }

... so my unformatted workaround became {{=shopping.change.amount undef 0}} which works but has no formatting.
I then tried adding the encoder as {{=shopping.change.amount undef 0!currency}} but it gave same results as no workaround (value if non-zero; else blank).

I then went and read the source but can't adequately-grok-in-sensible-time how to use a formatter with the workaround (thattmpl + compile code is kind'a heavy! :-O ). Guessing didn't work either ;-)

In case it's relevant, I'm using this with JQuery loaded.

Alternative workaround (that allows formatting)

Instead, I switched to using a function...

  $.views.registerHelpers({
    currency: function(number) {
      // alert("typeof "+ number +": "+ typeof number);
      try {
        return number.toFixed(2);
      } catch(e) {
        // supplied something other than a number
        return number +"(NaN)";
      }
    }
  });

... and my template obviously now has {{=$ctx.currency(shopping.change.amount)}}.
Zero and all other values render correctly. HTH other zero formatters!

josher19

Doing
$.template("Quantity: {{=quantity}}")
generates ... result = "" + "Quantity: " + html($data.quantity || "");
where it should be ... result = "" + "Quantity: " + html($data.quantity);
and $.views.encoders.html should become:

function (text) { 
   if (null == text) return ""; // skip null and undefined elements.
   return String(text).replace(htmlSpecialChar, replacerForHtml); 
}

PS:
(null == text) is true for undefined and null elements, but false for 0 and false,
whereas (text || "") will evaluate to "" for null, undefined, false, and 0.

Another inline optimization possibility is (null == text ? "" : text) instead of (text || "")
which should have good performance and certainly shorter than
("undefined" === typeof text || null === text ? "" : text).

josher19

Looks like this problem comes from the paramsOrEmptyString optimization.

I have branch (https://github.com/josher19/jsviews/blob/master/jsrender.js) with a commit (josher19/jsviews@338755b) which gets rid of the optimization and puts a similar one in the html encoder. HTML encoded text using {{= item }} will return blank ('') for undefined or null values but not for 0 or false, but using the ! will show 'undefined' and 'null' values:
{{= item !}}

Example usage:


$.template("HTML", "
Qty: {{=Qty}}, null:{{=nil}}, notset:{{=blank}}, bool:{{=bool}}
")(falsy={"Qty":0,"nil":null,"bool":false}) // Expected output:
Qty: 0, null:, notset:, bool:false
// Old output:
Qty:, null:, undefined:, bool:
$.template("NONE", "
Qty: {{=Qty!}}, null:{{=nil!}}, notset:{{=blank!}}, bool:{{=bool!}}
")(falsy={"Qty":0,"nil":null,"bool":false}) // Expected output:
Qty: 0, null:null, notset:undefined, bool:false
// Old output:
Qty:, null:, notset:, bool:
Adam Patridge

Seeing this open for a year doesn't give me hope I could offer a fix myself, so I hate to simply post a breaking example in both the current jsrender and @josher19's version. I'm still going to take a look at the jsrender source when I get the chance, but there is definitely still an issue when $data is 0. Here's the gist of the example:

<ul id="results"></ul>
<script id="x" type="text/x-jquery-tmpl">
    <li>{{=$data!}}</li>
</script>
<script type='text/javascript'>
    $("#results").html($("#x").render([0, 1, 0, 2, 0]));
</script>

Results in: "<ul id="results"><li>1</li><li>2</li></ul>"

It doesn't even appear to attempt to step into the template to render the zero-value elements of that array. This seems to make workarounds like the custom tag, custom encoder, and helper function ideas fail too.

Boris Moore
Owner

! do have a fix for this already, but it is part of a major update which I have not committed because it involves some breaking changes. I don't want to do breaking changes piecemeal - but rather in one significant upgrade which will require some porting to the new syntax. After that I hope to keep things pretty stable. The JsRender update is ready, but it also ripples to some changes in JsViews, and I am working hard now to integrate JsViews changess with this update too.

So apologies that this is taking some time, but I think/hope the update will be worth the wait! It should be committed in a couple weeks time... I am targetting Beta for JsRender end of February...

josher19

@patridge : fixed in my fork of the code so now your results render correctly with 0's included in the output.

Technical details: changed render to do

content = null != dataItem ? tmpl( dataItem, new View( context, path, arrayView, dataItem, tmpl, this )) : "";

instead of

content = dataItem ? tmpl( dataItem, new View( context, path, arrayView, dataItem, tmpl, this )) : "";

so now it will render the template for each line unless that line is null or undefined
(before it would skip rendering if the dataItem was falsy, meaning 0, false, "", null, or undefined).

Thanks for posting the example. It indirectly makes a strong argument for TDD.

@BorisMoore: feel free to pull these small changes and merge them with your changes to see if it fixes or breaks anything. Also let me know if you would like help setting up a test suite for new JsRender beta.

PS: Now 0 and false will show up whether or not you use ! when rendering:

$.template('qq', 'Quantity: {{=quantity!}}, Boolean: {{=bool!}}')({quantity:0, bool:false})
// "Quantity: 0, Boolean: false"

$.template('qq', 'Quantity: {{=quantity}}, Boolean: {{=bool}}')({quantity:0, bool:false})
// "Quantity: 0, Boolean: false"
josher19

I forked your " breaking example" JsFiddle and added a couple more tests.

Red (failing):
http://jsfiddle.net/yUfyH/1/

Green (passing):
http://jsfiddle.net/mW7Fs/

josher19

Hi Boris,

Updated the original example to use your new code:

<ul id="results"></ul>
<script id="x" type="text/x-jquery-tmpl">
    <li>{{: #data }}</li>
</script>
/*global $ */
$(function() {
    "use strict";
    $("#results").html($("#x").render([-1, 0, 1, 2, 3, 4,
                                  '-- booleans --',
                                  false, true,
                                  '-- null & undefined --',
                                  null, undefined,
                                  '-- strings --',
                                  "", "string"]));
});

Now get '[object Object]' for the "falsy" values of 0, "", null, undefined, and false.

http://jsfiddle.net/Vaxd6/1/

Cheers,
->> Josh <<-

Boris Moore
Owner

Ah, I see. Yes that is a slightly different case than the one I was looking at. I was thinking of the case where you have a data object with a property whose value is 0, or undefined. (e.g. { quantity: 0 } as above) - but this additional scenario is valid too. I have a fix for it, which I'll upload soon...

Boris Moore
Owner

Fixed in 5d284cb.
Closing, but please reopen if the fix does not work for you... Thanks...

Boris Moore BorisMoore closed this March 10, 2012
josher19

Yes, that seems to work pretty well:

Now undefined is replaced with "" (a blank string) and null is replaced with the String "null", while 0 and false remain unchanged.

http://jsfiddle.net/Vaxd6/2/

Boris Moore
Owner

Yes, that's the intention. Actually, undefined, 0, null, true and false are rendered by the strings "", "0", "null", "true", "false". Would you expect anything different from this design?

JsRender always renders a string, of course. The return value from render() can never be other than a string.

josher19

No, I think "" for undefined and "null" for null works well -- issue closed!

You might include in the documentation how to change that back to the old way (delete "falsy" values) or how to change "null" to "" using a helper function.

Boris Moore
Owner

There has been a new issue submitted suggesting null should render as "".
#87
I think it does make more sense. Any disagreement?

josher19

I agree. Might include in the docs how to customize what is displayed using helper functions, because displaying "null" can be useful for debugging, but not so useful for displaying in final HTML produced by render.

Adam Patridge

This definitely fixed that sample jsFiddle (once I updated the syntax: original). I would think an empty string for null/undefined ought to be just fine. I have only had one use-case where I wanted to display "null" for null values and that was an oddball usage. I put together the start of a simple demo using a helper function to display such values for anyone else that runs into a need to do so; it's not elegant, but it should be easily tweaked for someone's debugging needs.

ashok ashok-conflux referenced this issue in openMF/mifosx-community-apps February 10, 2013
Merged

MIFOSX-36- Add/Edit Code value UI changes #71

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.