Is it possible to define a view template in a javascript variable, instead of a script tag or a file?
Something like this:
var template = "< h1 ><%= title %> < / h1 >";
var rendered = can.view.render(template, data);
Ok, after a lot of research, because it isn't written in documentation, I found how to do it.
The trick is that you have to register your template with an id first.
If you are using a script tag or url to find a template, this step is done automatically by canJS.
So, if you want to render a template, stored in a variable, you have to do something like this:
var template = "< h1 ><%= title %> < / h1 >";
can.view.ejs('my-view-id', template);
var rendered = can.view.render('my-view-id', data);
Now you have the document fragment in rendered.
Take a look to jquery utils string format plugin. There is an example that shows rendering html from template that was defined as as string.
Creating template:
$.tpl('tweet', [
'<div id="tweet-{id:s}" class="tweet">',
'<div class="tweet-body"><b>#{from:s}</b>: {body:s}',
'(<a href="{href:s}" class="tweet-date">',
'<abbr title="{timestamp:s}">{timesince:s}</abbr>',
'</a>)',
'</div>',
'</div>'
]);
Rendering:
$.getJSON('/tweets/username/', function(resp, s){
$.each(resp.tweets, function(idx, tweet) {
$.tpl('tweet', {
id: tweet.id,
body: tweet.body,
from: tweet.screen_name,
timestamp: tweet.pub_time,
timesince: $.timeago(tweet.pub_time)
}).appendTo('#tweet-list');
});
});
Related
In my JS I have list of products.
var productData = [{
title: 'Bike',
price: 300
},{
title: 'Guitar',
price: 199
}]
This data is gathered from remote Json in a Async call. So I have to do this in JS.
Eventually, I come to a situation, that I need to display this product. But here are 2 things.
1) In HTML I am outside of my main Vue instance scope. It is so because there is 3rd party API that interacts with those products, apart other things... So This array is not bound to Vue instance in any way.
2) This product list is dynamically created, on the fly. In order to display it, I have to do a good old html string concatenation and then apply it.
Main problem:
Now whenever I need to display a product - I have a Vue.js Component for it. That has a template, and all data goes really nicely. I obviously want to reuse this same template.
So right now I have something like this:
//Vue.js Component, that I want to use, and feed my product to:
Vue.component('product', {
props: ['product'],
template: `
<div class="prod">
<h3>{{product.title}}</h3>
<p>{{product.price}} €</p>
</div>
`, data() {
return {
}
}
});
Next in JS, I have this code:
var prodList = getProductsAsync("3rd party service URL and parameters");
var prodHtml = '';
for(var i = 0; i < prodList.length; i++){
prodHtml += `
<div class="prod">
<h3>${prodList[i].title}</h3>
<p>${prodList[i].price} €</p>
</div>
`;
}
Here I have 2 templates (one as JS html, and another in Vue.js component), that is redundant.
I need to have 1 way to maintain this template. At the moment template is simple, but more functionality will shortly come.
Idealy I would like my JS object to use my Vue.js template. As a result it would also behave as Vue.js component too.
So in my JS I would like to have it like this (But this obviously does not work):
var prodList = getProductsAsync("3rd party service URL and parameters");
var prodHtml = '';
for(var i = 0; i < prodList.length; i++){
prodHtml += ` <product :product='prodList[i]'></product>`; // attempt to use Vue.js component 'on the fly' but this does not work!
}
Any suggestions?
It doesn't work, because there is some order in which you have to create component, html, and Vue instance.
// just use all your code together
// first, prepare the component
Vue.component('product', {
props: ['product'],
template: `
<div class="prod">
<h3>{{product.title}}</h3>
<p>{{product.price}} €</p>
</div>
`
})
// and get products
var prodList = getProductsAsync('/someMountpoint')
// then generate html with unknown tags "product"
var prodHtml = '<div id="productList">'
for(let i = 0; i < prodList.length; i++) {
prodHtml += `<product :product='prodList[i]'></product>`
}
prodHtml += '</div>'
// append this html to DOM
$('#someWhere').html(prodHtml)
// and now create new Vue instance to replace
// these unknown product tags with real tags
new Vue({
el: '#productList'
})
Is it possible to pass HTML tags as properties and then render in React.js
For example ES2015 syntax:
I add the property as a string with HTML tags:
renderItems(posts) {
var groupDate = this.props.item.date.toUpperCase();
var listCol = '<h4>' + groupDate.toString() + '</h4>';
return (<ViewList list={posts} postCol1={listCol}/>);
}
And in my ViewList component I have:
<div className="col-md-9">{this.props.postCol1}</div>
This is rendered as :
<h4>JANUARY 28TH, 2016</h4>
How do I get react to render the date excluding the HTML tags?
Different views uses this component and tags may be different explaining why I would like to include the tag.
This actually worked:
renderItems(posts) {
var groupDate = this.props.item.date.toUpperCase();
return (<ViewList list={posts} postCol1={<h4>{groupDate.toString()}</h4>}/>);
}
Take the <h4> tags out of the listCol string. Your ViewList component should render them:
<div className="col-md-9">
<h4>
{this.props.postCol1}
</h4>
</div>
So I'm working with Django on a website that I am playing around with, and have been trying to research how I could get the following list in my views.py and be able to reference it in my javascript? I'm working on creating an ajax call and the tutorials I am coming accross are a bit confusing.
#lines 6 - 8 of my code.
def catalog_home(request):
item_list = item.objects.order_by('name') #item is the model name
note: the item model containts a name, description, overview and icon column.
Is it possible for me to use the list above (item_list) and be able to write a javascript function that does something similar to this? :
$(document).ready(function() {
$("#showmorebutton").click(function() {
$("table").append("<tr></tr>");
for (var i = 0; i < 3; i++) {
var itemdescription = item.description;
var itemName = item.name;
var icon = item.icon;
$("table tr:last").append(generateCard(itemName,
itemdescription,
icon));
}
function generateCard(itemNameC, itemdescriptionC, iconC) {
var card = "<td class='tablecells'><a class='tabletext' href='#'><span class='fa "
+ iconC
+ " concepticons'></span><h2 class='header'>"
+ itemNameC
+ "</h2><p>"
+ itemdescripionC
+ "<span class='fa fa-chevron-circle-right'></span></p></a></td>";
return card;
}
I don't mean to crowd source the answer to this, I just would appreciate any feedback/advice for me to handle this task, as I am fairly new to coding.
You should absolutely be able to do this. The trick is to understand Django templates. You showed part of the view but you will need to render to a template. Inside the template, you can just do something like
HTML code for page goes here (if you're mixing js and html)
<script>
var items = [{% for d in data %}
{% if forloop.last %}
{{ d }}
{% else %}
{{ d }},
{% endif %}
{% endfor %}];
// code that uses items
</script>
Note there's a little bit of work required to make sure you have the right # of commas [taken from this SO answer and your code should handle the case where the array is empty.
Alternatively, you could do an ajax call from static javascript to your django server using something like django rest framework to get the list of items as a json object.
My html document will have div container which gets populated with handlebars template name 'relatedVideosTemplate' on execution.
<div id="relVideos"></div>
Below anonymous function will make ajax request and pass the data to handlebar template which loops over all items in data object to construct related videos UI.
(function(options) {
var defualt = {
defaultThumb: "/url/to/default/thumbnail/",
apiURL: '/path/to/api/url'
};
options = options || {};
options = $.extend(true, defaults, options);
// handlebars template for the related video carousel
var relatedVideosTemplate : "<h3>Related Videos</h3>" +
"<ul class=\"related-videos\">" +
"{{#foreach items}}<li class=\"video {{#if $last}} last{{/if}}\">" +
"<a href=\"/video/?videoid={{id}}\" class=\"image\">" +
"<img alt=\"{{name}}\" {{#if videoStillURL}}src=\"{{videoStillURL}}\"{{else}}src=\"{{defaultVideoThumb}}\"{{/if}} width=\"90\" height=\"75\" data-id=\"{{id}}\" onerror=\"this.src='{{defaultVideoThumb}}';\" />" +
"<span class=\"video-time\">{{length}}</span></a>" +
"<div class=\"info\"><h5>{{name}}</h5>" +
"<span class=\"published-date\">{{publishedDate}}</span>" +
"{{#if playsTotal}}<span class=\"video-views\">{{playsTotal}} views</span>{{/if}}" +
"</div></li>{{/foreach}}" +
"</ul>",
template, relVideosHTML;
$.ajax({
url: options.apiURL,
success: function(data) {
template = Handlebars.compile(relatedVideosTemplate);
relVideosHTML = template(data);
$("#relVideos").html( relVideosHTML );
}
});
});
Its very likely the video still image (thumbnail) for some videos will return 404 and in that case I use onerror event on image tag to replace it with default thumbnail.
Is there a way to pass this default thumbnal value as object to handlebars block expression template ?
I don't want to amend the data object to have 'defaultThumb' property for all items. Like below...
for ( i = 0, max = data.items.length; i < max; i++) {
// Adding new property to each item in data object
data.items[i].defaultThumb = options.defaultThumb;
};
It seems to me amending data property in above loop is non efficient as the defaultThumb is same across all videos which return 404 for still(thumb) image.
Why not set defaultVideoThumb once at the top level and then reference it as {{../defaultVideoThumb}} inside the loop? Something like this in the template:
<img
{{#if videoStillURL}}src="{{videoStillURL}}"{{else}}src="{{../defaultVideoThumb}}"{{/if}}
width="90" height="75"
onerror="this.src='{{../defaultVideoThumb}}'
>
and then in the JavaScript:
data.defaultVideoThumb = '...';
var html = template(data);
Demo: http://jsfiddle.net/ambiguous/9ecx3/
I have this template:
var template = kendo.template("<div class='relatedItemRow'>"
+ "<span id='relatedItemName'>Related Item #: Number #</span>"
+ "<div class='relatedItemRowInfo'><span >#: Name #</span>"
+ "<a data-relatedItemID='#: Value #' class='removeRelatedItem'>"
+ "<img src= '#: Img #'/</a></div><br class='clear'/></div>");
var data = {
Name: "" + checkbox.getAttribute('flatName'),
Number: $('#relatedItemsList').children().length + 1,
Img: '/Content/images/x_remove.png',
Value: checkbox.value
};
var result = template(data);
$("#relatedItemsList").append(result);
I am able to access the data-relatedItemID by using:
$('#relatedItemsList').children().eq(i).children().last().attr('data-relatedItemID')
But how do I get to the Number field in data? I want to change that one dynamically.
I have tried:
$('#relatedItemsList').children().eq(i).children().attr('Number') == 5
but it does not work. Any idea how to do that?
I know that there is an answer for this question even accepted but I'd like to suggest a different approach that I think it is much simpler and more Kendo UI oriented and is using Kendo UI ObservableObject. This allows you to update an HTML that is bound to the ObservableObject without having to crawl the HTML.
This approach is as follow:
Wrap your data definition with a Kendo Observable Array initialization.
Redefine your template and start using using data-binding.
Append this new template to your HTML.
Bind data to the HTML.
Now you can get current value using data.get("Number") or set a new value using data.set("Number", 5) and the HTML get magically updated.
The code is:
Template definition
<script type="text/kendo-template" id="template">
<div class='relatedItemRow'>
<span id='relatedItemName'>Related Item <span data-bind="text : Number"></span></span>
<div class='relatedItemRowInfo'>
<span data-bind="html : Name"></span>
<a class='removeRelatedItem' data-bind="attr: { data-relatedItemID : Value }">
<img data-bind="attr : { src : Img }"/>
</a>
</div>
<br class='clear'/>
</div>
</script>
data definition as:
var data = new kendo.data.ObservableObject({
Name: "" + checkbox.getAttribute('flatName'),
Number: $('#relatedItemsList').children().length + 1,
Img: '/Content/images/x_remove.png',
Value: checkbox.value
});
and the initialization of the HTML is:
$("#relatedItemsList").append($("#template").html());
Getting current value of Number is:
var old = data.get("Number");
Setting is:
data.set("Number", 5);
Running example in JSFiddle here : http://jsfiddle.net/OnaBai/76GWW/
The variable "result" and thus the data you're trying to change aren't a Kendo templates, they're just html created by the template, and the number is just text in the html. To modify the number without rebuilding the whole string, you need to change the template so you can select the number by itself with jQuery by putting it in it's own element, and adding something to identify it.
var template = kendo.template("<div class='relatedItemRow'><span id='relatedItemName'>Related Item <span class='relatedNumberValue'>#: Number #</span></span><div class='relatedItemRowInfo'><span >#: Name #</span><a data-relatedItemID='#: Value #' class='removeRelatedItem'><img src= '#: Img #'/</a></div><br class='clear'/></div>");
//other code the same
And once you can select it, then you can change it like this.
$('#relatedItemsList').children().eq(i).find('.relatedNumberValue').text(5);
And retrieve it like this.
var foo = $('#relatedItemsList').children().eq(i).find('.relatedNumberValue').text();