Switch case in MustacheJs - javascript

Using Mustache js (a logic less templating) is there a way i can achieve switch case? this i need because a class is assigned to dom element based on the value for example:
switch(tasks.Count)
{
case 0:
element.Class = "no-tasks";
break;
case 1:
element.Class = "one-tasks";
break;
.
.
.
}
that's the code i got now, how do i transform it to template( I Believe having methods on model being rendered is the one option) But adding methods to determine which class to use is an overkill and besides that is going to pollute my model to a swamp!!
I ask this because i am using Nustache a port of MustacheJs to C#, .NET to render nested model.Anything that applies to Mustache also applies to Nustache

There's a few ways to do this.
In Javascript, if Mustache encounters a function in a value, it will call it using the enclosed text as the only argument.
var data = {
foo: function(text) { return '<b>' + text + '</b>'; }
}
mustache
{{#foo}}
HI I LIKE FISH, thanks.
{{/foo}}
outputs
<b>HI I LIKE FISH, thanks.</b>
Search for "lambda" in the mustache docs.
Another way to do it is do a falsey/truthy check.
data
{ foo: true }
mustache
{{#foo}}
output this if true.
{{/foo}}
{{^foo}}
output if false
{{/foo}}

Related

Use Templating on JavaScript Files

I'm in the most interesting position where I would like to template my JavaScript files server-side to include and remove certain parts based on an object. Given an object like so:
var obj = {
"includeA": true,
"includeB": false,
"includeC": true
}
I would like the ability to include/exclude certain parts of said JS file. For example:
if (obj.includeA) {
// This is some code from A
}
if (obj.includeB) {
// This is some code from B
}
Would produce either a string or a file that looks like:
// This is some code from A
I've looked into some basic options, one of the foremost ideas that came to mind was to simply use if statements in JS. This code however looks rather terrible, and considering there will be upto 1,000 lines of this, not suitable at all:
var string = ""
if (obj.includeA) {
string += "This is one line \n"
string += "This is another line \n"
}
// etc.
This produces the right output, but the repetitiveness of the string += makes me detest it. I then decided to package it up into a function:
var string = ""
function call(line) {
string += line + "\n"
if (obj.includeA) {
call("This is one line")
call"This is another line)
}
// etc.
But that seems only slightly better. Is there any sort of templating engine (imagining something similar to Jade), that allows templating of text blocks like this?

How to Display something depending on variable given in angular

I need to show a word that is attributed to a number, in AngularJS.
Through the controller I send to the view a variable $game.complexity, and complexity can be a number from 1 to 4. I want to take that number and show it as a word:
1 ---> easy
2 --->medium
what I initially thought was that maybe it would work with a cutstom filter:
var filtersModule = angular.module("ttmatchApp.Filters", [])
filtersModule.filter("complexityFilter", function(){
return function(value){
switch(value)
{
case 1:
return "easy"
break;
case 2:
return "medium"
break;
case 3:
return "hard"
break;
case 4:
return "very hard"
break;
}
}
})
and call it like this:
<p>{{game.complexity | complexityFilter:game.complexity}} complexity</p></div>
i also tried it like this:
<p>{{game.complexity | complexityFilter}} complexity</p></div>
I define $scope.game within a controller, and i give it the necessary data through a json file. Other scope elements such as game.name work well, and show.
the filtersModule is also linked to the main module.
Do i have to introduce the filter to the controller as well?
Am i using the wrong method?
Once game.complexity is evaluated in the expression, it is outputted as a string. That means that your switch case should be on strings and not integers - "1" instead of 1, etc..
Edit: I was wrong, the expression is evaluated into a string, but the filter is still within that expression, so it receives game.complexity still as a number. The problem was what you solved in the comments.

Accessing a Dynamically Named Object Property

I'm creating a javavascript object which I'm calling rulesObject. The idea is for it to be a javascript object containing all of the rules I need to check to enable/disable other checkboxes that is dynamically generated from a mysql database at the very beginning of the script. For now, I'm just testing it out with two rules which I know create the scenario I'm looking for, so here's what my object looks like at the moment:
rulesObject = {
chk533570 : ["533577", "503671", "503667", "604028", "503661"],
chk503928 : ["533577", "533578","503671", "503666", "533576", "503667", "324201", "503221", "604028", "503668", "533580", "503669", "533579", "533581", "503670"]
};
Now what I need to do is access the information out of that object. If I do a simple alert(rulesObject. chk533570), it works PERFECTLY – gives me exactly what I need. However, what I'm going to need to do is access a specific rule based on what was just clicked by running through the following. So, for example, if I clicked the checkbox valued "533570", it would go through the following:
$('input').click(function(){
if(this.checked) {
checkRules(this.value, 'checked');
} else {
checkRules(this.value, 'unchecked');
}
});
(Of course I'm using jQuery there, but I'm using it throughout the web app so I don't mind going back and forth.)
Now onto my checkRules function. It's still very simple as it's in the beginning stages – I just want to alert the value of what I just selected. Again, if I do alert(rulesObject. chk533570), even within the function, I get the right result, but I need to access what I just selected, so I have to add the letters 'chk' to the beginning of the object property name and then append the justselected value (which in this case equals 533570). Here are the ways I've tried to do it:
function checkRules(justselected, state) {
rulename= 'chk' + justselected;
currentrules = rulesObject.rulename;
alert(rulename);
alert(currentrules);
}
Alert 1: chk533570
Alert 2: undefined
function checkRules(justselected, state) {
rulename= 'chk' + justselected;
alert(rulesObject.rulename);
}
Alert: Undefined
function checkRules(justselected, state) {
rulename= 'chk' + justselected;
alert(rulesObject + '.chk' + justselected);
}
Alert: [object Object].chk533570
function checkRules(justselected, state) {
alert(rulesObject.chk533570);
}
Alert: 533577,503671,503667,604028,503661
So, any idea how to properly call that name so that I get the right results? I also tried not having the 'chk' in there at all, but the javascript object didn't like a completely numeral property.
obj.key is the same as obj['key'] - but in the second way the key can be dynamic since it's a plain JavaScript expression.
So you can simply use rulesObject['chk' + justselected]:
function checkRules(justselected, state) {
alert(rulesObject['chk' + justselected]);
}
Long time ago people used to use alert(eval('rulesObject.chk' + justselected)); by the way. While this works, do not use this. Using eval() should be avoided at all times; and in this case there is a much cleaner way anyway.

Limit the number of characters rendered by a Mustache.js tag

Is there any way in Mustache of limiting the number of characters a Mustache tag generates?
eg
template = "<li>{{my_tag}}</li>"
data = {
"my_tag" : "A very long string that needs to be abbreviated to fit into the available space."
}
Now when I render my tag I want to abbreviate the long string by showing only the first 10 chars follwed by an ellipsis. I looked into using a lambda function (as described in the Mustache docs) like so...
template = "<li>{{#limitLength}}{{my_tag}}{{/limitLength}}</li>"
data = {
"limitLength" : function() {
return function(text) {
return text.substr(0,10) + '...';
}
},
"my_tag" : "A very long string that needs to be abbreviated to fit into the available space."
}
but unfortunately the {{my_tag}} tag doesn't get expanded. The Mustache manual states:
The text passed is the literal block, unrendered. {{tags}} will not
have been expanded - the lambda should do that on its own.
.. but I can't imagine how to do this without using the Mustache.to_html() function and when I try to use it like so...
eg
data = {
"limitLength" : function() {
return function(text) {
return Mustache.to_html(text,data).substr(0,10) + '...';
}
},
"my_tag" : "A very long string that needs to be abbreviated to fit into the available space."
}
... it fails silently (the recursive use of the data object is possibly to blame here)
Does anyone know of any other way of achieving this without resorting to a javascript/jQuery function, I'd like to implement it just using Mustache if possible.
Your function actually gets called with two arguments: the unrendered text and a render function which can be used to render your text, keeping the current context.
data = {
"limitLength" : function() {
return function(text, render) {
return render(text).substr(0,10) + '...';
}
},
"my_tag" : "A very long string that needs to be abbreviated to fit into the available space."
}

convert string to a variable java

i have i string like
5: "White", 6: "Yellow", 7: "Pink"
i need that string view like this
s={5: "White", 6: "Yellow", 7: "Pink"};
for attach it to select on form
for (var a in myOpts)
{
var t = document.createElement("OPTION");
t.value = a;
t.appendChild(document.createTextNode(myOpts[a]));
selectObj.appendChild(t);
}
If you json_decode your string s, you will get a plain object with 3 owned properties. Then you can loop on those properties with the for..in construct:
var myOpts, s='{5: "White", 6: "Yellow", 7: "Pink"}';
eval('myOpts='+s); // or better, a json parser
for(var a in myOpts) {
if(myOpts.hasOwnProperty(a)) {
// your dom code here
}
}
Your question is a little unclear, however - I'll try to guess what you're saying, cover all cases and give a little added value ;)
I assume that you have a server-side string in a JSP page, who's value is
5: "White", 6: "Yellow", 7: "Pink"
What makes it look like
<%
String data = "5: \"White\", 6: \"Yellow\", 7: \"Pink\"";
%>
And now you want to write it to to the document, so you can for it later on on client-side code.
In that sense - you need to distinguish between few cases.
Although when the server writes it into the response document it is a string - the client code can get this value in different ways. In all of them - the server must write the data in a specific way so that the client can access it, however, the validity rules are different.
Write an object literal
Actually - I think that that's what you're trying to do.
The client code does not get it as a string - but as an object literal.
<script>
var sObjData = {<%= safeJs(data) %>};
</script>
The limits of this choice is that whatever comes from the server code (within the <%%>) and whatever comes from the markup (outside the <%%>) must work together as a valid JavaScript object literal.
There are many things that can break legality of this Object literal - like broken strings, missing commas, missing colons, and so on. Although this is the recommended way - you have to know what you're doing, and I advise you to gap up this knowledge, and your example is a good start.
In your example - this renders to a valid JavaScript Object-Literal, and the problem is not there.
<script>
var sObjData = {5: "White", 6: "Yellow", 7: "Pink"};
</script>
This is a perfectly legal object literal that can be used in for - just the way you do.
It could be that your example is simplification of your case, and the strings that you use may break your execution. Here's how to handle strings from server to client-code:
Write a JavaString string
The limits in this case - is that any character in data string that might break JavaSctipt strinbngs - must be escaped for javascript.
Here I just treat the whole data value, however - bear in mind that you might want to do the same for every values that you put inside this data.
Here's the simplest implementation that explains that's to escape a Java string for JavaScript:
<%!
String safeJs(String data){
return data.replace("\"","\\\"") //why three? two emit a sigle \ and the third escape the "
.replace("'","\\'")
.replace("\n","\\n") //why two? you're not escaping n, your're emitting \ and n
.replace("\r","\\r"); // that will render as escaping for the client code
}
%>
<script>
var sObjData = '<%= safeJs(data) %>';
<script>
This part will assure that you get all the data from the server to the client, and that it will be accessible to the client. From there - it's a matter of your own protocol of delivering data and parsing it on the client.
However, this is not always recommended: If all you're delivering can be formulated as an Object Literal - it is much better - because the Browser handles the parsing for you in a complied code, and gives the scripting code a ready-made object.
Unless you want to parse your own string-protocol, seemingly - its gets the same result to the following, so why bother? better to safeJs your values.
<script>
var sObjData = '<%= safeJs(data) %>';
var oObjData = eval("{" + oObjData + "}");
<script>
Write the string to a content of a TextArea
This is the most robust way of passing strings between server and an HTML client - because the only thing that can break - is if the data string contains a closing tag of TextArea.
A text area is immune to line-breaks, it is immute to quotation marks (single and double), it's sole weakness is it's own closing tag.
Note that replacing the "" with "<textarea>" and "" with "<textarea>".
Assigning an ID to the text area and putting it in style="display:none" assures that it will not bother the UI, and yet be accessible.
<textarea style="display:none" id="txtData"><%=data.replace("</","</")%></textarea>
<script>
var s = document.getElementById("txtData");
</script>
building options in a Select
The DHTML tricks of createElement works, however, I rarely use it, because it's cumbersome, and very low on performance.
However - if you managed to write your Object Literal properly - it should work.
injecting HTML
Instead of creating a select and trying to populate it - it is faster and more reliable to inject it completely into the DOM.
I use the following utility for that:
function getStringBuffer(){
var bfr = [];
bfr.add = function() {
for(var i=0;i<arguments.length;i++) {
this[this.length] = arguments[i];
}
}
bfr.toString = function() { return this.join("") }
return bfr;
}
The wrap in (function(){ and })() creates an anonymous function and executes it instantly - that assures that no variables that are declared for this work will pollute the global scope.
first way - using document.write:
<script>
(function(){
var HTML = getStringBuffer();
var k;
HTML.add("<select id='selectObj'>");
for (k in myOpts) {
HTML.add("<option value='", k, "'>", myOpts[k],"</option>");
}
HTML[HTML.length] = "</select>";
document.write(HTML); //note the overriden toString method that will be called here
})();
</script>
Second way - using innerHTML
You can do the same and instead document.write - use a container tag to mark the place of the select, and inject it there even after the DOM has finished loading.
it's the same as the first way, in one difference: Instead document.write(HTML); -
put a container, say <span id="oSelectPlace"></span> where you want the select to be, and then use
document.getElementById("oSelectPlace").innerHTML = HMTL;

Categories