populating Moustache.js template - javascript

I am currently working with a QuickBase database trying to make a custom report using moustache.js, When I was looking into moustach.js I noticed you needed to have your data in JSON format so I used (http://pastie.org/9364908#16) to get my data into JSON which then comes out like (http://pastie.org/9364674#18)
My question is when I make the template for this, does it need to be all contained in the page that the call to get the json data is? I have looked at examples of mustache templates, but all I can find is it being used with data supplied right then made in JSON format, but my data I need is being supplied when I make the call so how would I go about setting that up.?

When working with mustache js templates (or js templates in general), you do not need to have the template be in the same location as the data being returned from the ajax call. However, you will need to have the data stored in a var that is within scope of the render function of the template. I am assuming you wish to ajax in a set of data, parse it to JSON, then at some point render that JSON data to the DOM. So to answer your questions:
1) Does the template need to be contained in the page that the JSON data is?
Not necessarily, but you will need to be able to access both parts from one locations (ie, you would ajax in both the template and the data, then put it together. Alternatively, you could store the template in the DOM as a script [recommended way unless you are using AMD], and then render the template when your ajax call is complete).
The main thing to note is you will need to have a reference to both your template and your data in the same scope.
2) Setting up the template / data ?
This can be done by using the ajax success callback: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest
So on success, you can have the function call render on your template, or just set a locally scoped variable with the data and handle the template rendering after.
3) render the template normally
var template = $('#template').html(), //script tage with id="template" from your dom
data = jsonData, //saved somewhere in a local scoped var .. maybe from an ajax call
rendered = Mustache.render(template, data),
target = $("#target"); //where the template renders to
$('#target').html(rendered);
4) render the template via $.ajax
$.ajax("/api/data", function(data){
var jsonData = $.parseJSON(data),
template = $('#template').html(), //script tage with id="template" from your dom
rendered = Mustache.render(template, jsonData),
target = $("#target"); //where the template renders to
});

Related

Update a template with Mustache js

