Closed Frencil closed 7 years ago
The functionality I want is foo || foo === 0
.
Syntax options:
{{#if foo || foo === 0}}
- supporting ||
and [===
, <
, &c] wouldn't be too hard. It could also support &&
(which happens before ||
) and !
(happens first) to reach conjunction-of-disjunctions completeness. No need for parentheses, and it'll make {{#else}}
never necessary. It'd better be easy to use because it'll be confusing to debug.{{#if foo|truthy_or_0}}
- especially if truthy_or_0
is built-in to LocusZoomCurrently, we parse templates with
/\{\{(?:(#if )?([A-Za-z0-9_:\|]+)|(\/if))\}\}/;
but the new regex will be:
var field = '[A-Za-z0-9:|_]+';
var thing = '(?:' + field + '|"(?:[^"]|\\\\")*"|[0-9]+)';
var op = '(?:===|!==|<|>)';
var bool = '\\s*(?:!\\s*)*'+thing+'\\s*';
var comp = '\\s*'+thing+'\\s*'+op+'\\s*'+thing+'\\s*';
var expr = '(?:' + bool + '|' + comp + ')';
var disjoint = '(?:' + expr + '(?:\\|\\|' + expr + ')*)';
var ifregex = '{{#if ' + disjoint + '}}';
var varregex = '{{' + field + '}}';
var endifregex = '{{/if}}';
var regex = new RegExp(ifregex + '|' + varregex + '|' + endifregex);
which evaluates to
/{{#if (?:(?:\s*(?:!\s*)*(?:[A-Za-z0-9:|_]+|"(?:[^"]|\\")*"|[0-9]+)\s*|\s*(?:[A-Za-z0-9:|_]+|"(?:[^"]|\\")*"|[0-9]+)\s*(?:===|!==|<|>)\s*(?:[A-Za-z0-9:|_]+|"(?:[^"]|\\")*"|[0-9]+)\s*)(?:\|\|(?:\s*(?:!\s*)*(?:[A-Za-z0-9:|_]+|"(?:[^"]|\\")*"|[0-9]+)\s*|\s*(?:[A-Za-z0-9:|_]+|"(?:[^"]|\\")*"|[0-9]+)\s*(?:===|!==|<|>)\s*(?:[A-Za-z0-9:|_]+|"(?:[^"]|\\")*"|[0-9]+)\s*))*)}}|{{[A-Za-z0-9:|_]+}}|{{\/if}}/
I'd propose a third option; something that lets basic conditionals use expected javascript evaluations of truthiness but allow for an explicit "is defined" check (maybe something along the lines of {{#ifdefined {{var}}}}...{{/ifdefined}}
). In your use case here it seems you only care about showing something if it's defined and don't really care about its value if it is, so maybe expanding out the conditional logic to allow for operators and compound conditionals is an overkill approach to a much simpler problem.
But, in my case, I want empty strings to be falsy.
{{ifnotempty {{var}}}}...{{/ifnotempty}}
?
Certainly gargantuan regexes are an indication that we're not heading in the right direction. A more explicit tag that is purpose-built and can be clearly documented with clean syntax is going to play much nicer for clarity and long term maintainability.
(rows with disagreements are capitalized)
Boolean() |
not empty | what most users want | |
---|---|---|---|
0 | FALSE | TRUE | TRUE |
1, inf | true | true | true |
"" | false | false | false |
"x" | true | true | true |
[] | TRUE | FALSE | ?? |
[1] | true | true | ?? |
{} | TRUE | FALSE | ?? |
{x:1} | true | true | ?? |
true | true | true | true |
false | FALSE | TRUE | ?? |
null | false | false | false |
NaN | FALSE | TRUE | ?? |
undefined | false | false | false |
I like the term not empty
, good idea.
I see two types of usage of guards:
false
should be shown in is_imputed
but hidden for isldrefvar
.""
if desired.If we'd only need a few tests, it might make sense to make each one a {{#iffoo var}}
, but with lots (and a need for customization), transformations make more sense.
Should we roll-back my 0-is-truthy PR and instead add and document
LocusZoom.TransformationFunctions.add("is_not_empty", function(x) {
if (typeof x === "undefined") return false;
if (typeof x === "number") return true; // note: typeof NaN === "number", despite the name
if (typeof x === "boolean") return true;
if (typeof x === "object" || typeof x === "string") { handles array, object, null, string
for (var k in x) if (x.hasOwnProperty(k)) return true;
return false;
}
console.error("what is " + x.toString() + "?"); return true;
});
?
In response to the table my assumptions about what "not empty" means would differ with yours for []
and {}
and could really see NaN
going either way. The term is clearly too ambiguous, so isn't a viable solution to this problem.
At this point I'd be wary of overcomplicating this issue. We've solved the immediate problem for PheWeb's use case, and the behavior is well documented. Let's let it be until an actual use case for 0-falsey behavior presents itself.
In #101 the
{{#if foo}}{{/if}}
conditional was changed such that the value (foo
) is evaluated as true when0
. This solves the immediate problem that arises when using the conditional tag for determining if a field is populated with any value but may break expected behavior should a value of0
need to be evaluated as false.A potential solution would be to expand the conditional tag to optionally support an operator and comparison value, allowing for more explicitly defined behavior.