Any values of 0 or 1 from REST API, when type-casted to boolean returns true.

I came across a strange issue with boolean operation in my web application. I have a service that responds with 1 and 0 for true and false. The REST API (internal one) that I call, sends only this output:

GET /stuff/id/5
0

GET /stuff/id/7
1

Based on the above output from the server, I use a toggle switch in the front end to check make it switch on or off. The code that makes it is:

$(this).find(".toggle").toggles({
  "on": requestContent
});

I do understand that sometimes, 1 and 0 might not be interpreted as boolean true or false, so I planned to use !! to force them to get converted into true and false.

$(this).find(".toggle").toggles({
  "on": !!requestContent
});

But still, to my dismay, it shows all the switches in the ON position, than the right way. Somehow it is getting converted to only true for both the values of 1 and 0.

I have even tried to make a mock version of the server call and my front end here, which exactly replicates the issue:

<script>
$(function () {
  // Mimicing the HTTP Response.
  var states = ["1", "0", "0", "1", "1"];
  // This loop loops through all the values and sets the state of the switch.
  $('.toggle').each(function (i) {
    $(this).toggles({
      "on": !!states[i]
    });
  });
});
</script>

<style type="text/css">
body {background-color: #f5f5f5;}
ul, li {margin: 0; padding: 0; list-style: none;}
ul {width: 150px; margin: auto; background-color: #fff; padding: 10px; border-radius: 3px; border: 1px solid #eee;}
ul li {padding: 10px;}
ul li span,
ul li .toggle {width: 50px; display: inline-block; vertical-align: middle;}
ul li span {width: 75px; line-height: 1;}
</style>

<link rel="stylesheet" href="https://cdn.rawgit.com/simontabor/jquery-toggles/master/css/toggles-full.css" />
<script src="https://code.jquery.com/jquery-2.2.4.js"></script>
<script src="https://cdn.rawgit.com/simontabor/jquery-toggles/master/toggles.min.js"></script>
<ul>
  <li>
    <span>Item 1</span>
    <div class="toggle toggle-light"></div>
  </li>
  <li>
    <span>Item 2</span>
    <div class="toggle toggle-light"></div>
  </li>
  <li>
    <span>Item 3</span>
    <div class="toggle toggle-light"></div>
  </li>
  <li>
    <span>Item 4</span>
    <div class="toggle toggle-light"></div>
  </li>
  <li>
    <span>Item 5</span>
    <div class="toggle toggle-light"></div>
  </li>
</ul>

As you can see, all the happens is even !!0 returns true. How do I solve this? What's the mystery behind this?

Solution

The main reason to above problem is, the way of type-casting is totally wrong. I found out after an hour of debugging that, the issue was with the way, JavaScript treats the strings as truthy values.

When the server responds, the response is always given as string type. When the string with a 0, which is actually "0" needs to be type-casted into boolean false. Instead, JavaScript takes it as a non-empty string and finds it as truthy value.

Let's consider this code that was run on the console.

» if ("0") "Yes"; else "No";
« "Yes"

Here, we could clearly see that the "0" string value is treated as a true or correctly, truthy value. So when the non-empty strings are not considered as false, a string with "0" is also not considered false.

Workarounds

One of the best way to get around this is using the comparison with 0. Consider the following instruction on the console:

» "0" == 0
« true

» !!"0"
« true

To check the correct value, the comparison operator helps us in comparing with string "0" with intergral 0and it works. At the same time, it is freaking out that the type-casting of string "0" gives you true.

The second method would be using parseInt(). This should be used only when we are triple sure that the output is an integral value and nothing else. We can also add isNaN() as an exception handling mechanism, but it is of too much overkill.

» if (parseInt("0")) "Yes"; else "No";
« "No"

Final Solution

Right now, the best solution is to use parseInt() in this scenario, as I am definitely sure, the service will not return any other value other than 1 or 0.

$(function () {
  // Mimicing the HTTP Response.
  var states = ["1", "0", "0", "1", "1"];
  // This loop loops through all the values and sets the state of the switch.
  $('.toggle').each(function (i) {
    $(this).toggles({
      // Now this works perfectly! ;)
      "on": parseInt(states[i])
    });
  });
});
body {background-color: #f5f5f5;}  
ul, li {margin: 0; padding: 0; list-style: none;}  
ul {width: 150px; margin: auto; background-color: #fff; padding: 10px; border-radius: 3px; border: 1px solid #eee;}  
ul li {padding: 10px;}  
ul li span,  
ul li .toggle {width: 50px; display: inline-block; vertical-align: middle;}  
ul li span {width: 75px; line-height: 1;}  
<link rel="stylesheet" href="https://cdn.rawgit.com/simontabor/jquery-toggles/master/css/toggles-full.css" />
<script src="https://code.jquery.com/jquery-2.2.4.js"></script>
<script src="https://cdn.rawgit.com/simontabor/jquery-toggles/master/toggles.min.js"></script>
<ul>
  <li>
    <span>Item 1</span>
    <div class="toggle toggle-light"></div>
  </li>
  <li>
    <span>Item 2</span>
    <div class="toggle toggle-light"></div>
  </li>
  <li>
    <span>Item 3</span>
    <div class="toggle toggle-light"></div>
  </li>
  <li>
    <span>Item 4</span>
    <div class="toggle toggle-light"></div>
  </li>
  <li>
    <span>Item 5</span>
    <div class="toggle toggle-light"></div>
  </li>
</ul>

Happy Coding folks! :)



comments powered by Disqus