I`m using mustache js to render a template with data from API and works nice, but i need to update (re-render) same template after a while. In my case I have a list in template like this:
template.html
<div id="template">
{{#list}}
<span>{{firstName}} {{lastName}} - {{phone}}</span>
{{/list}}
</div>
index.js
$(document).ready(function(){
$.ajax(
//some ajax here
).done(function(response){
loadTemplate(response);
});
});
function loadTemplate(data){
var template = $("#template").html();
Mustache.parse(template);
var render = Mustache.to_html(template, data);
$("#template").empty().html(render);
};
But the user can add more elements on this list, and after that I need to update the mustache template. I tried call the Ajax (that response with new value add on the list) then call loadTemplate function again but does not work, the list does not change (update) with new values.
The first time you render the template, the original mustache template gets lost.
ONLY the rendered text exists in same location. So the second time you try to re-render the template there is no template to render simply text that is NOT a template anymore so the text is simply outputed again.
The solution is to store your original template in another location (eg inside an element with id=#originalTemplate).
Then do following:
function loadTemplate(data){
var template = $("#originalTemplate").html(); // NOTE we use original template which does not get overriden
Mustache.parse(template);
var render = Mustache.to_html(template, data);
$("#template").empty().html(render);
};

AngularJS Filter Data Binding

I have a custom filter that I use to return an html string using $sce.trustAsHtml. In the template/view I use ng-bind-html directive and pass the filter to as follows:
<div ng-bind-html="userAgent | geoCode:business"></div>
Inside my filter I have an inner function that takes an input, business model in my case, which takes properties from the business model, a mongoosejs model, and generates a formatted string which is used to generate and html a tag:
'<a href="some_url_i_create" ...>'+ myFormattingInnerFunction(business) +'</a>';
What is strange is, if I use this function several of the fields are returned as undefined/blank. However, if I directly access the variables a follows:
'<a href="some_url_i_create" ...>'+ business.prop1 + business.prop2+ ... +'</a>';
Then all of the properties are found and output. Any ideas?
P.S. The model is a retrieved via an AJAX request, which in turn use mongoosejs to retrieve the data, inside of the angular controller for this section.
When you are calling the function you are accessing the business object on the first rendering event when all the scripts are loaded and the first DOM manipulation occurs.
But When you accessing the business object directly angular puts the values into the view on the first rendering event and on all of the digest events and of course on other rendering events.
You might want to consider using a $scope. attr in the template to render and call the formated string value method in the callback as well.
In the JS:
.success(function(data){
business=JSON.parse(data);//Iguess
$scope.formatedtext= myFormattingInnerFunction(business);
$scope.$apply();// If you use an angular libs callback this probably not needed.
})
In the template:
'<a href="some_url_i_create" ...>'+ formatedtext +'</a>';

Issue with getJSON within Backbone view rendering

I'm pretty new to Backbone.js, loving it so far, but I'm having a little trouble trying to get relational data to render.
Within my Backbone view (called ImagesView) I have the following code:
// Render it
render: function () {
var self = this;
// Empty the container first
self.$el.html("")
// Loop through images
self.collection.each(function(img){
// convert `img` to a JSON object
img = img.toJSON()
// Append each one
self.$el.append(self.template(img))
}, self)
}
There are 3 images in the collection, and they are templated correctly with the above code. Within the img object is a user attribute, containing the User ID. I'm trying to return the user's details, and use these within the template instead of the ID. I'm doing that using the code below:
// Render it
render: function () {
var self = this;
// Empty the container first
self.$el.html("")
// Loop through images
self.collection.each(function(img){
// convert `img` to a JSON object
img = img.toJSON()
/* New code START */
// Each img has a `user` attribute containing the userID
// We'll use this to get their details
$.getJSON('/user/' + img.user, {}, function(json, textStatus) {
img.photographer = {
id: json.id,
username: json.username,
real_name: json.real_name
}
/* Moved 1 level deeper */
// Append each one
self.$el.append(self.template(img))
});
/* New code END */
}, self)
}
When I do this, the user's details are returned correctly and inserted into the template, but I now get 3 of each image returned instead of 1 (i.e. 9 in total), in a completely random order. What am I doing wrong? I'm open to using Backbone methods instead of the getJSON if that will make it easier, I just couldn't get it to work myself. I'm using underscore.js for the templating
The random order is likely caused by the requests being fired at very close intervals and responses returning out of the order they were fired in. I'm not sure why you're getting the multiple things, but if your template renders everything and you're calling that 3 times that could be it?
Anyway where I think you're going wrong is putting the responsibility of loading data into the render method. You'd want this to be abstracted so you have a good separation between data concerns and template concerns. As the ordering of the data is of interest, you'll want all 3 requests to have loaded before rendering. There's two different approaches you could take to this depending on if prior to loading this data you have sufficient data to render the view:
If you're waiting on all the data prior to rendering the view then you would want to render a different view (or template of this view) whilst the data is loaded and then replace that with a view showing all the data once it is loaded.
If you have sufficient data to render the view and what you are loading is supplementary, you'd want to render the view with the data you have in render and then once the other data is loaded use a custom method to modify the rendered view to include your data.
If you want to find out when all 3 requests are complete you can use http://api.jquery.com/jquery.when/

Backbone.js: Access JSON returned inside an HTML fragment served over Ajax?

I'm building a web application that uses Django for the back-end, and Backbone for a user-responsive front-end.
When the user carries out a search (or loads more results for an existing search) I retrieve results via Ajax, using a partial template served by Django.
This works fine, but I'd also like to update the search filters so that the user cannot refine for querysets with zero results.
For example: if the user searches for cars between $1000-$3000, and no blue cars are available, I want to grey out the "blue" colour selector in the search form. So as well as returning the results, I also return an JSON object with the available colours.
My question is this: I know how to inject the results into an HTML element of the page, and I know how to return JSON in the template fragment. But how can I access that JSON from inside Backbone?
This is my Backbone model. It listens for search events, when it performs an Ajax request, and sets its 'results' property to the template fragment returned by Ajax:
var SearchModel = Backbone.Model.extend({ ..
performSearch: function() {
$.get(this.get("querystr"), function(html) {
self.set("results", html);
// TODO: How to extract JSON results
});
} ...
});
The template fragment returned by Django over Ajax contains both HTML and JSON:
<script type="text/javascript">
var queryset_propeties = JSON.parse('{{queryset_properties|jsonify|escapejs}}');
</script>
<ul id="results">
{% for results in results %}
<li>{{ result }}</li>
{% endfor %}
</ul>
I also have some Backbone code that listens for changes to the results property of the search model, and updates the front-end:
var SearchResultsView = Backbone.View.extend({ ...
initialize: function() {
this.model.on("change:results", this.displayResults, this);
this.render();
} ...
displayResults: function(model, results) {
this.$el.html(self.model.get('results'));
// TODO: Use queryset_properties object to update search filters?
console.log('queryset_properties', queryset_properties);
} ...
});
My problem is that the queryset_properties object is not up to date, and I don't know how to access it from inside the Backbone code.
I have thought of the following:
Make two $.get calls, one to an HTML file and one to a JSON file. I'd like to avoid this because of the extra HTTP overhead.
Only return JSON via Ajax, and use this to update all the HTML in Backbone, rather than returning the template from Django. I want to avoid this though, because by returning HTML, the Django application works for non-JS users (like search bots), which is important.
Somehow extract the JSON object from the returned HTML, and set it as a Backbone model attribute that I can then use in the usual way - but how to do this, short of using a regex or something equally messy?
Any ideas?
My question is this: I know how to inject the results into an HTML
element of the page, and I know how to return JSON in the template
fragment. But how can I access that JSON from inside Backbone?
Instead of having those $.get requests, use Backbone fetch. It has the appropriate success, and error callbacks just like jQuery's $.get.
In order to do it the Backbone way, first you have to set up your model's URL:
var SearchModel = Backbone.Model.extend({
url: this.get("querystr")
});
after initializing your model call fetch:
var sm = new SearchModel({querystr: "http://example.com?car"});
sm.fetch({ // calls model's url
success: function (model) {
// you can access the returned json object here by doing:
model.get('price'); // assuming your json looks like { price: 500 }
},
error: function (model) {
}
});
Documentation
Short tutorials

How do I serialize data from non-form elements and make it accessable from params[:model]

I have a Sinatra app which loads information from an external API and displays it on a page. This is done in Sinatra which gets the information and puts it a temporary model instance (which is NOT saved), so it is easier to access all its propertys in the view.
Now when the user clicks a link I want the model instance to be saved to the database, which I think only can be done via AJAX etc. because the last request already finished and none of the instances is still alive. I thought I needed to extract all the information of the corresponding HTML elements and make an AJAX-Post to another route.
My problem is now, I want to be able to create(and save) the model using #model = Model.create(params[:model]). It would be clear what to do using a form, but that is not an option because all the data is displayed within a table and each table row is one instance of the model.
How do I serialize the data from the table row in which the clicked link is, so I can use it as described above?
UPDATE
I am using MULTIPLE instances of the object class, each in one tablerow!
I am using DataMapper, only the temporary objects are not stored!
I dont want to clutter up my whole setup!
Did you consider ActiveResource? You can use ActiveResource to maintain object state. If your REST API follows convention it would be very easy to map resource.
Regarding second half sending back data to your controller, you could store in hidden variable(s) and on post it should be easy to construct back the object and persist it to database.
Something like
#model
class MyModel < ActiveResource::Base
# set configs here
end
# To fetch record from REST API in controller or whatever
MyModel.find(1)
#in controller on form submit or AJAX
post "/path" do
MyModel.new(params[:myModel])
end
Update
To maintain state of object without using hidden form
in javascript you can have something like
var myModel = #{myModel.to_json}; #Ruby interpolation in HAML it will depend on templating language
on certain action you can update the JSON object
and to post using AJAX
$.post("post/path", myModel);
More Update
In External JS
function my_js_function(obj) {
/* do something useful here like setting up object hash etc
*/
}
In Ruby Template
<script>
var myObj = #{myObj.json}
my_js_function(myObj);
</script>
I found a pretty easy solution. It was nothing more than getting all the required values from the DOM and putting them into an Array!
application.js:
$(".enable").click(function() {
var table_row = $(this).closest("tr");
var model_array = new Array;
var elements_with_information = jRow.find("[name]");
elements_with_information.each(function() {
// Doing some checking on which kind of element
// it actually is and then basically doing:
model_array.push($(this).text());
});
// Constructing nested array to use `params[:model]`
var data = { "model" : {
"property1": model_array[0],
"property2": model_array[1]
}};
// Now doing the AJAX request
$.ajax({
url: "/model/doshit",
type: "POST",
data: data
});
});

Categories