I'm currently reusing a template to populate a list using the code below:
<li>
{% include "ding/search_result.html" with title=field.title url=field.url description=field.description %}
</li>
When new data comes in, I want to be able to add new elements to my list dynamically from javascript. I can use the code below to add new list items:
$("ul.search-results-list").append('<li>New List Item</li>')
Is there a way for me to append the reusable template code I'm using, and pass in the appropriate parameters?
Yes there is! AND you get to refactor your APIs as well.
Imagine that you have an API that returns this json blob for every new list item.
{
name: "limelights"
}
And let's just use jQuery for this (even though I kinda don't want to.)
So you query the API like this
$.getJSON('api/v1/getName.json', {'someParameter', 123}, function() {
//this is where you would do your rendering then.
});
So how to do the rendering? Well, I'm a huge fan of underscore.js and it's rendering of templates, so I'm gonna go ahead and use that (but you can exchange it for Mustasche, Handlebars, Hogan or whatever you fancy).
First, we'll define a script template like this: (We're using underscore.js own ERB style template language).
<script type="text/template" id="my_fancy_list">
<li><%= name %></li>
</script>
Now this can live pretty much anywhere, either in your template or you can require it in if you're using Require.JS but we're gonna assume that it lives in your template (Hint: it could be rendered by some Django template tag)
Anyhoo,
Fill this template with data now:
var template = _.template($('script#my_fancy_list').html());
//this will give you the template as a javascript function.
//Query the API
$.getJSON('api/v1/getName.json', {'startsWith': 'l'}, function(data) {
$('ul.search-results-list').append(template(data));
});
And presto, you now have an JavaScript driven application that renders new data that comes from the server without fetching the entire template and render it all again.
Related
I am new-ish to jade templates and some of the more complex feature that exist in the templates. As of right now, I am building a mock portfolio site using node and jade. I have a layout that is inherited by all other jade files. The layout has all of the universal site navigation inside of it. I am wanting to highlight what section of the website the user is currently in. I am currently doing this by having a unique js files that will load when the user is in a particular section. This js file will add a class on to the list item in which will add the highlighting to the navigation.
My question, do I need to create and load these js files in order to accomplish this? Is there a better way to get a universal navigation in one template while having a unique highlighter?
If the highlighting does not have functional purposes (e.g. accessibility), or it's done using URI fragments (hashtags), it might be better to leave it to the JS.
If your navigation highlight is per page, you could set it up in nodejs/jade, for example:
app.get('/about', (req, res) => {
var locals = {};
locals.navHighlight = 'about';
res.render('about', locals);
});
And in your jade template you could do something like this:
ul.navigation
li(class=(navHighlight=== 'about' ? 'highlight' : '')) About Me
li(class=(navHighlight=== 'blog' ? 'highlight' : '')) My Blog
Whatever you pass as properties to the locals object of res.render, is available in Jade as variables. And in jade, when using the tag(attr=value, attr2=value,...) format you have access to JS syntax and the exposed variables.
As long as you set a variable (e.g. navHighlight based on which route it enters, you can use that to set the class attribute of the tag. Just make sure to separate the class names with spaces, if you have multiple classes.
I'm trying to load in partials from a separate file while using mustache.js but it's proven difficult. The PHP implementation makes this very easy, but not so much in the JS side.
I've gone through the docs and can't find anything related to this, only using an object as a partial instead of a file.
Here's some sort of psuedocode to explain what I'm trying to do.
$.Mustache.load('/mustaches.php', function () {
var item = { thing: 'one' };
var partial = 'partials/actions.mustache';
$('.container').mustache(
'main_mustache',
{item: item},
partial
);
});
So, I'd like to be able to load a secondary file as a partial an include it with the template to be used so I don't have to duplicate code across all the different templates I use.
With something like Blaze I can import a template with {{> templateName}} but it doesn't seem to be quite so easy with Mustache.js.
If this isn't possible with Mustache, what other libraries would you recommend?
You could load both templates with mustache, and then pass one of them (the partial) to the one that should render the partial. Be aware that in order to make it work, in the mustache where you want to render the partial, the variable name should be enclosed in triple curly bracers in order to tell mustache that it should be html:
<div>
<h1>This is my title</h1>
{{{partial}}}
</div>
and then:
$('.container').mustache(
'main_mustache',
{item: item, partial: partial},
);
(EDIT: I've changed this question because of some confusion and it's maybe a duplicate now and current answers may not make sense, sorry for that)
Many modern js libraries, e.g angularjs, emberjs, reactjs, ractivejs, riotjs, use a similar pattern. Which is specify container, define a template, get some data that fits with template and then render HTML in the container using the template and data.
This will give you an empty container on first page load before the javascript does its magic, not very search engine friendly. I know about some tools to get around this problems e.g https://prerender.io/
I'm using .net mvc and for ReactJS I've found this solution http://reactjs.net/guides/server-side-rendering.html "pre-render the initial state of your React components server-side" and I guess that solves the problem for reactjs.
Are there similar solutions for other js libraries? or is this not an big issue since those libraries are supposed to be used only for SPA?
(I've had a quick look at flight.js as well which may be a better fit for me http://flightjs.github.io/ )
Yes you can simply have your model serialized out as json within javascript.
Render your views the same way as you would with the MVVM of your choice.
To render the view model use this approach:
var data = #Html.Raw(Json.Encode(Model));
With your example this would become:
var sampleComments = #Html.Raw(Json.Encode(Model));
var ractive = new Ractive({
el: example,
data: {
comments: sampleComments
}
});
If you were to use knockout, you could then do the following:
var data = #Html.Raw(Json.Encode(Model));
var viewModel = new AViewModel(data);
ko.applyBindings(viewModel);
Then you would use standard ko bindings on the page.
In order to get two way binding in knockout I simply make sure that the naming convention of the properties match.
As an example in a collection index them to keep the model binder happy i.e.
<tbody data-bind="foreach: Comments">
<tr>
<td><input data-bind="attr: { name: 'Comments[' + $index() + '].Author' }, value: Author" /></td>
<td><input data-bind="attr: { name: 'Comments[' + $index() + '].Content' }, value: Content" /></td>
</tr>
</tbody>
No it does not make sense.. :)
Ractive needs to have a template and the data to do some looping. It can't generate data/template from a given content.
But as mentioned above, you can put all the data in a js variabel, and do the rendering with that. I don't think that your users will experience any 'speedbumps' with that approach.
Actually you will download less bytes from the server, as you only download the template once instead of for each line.
This is fairly complex, so please bear with me.
Let me first say that I am very new to MVC. My experience in even the basics are minimal, but my overall development experience with .NET/C# is extensive. Point being, the solution may be simple and I just do not know it lol.
Now.. We have a massive app that uses "EditorTemplates" (Partial views) via #Html.EditorFor() rendering in order to render customized UI elements based on database content as needed.
Now... I was tasked with creating one of these elements, and due to the complexity of our system and how long it takes to load it just to test, I decided to first develop my UI/Logic in its own standalone view/controller.
The view consisted of 3 cascading Kendo dropdownlists which pull data from a method in the controller (which returns a list of class objects).
I got this working beautifully in a standalone view/controller.
Now... I ported the HTML and logic from the controller in to the partial view files in our "EditorTemplates" folder, and ran our app for the first time.
Immediately I get a javascript error
"filterRabu2" is not defined.
Here is the associated code:
<label for="rabu2">Rabu2:</label>
#(Html.Kendo().DropDownList()
.Name("rabu2")
.HtmlAttributes(new { style = "width:300px" })
.OptionLabel("Select ...")
.DataTextField("Name")
.DataValueField("ID")
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetRabu2", "Datasets")
.Data("filterRabu2");
})
.ServerFiltering(true);
})
//.Enable(false)
.AutoBind(false)
.CascadeFrom("rabu1")
)
<script>
function filterRabu2() {
return {
rabu1: $("#rabu1").val()
};
}
</script>
Now... I got rid of that error by moving that function to a .js file that was already being included in the page.
But... when the dropdownlists render, the first one (which should be enabled and with data present), it appears to be disabled and is not clickable. I confirmed that our data access routine is being hit and returning a valid and populated list of data, just as it did (working) in the standalone view.
That's where I'm at... I can't get the DDLs to function, and the existence of that JS error leads me to theorize that JS is not being rendered or allowed to execute properly? I have no idea.
This is being rendered via the #Html.EditorFor() method from another partial view inside a loop which renders templates for data based on that data... it's quite complex... but I could really use a hand at figuring out whats going on.
It could be that the dom is rendering before the the javascript has executed. Try wapping the calling method up in a
$(document).ready(
function(){
//initial method call here
});
This will ensure that the javascript executes after the dom has loaded.
My web server returns a page with some structured markup. I need to use knockoutJS to have a markup representation at hand as a JSON object - knockout view model object.
The page basically has (right after initial loading) a <div data-bind="foreach: ExistingNamings"> that has several enclosed divs that actually hold stuff that supposed to go into the ExistingNamings array on the view model object.
Can knockout "parse" and existing markup and populate view model based on the markup provided at the moment of calling ko.applyBindings?
A tutorial on KNJS shows the opposite - we have a data generation code in JS, and that gets pushed into an html upon applyBindings call.
P.S. My server side is ASP.NET MVC, and I've seen people suggesting http://knockoutmvc.com/ - an approach to generate initialization code for js file. This way it is "as if" view model is initialized via javascript. Is this the only way of dealing with initial data, or I indeed can parse markup?
You can directly serialize your C# models into JSON using razor like this:
var serverModel = #Html.Raw(Json.Encode(Model));
or, obviously:
var serverProperty = #Html.Raw(Json.Encode(Model.Property));
The only time this fails is when you have circular references, which can happen if you are dropping your Entity models directly in. If you are doing this, make a ViewModel for them, to eliminate the circular navigation properties.
Update:
To get this into your viewModel, add this to the bottom of your Razor View:
<script type="text/javascript">
var serverModel = #Html.Raw(Json.Encode(Model));
//Define KO viewModel, either here, or by including via script tag in header
ko.applyBinding(new ViewModel(serverModel));
</script>