borismoore / jsrender Goto Github PK
View Code? Open in Web Editor NEWA lightweight, powerful and highly extensible templating engine. In the browser or on Node.js, with or without jQuery.
Home Page: http://www.jsviews.com
License: MIT License
A lightweight, powerful and highly extensible templating engine. In the browser or on Node.js, with or without jQuery.
Home Page: http://www.jsviews.com
License: MIT License
If creating a table template with <col> tags without <colgroup>, the browser will force to add a <colgroup> around <col>.
The active view comments get messed up causing a JavaScript error, not able to find the correct data for the template.
<table>
{{each columns tmpl=templateCol}}
…
</table>
templateCol is:
<col />
The output on the page is:
<!--tmpl() _0-->
<table>
<!--tmpl($data.columns) _1-->
<!--item-->
<colgroup>
<col>
<!--/item-->
<!--item-->
<col>
<!--/item-->
<!--/tmpl-->
</colgroup>
</table>
<!--/tmpl-->
As demonstrated in Demo 1 (https://github.com/BorisMoore/jsrender/blob/master/demos/step-by-step/01_inserting-data.html), when an array of data is passed to a template that template gets duplicated. Is it possible to simply iterate through the data and only duplicate part of the template?
Using Demo 1 as a basis, something like...
<script id="movieTemplate" type="text/x-jquery-tmpl">
<ul>
{{#each}}
<li>
{{=$itemNumber}}: <b>{{=Name}}</b> ({{=ReleaseYear}})
</li>
{{/each}}
</ul>
</script>
In jQuery templates, one could call a nested template without specifying a data object (example: {{tmpl '#myTemplate'}}), which was useful. In jsrender, this does not appear to work and fails with the error 'current is undefined'. I've seen this in two places:
Thanks for all your great work, Boris!
in order to avoid validation conflicts i use a CDATA section, see example below:
<![CDATA[
/\* template goes here */
]]>
</style>
when compiling the template, the markup needs cleaning:
markup = markup.replace(/\]\]>/, "" );
Right now, {{#... is for block tags, and {{... is for not block tag, but why not having just one notation {{... and when there is no content, we just end it with /}}.
I think that this notation would be more familiar to developers (as it is similar to xml), and will simplify the notation.
JSON number values that are 0 are not rendered. For example:
input:
{"quantity":0}
template:
Quantity: {{=quantity}}
output:
Quantity:
I tested the rendering in IE7-9 and from a few hundreds rows until a few thousand, it goes extremly fast, even in IE7. In Firefox, it's ok but it takes more time, specially the difference between IE and firefox grows when the data are bigger and bigger, but well it's still acceptable.
But in Chrome, it takes 2-3 seconds by 1000 lines, 10-15 by 2000 rows and almost 1 minute by 3000 while it takes at most one second for IE7 for exactly the same data. I guess there is somewhere something wrong.
Sometimes you get an JSON object like this (copied from firebug):
link [Object { title="Inicio", url=""}, Object { title="Ciudad", url="ciudad.php", sublink=[11]}, Object { title="Tramites", url="#"}, 3
0 Object { title="Inicio", url=""}
1 Object { title="Ciudad", url="ciudad.php", sublink=[11]}
2 Object { title="Tramites", url="#"}
3 Object { title="Noticias", url="#"}
4 Object { title="Calendario", url="#"}
5 Object { title="Sobre Nosotros", url="#"}
Where you get an index for an object instead of the object itself. In order to access the properties of the object, you need to reference this index.
I dont know if there is a way to get the length of the object and iterate it.
What are your comments.
Hi Boris,
When I run the current version of JSRender's 01_inserting-data.html page I get an Error: Unterminated string constant exception due to newlines in the generated function javascript. I fixed it by changing the end of the buildTmplFunction function to
try {
ret = new Function("$data, $view", (code.slice(0, -1) + ";return result;\n\n}catch(e){return views.err(e);}").replace(/\n|\r/g, " "));
} catch(e) {
...but this might not be the best way to fix it!
Cheers
Jason
Trying to render the following on IE9 in IE8, IE7 rendering modes:
<script id="tableChangeLog_template" type="text/x-jquery-tmpl">
<div class="logrow logheader">
<div class="logcell">Time</div>
<div class="logcell">User</div>
<div class="logcell">Action</div>
<div class="logcell">Old Value</div>
<div class="logcell">New Value</div>
<div class="logcell">Change Reason</div>
</div>
{{each($index, line) data}}
<div class="logrow">
<div class="logcell logdate">{{= line.time}}</div>
<div class="logcell">{{= line.user}}</div>
<div class="logcell">{{if line.action.indexOf("­") == -1}}{{= line.action}}{{else}}{{html line.action}}{{/if}}</div>
<div class="logcell">{{if line.old.indexOf("­") == -1}}{{= line.old}}{{else}}{{html line.old}}{{/if}}</div>
<div class="logcell">{{if line.new.indexOf("­") == -1}}{{= line.new}}{{else}}{{html line.new}}{{/if}}</div>
<div class="logcell">{{if line.reason.indexOf("­") == -1}}{{= line.reason}}{{else}}{{html line.reason}}{{/if}}</div>
</div>
{{/each}}
</script>
Calling as such:
$('#tableChangeLog_anchor').html(
$('#tableChangeLog_template').render(my_data)
)
Yields the following error in the console:
SCRIPT1010: Expected identifier
jquery.render.js, line 341 character 2
Tested against code circa Sept 13, commit c6daa48
Same rendering engine renders other (simpler, a few string replacements and simple each loop) templates just fine on the same page. Just blows up on the above template.
I have an object like this:
"GoodStuff": {
1: "Chimay",
2: "Orval"
3: "Westmalle"
}
I would expect that if I say ...
{{#each GoodStuff}}
I created a workaround by changing the object to
"GoodStuff": [
{
"Key": 1,
"Value": "Chimay"
},
{
"Key": 2,
"Value": "Orval"
},
{
"Key": 3,
"Value": "Westmalle"
}
]
Thanks for your work, really love working with the project!
I'm just throwing this thought out there as a suggestion because I feel a little weird still using the script type x-jquery-tmpl as seen in the examples.
jsrender's syntax is different than jquery-tmpl. Also, there is no jQuery dependency.
text/x-jsrender?
A small thing but I spent an hour trying to figure out why JSRender was not working for me. It was because I was still loading Jquery Templates in the page. Might want to spit out a console error if JSRender is called when JQuery templates also exists.
I usually list the field names in the table and then fill the table using jquery templates. With jsrender the appendTo doesn't seem to be working. Maybe I'm going about it wrong?
This works but removes my table header row:
$("#tblMostActiveUsers").html($("#MostActiveUsersTemplate").render(data.d));
This doesn't work in jsrender:
$("#tblMostActiveUsers").appendTo($("#MostActiveUsersTemplate").render(data.d));
Thanks for any help!
Craig
I have to deal with a key with a period in the name ("Scope.Name") and it would be great to access it within a template like this.
Attributes["Scope.Name"].value
in the meantime i'm using this to get the job done.
{{#each Assets}}
{{* var $row = $view.parent.data[$view.itemNumber-1]; }}
<li>{{=$itemNumber}}</li>
<li>{{=Attributes.Name.value}}</li>
<li>{{* result += $row.Attributes["Scope.Name"].value; }}</li>
{{/each}}
Is it possible to make a tool available for precompiling templates (using node, for instance)?
This could be integrated in an assets builder setup or using tools like Guard.
I'm hoping this could improve performance under production.
Thanks for considering the idea.
Sorry I can't provide code to back this issue... I was testing with an ajax call which returned an object that was preprocessed and then passed to render... This problem appeared (under FF7)... The template was OK, as well as the variables... Do you know if there are known bugs where this can happen?
I'm porting away from jQuery to Zepto.js, so I was happy to see that jsrender is a non-jQuery dependent version of jQuery templates. However, it overrides $ if jQuery isn't present, which means it overrides Zepto's use of $. I think I've resolved this for now by adding this to jsrender.js:
if (Zepto) {
$ = Zepto;
$.isArray = Array.isArray || function( obj ) {
return Object.prototype.toString.call( obj ) === "[object Array]";
};
$.noConflict = function() {
if ( window.$ === JsViews ) {
window.$ = _$;
}
return JsViews;
}
}
But there's probably a better way - perhaps if it finds something else using $, it could just add to it, not redefine it? Thanks!
Is there a way to use a variable with {{=my_var}} and have it not print anything when that variable in undefined?
I am trying to do something like:
<input name="form_field" type="text" value={{=previous}} />
And the page is showing "undefined" as the value. I would prefer to not see any text.
Not sure if I just missed this but in a nested template how do i display a property from the parent object..
eg. Display the movie title in the nested template
http://borismoore.github.com/jsviews/demos/jQueryConfDemosOct2011/08b_each-composition.html
This should be possible: {{=$ctx.foo().name}}
I'm switching from jquery templates and have it almost working.
I'm currently getting this error:
Error: $data.formatScheduleDateTime is not a function.
Here is my code:
{{=dateFormat(formatScheduleDateTime(DatePublished), 'dddd, mmmm dS, yyyy, h:MM TT') }}
Is there something special I need to do to call the function? i know the function exists.
Thanks,
Craig
Currently #each only works if you have an array, so i am having to do a costly conversion:
http://jsfiddle.net/pixelhobo/E9dUm/
It would be much better you went over the key/value pairs of an object, something like this:
e.g. nested template in if block: {{#if languages}}{{/if}}
Everything works perfectly on the main page, but when I browse the contact page the plugin does not work:
Error message in console (contact page):
Uncaught TypeError: object is not a function
jquery.tmpl.js:329
Uncaught Template command not found: getDay
js:2000
The tag is registered! I have nothing unusual about the contact page (no javascript nothing but jsrender)
See images: http://imgur.com/a/LwXDn#0
See the complete question: http://stackoverflow.com/questions/8084036/template-returns-an-object-instead-of-a-function
jsrender seem to fail when a json property contains a $ like the youtube api data media$Group.$t
is it possible to escape this somehow or?
Using this as an example
http://borismoore.github.com/jsviews/demos/jQueryConfDemosOct2011/08_each-tag.html
What is the best method to print just the first x Languages.
Brad.
Unless I have overlooked it, I have not seen an example of how to render a template inside of another template. Would it require the creation of a new tag?
A common use is nesting two or more #each.
I you have a JSON like
{
"name": "m-form",
"id": "m-form",
"action": "",
"method": "post",
"elements": [{
"type": "div",
"class": "m-form-div-email",
"elements": [{
"type": "label",
"for": "m-form-mail",
"html": "E-mail"
}, {
"name": "mail",
"id": "m-form-mail",
"type": "text"
}]
}, {
"type": "div",
"class": "m-form-div-country",
"elements": [{
"type": "label",
"for": "m-form-country",
"html": "País"
}, {
"type": "select",
"id": "m-form-country",
"name": "country",
"options": {
"US": "USA",
"ES": {
"selected": "true",
"value": "ES",
"html": "Spain"
},
"FR": "France",
"PT": "Portugal",
"UK": "United Kingdom"
}
}]
}]
}
And have the following templates,
formTemplate:
<script id="formTemplate" type="text/x-jquery-tmpl">
Lorem ipsum
{{#each elements tmpl="#elementTemplate"}} </script>
<script id="elementTemplate" type="text/x-jquery-tmpl"> {{#if type == 'div'}}
my div {{#each elements tmpl="#inputTemplate"}}{{/if}} </script>
<script id="inputTemplate" type="text/x-jquery-tmpl"> {{#if type == 'label'}} {{=html}} {{/if}} </script>
The result should be a:
FORM DIV ...elements DIV ...elements
But instead I get nested elements as:
FORM DIV ...elements DIV ...elements
Hope I'm clear and you can fix it.
HI Boris,
BTW Very cool library:
If I had data like { name:"just_dog", age:7 }
How could age (as a number) be used in a template:
All the best
Chris
I have many templates like this:
<script id="stats-table-foodtypes-data-tmpl" type="text/x-jquery-tmpl">
{{#each dates}}
{{#if data}}
{{=$data}}
{{else}}
?
{{/if}}
{{/each}}
</script>
They expect an array of values, and they render one thing if the value is there and another thing if it is not. This worked in jQuery templates, but in jsRender, it appears that it does not call the template code at all for a null value. Is this the expected behavior?
it would be nice to have access from within a template to the current iteration index, e.g. {{=$ctx.index}}
some use cases:
the index could always be stored in the data before hand, but there should not be a correlation between display position and data, e.g. a filtered data table, whose first result may not be the first data entry.
I had an issue where a carriage return character was finding its way into the parsed template and in Internet Explorer I'd get an error at line 545 complaining of an unterminated string which on inspection turned out to be a " followed by an unescaped \r.
My workaround was chnaging line 406 to the following:
content.push( markup.substr( loc, shift ).replace( rNewLine,"\n").replace("\r", "\n"));
Unfortunately I haven't had time to replicate this small-scale yet but I'm posting an issue in case it's something obvious that you can fix.
In jQuery templates, I could use $value to get the value of an item in a list, for example. I can't manage to figure out how to do that with the jsRender templates.
For example, given this list:
['dogs', 'cats', 'monkeys']
and this template:
<script id="log-tags-tmpl" type="text/x-jquery-tmpl">What should go instead of {{=$value }}?
I've looked through the demos but don't think I saw an example using a flat list. Thanks!
{{=languages.0.name}}
See issue.
I guess this is chrome issue, but worth to mention here.
I had situation when rendered template replaced content in of whole form element content, including initial input:submit button, which caused form not submiting to server regular (without giving it hand with additional javascript code) form submit was not mention to be ajaxified, just plain old HTTP post.
Issue only occurs in Google Chrome, Firefox is not suffering from it.
Current workaround is to attach event handler like:
$("form").on("click", "input:submit", function(){ this.form.submit(); });
I have found when working with jquery templates that there are a number of things that need to be bound after the template is rendered, for example click events or loading masks/watermarks on inputs. My solution to this was to wrap the template load call in a function which inserts the template name as an attribute to target DOM element and pass the original arguments, then use .live() to wire these behaviors if the template and event appears. For example:
$("[template*=#navigation]").live("template_loaded", function(e,templateName) { }
Is there an existing/different way to do this sort of behavior binding after template load that i may have missed? is firing some events off that we can subscribe to something you could consider in the future.
If this is supposed to be a serious replaced for jQuery templates then you need real documentation and not just a set of examples for me to make wild guesses about
I was wondering if it would be possible to make a common js compliant jsrender.js file (something that doesn't use window.views or whatnot outside of the main method).
I have a small wrapper I wrote around jsrender for nodejs:
https://github.com/shtylman/node-jsrender
and it would make bringing in jsrender code changes much easier :)
(If you accept patches for this I would be happy to provide one).
Is there a way to render templates from XML datasources?
The syntax for implementing simple comparisons is overly complex and I think there should be simpler method for adding simple comparisons to your template code.
For example, in jquery.tmpl, you could do:
<div class="base{{if varName == 'None'}} none{{/if}}">${varName}</div>
However, this simple comparison is much more difficult in the new engine. First, you've got to set:
$.views.allowCode = true;
And then your template ends up looking something like this:
<div class="base{{* if($view.data.varName == 'None'){ result += ' none'; } }}">{{=varName}}</div>
This is quite a bit more complicated to implement and much more difficult to interpret.
Any chance of being able to implement something like:
<div class="base{{#if equals(varName, 'None')}} none{{/if}}">{{=varName}}</div>
Where we have some functional helpers like equals(), not(), gt(), lt(), gte(), lte()--and with the potential to define more helper functions.
I can understand dropping to code view for more complex operations, but it seems like there should be a way to at least perform some simple comparisons w/out having to drop to the overly complex code syntax.
Hi, given a JSON snippet like:
[{"title":"Cat 1 & Cat 3 Title 2","body":"<p>Lorem ipsum
(I escaped the source so it looks correct in preview)
The ampersand is being escaped so that it is rendered like: &amp; -- Some way to fix in the current build? (just cloned a few minutes ago). On line 244, I see:
encoders: tmplEncode = {
"none": function( text ) {
return text;
},
"html": function( text ) {
...
How do I trigger "none"?
The less than and greater than for the p is rendered correctly (i.e. as an open p tag).
My template looks like:
<script id="pf-video-teaser-tmpl" type="text/x-jquery-tmpl">and I call it like (your sample demos):
$ul.html($teaser_tmpl.render(videos));
Been giving this a little try and found 2 small syntax errors:
Changed:
tmpl = buildTmplFn(tmpl)
To:
tmpl = buildTmplFn(tmpl);
And:
content = self.tmpl($, self);
To:
var content = self.tmpl($, self);
Will come back for some question, tho now i gotta get back to work :)
Robert
<img src="{{if photo}}${photo}{{else}}/media/no_photo.png{{/if}}" class="photo" alt="${slashes_title}" />
not working... getting
<img alt="Soraya" class="photo" src="%7B%7Bif%20photo%7D%7D$%7Bhtml%20photo%7D%7B%7Belse%7D%7D/media/no_photo.png%7B%7B/if%7D%7D">
It looks like the latest version causes an error in IE8 resulting in the following error: "Unterminated string constant." The error seems to occur in the function buildTmplFunction
at this line:
try {
ret = new Function("$data, $view", code.slice(0, -1) + ";return result;\n\n}catch(e){return views.err(e);}");
} catch (e) {
ret = function () {
return viewsNs.err(e);
};
}
This error is visible in all the demos.
Thanks!
Hi Boris,
just noticed that if I set the delimiters with 2 different characters, like for example "<%" and "%>", it doesn't work.
setDelimiters: function( openTag, closeTag ) {
// Set or modify the delimiter characters for tags: "{{" and "}}"
var firstCloseChar = closeTag.charAt( 1 ),
secondCloseChar = closeTag.charAt( 0 );
openTag = "\\" + openTag.charAt( 0 ) + "\\" + openTag.charAt( 1 );
closeTag = "\\" + firstCloseChar + "\\" + secondCloseChar;
I presume you wished to type:
var firstCloseChar = closeTag.charAt( 0 ),
secondCloseChar = closeTag.charAt( 1 );
with this little fix, it works.
I have an ajax request that fetches the templates along with the data...
response{
templates{...},
data{....}
}
in your demos there are already predfined templates in a script element.. can you make a demo example with templates loaded from an external json file or at least from a js string variable?
Boris,
I'm not sure it's an issue rather than a request... :)
Nevertheless, it would be nice to be able to do a
{{#if varOne==1 && varTwo==2 }}
and Merry Xmas ! ;)
jquery-tmpl was dual-licensed via the MIT and GPL2 licenses. I'm guessing that your code is also, but I think it would be good to clarify this point. Will you add a license to the code?
Hello,
I am working on a fork / port for jsrender for nodejs. Would it be possible to bake in support in option form for maintaining whitespace formatting for the scripts output?
Thanks
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.