Following up on this queston/answer (second answer) Dynamically loading templates in Meteor.js
I have set up a helper in the current displayed template and i am returning the template dynamically. This works great.
Template.template1.helpers({
dynamicView: function(){
return Template['dynamic_template']();
}
})
This ends up showing my html in template 1:
Questions:
How do i pass data to this Template as it's being created, can i do something like this:
Template['dynamic_template'](data1, jsonData2);
I want the dynamicView helper in template1 to also be dynamic in the sense that it can have a different template based on some other criteria. Can i use a Session here and change the dynamicView return statement to something like this:
dynamicView: function(){
return Session.get('dynamicTemplate');
}
and somewhere else Session.set('dynamicTemplate', Template['dynamic_template']()); This works, but is it recommended. It's just a string but i am concerned about performance problems and the size of my template being passed reactively
OK I guess ill have to split my answer up:
With 1.
The templates are compiled handlebars templates so you just need to provide a context to them so the handlebars data can be filled up:
data = {name1:value1, name2:value2}
return Template['dynamic_template'](data);
So that {{name1}} and {{name2}} get filled up with value1 and value2 respectively.
With 2.
Yes that should work, you can pass off any data that will give off HTML as a result. For a very detailed videocast have a look at the EventedMind screencast on template functions: http://www.eventedmind.com/posts/meteor-rendering-template-functions
The template system's use case might not be this exactly. You might want to use Meteor.render instead, but it depends on what you want to do.
Despite the Session name, its just a reactive javascript variable so it should be fine with larger strings too to the same that would be used in an ordinary javascript variable
Related
I'm programming in oTree (which is a Django based environment for social experiments) and I have the following problem. I defined some lists in Python and I'd like to import them and use them in an HTML template. If I print them in HTML I manage to see them without any problem, however, once I need to use them in Javascript, the program fails to read them and the single quotes of the elements of the list are converted in '.
The list is imported like this var filtered_elements = {{ array }};.
I think the problem is exactly here, as JS cannot work with them. Do you have any suggestion on how to do that? I considered using JSON, but since I'm quite new to programming, I cannot understand if it's just a waste of time or there is a simpler way out.
Thanks for your answers!
It sounds like your data is already JSON, otherwise you would be getting single quotes and u prefixes. So the only issue is Django autoescaping; you can disable it with the safe filter:
var filtered_elements = {{ array|safe }};
Your data should be JSON, instead of putting the Python list into the contact directly, put "array": json.dumps(array) in the context dictionary.
The JSON string doesn't need HTML escaping inside a tag, but it does need JS escaping! Otherwise some string may include something like </script><script>absolutely anything goes here... to run arbitrary JavaScript, if the JSON contains user data.
So use |escapejs:
var filtered_elements = {{ array|escapejs}};
I have an array of JSON objects being passed from my Node route into its respective view. For example:
res.render("path/to/view", { data: result, data2: result2 })
where both result and result2 are arrays of JSON objects. In my view, I am using them in an ng-init function like so: ( {{}} designates swig, where I have changed [[]] to designate Angular, so in the below example, we are using swig before using my defined Angular init function)
<div ng-init="init( {{ data|json }} )"> </div>
I should say that the above example works fine, but when "data" becomes a very large dataset, SO much time is spend on the swig part - that is converting it to JSON (again..?). Like I said, the "data" is already in the form of JSON, but when I remove the |json from the swig part above, I get a [$parse:syntax] error, and it give me the above line but evaluated:
<div ng-init="init( [object Object],[object Object] )"> </div>
I have tried variations of using ng-init="init( [[ JSON.parse( {{ data }} ) ]] )" so that I evaluate the output to JSON (even though the output already is..?) but cant get anything to work.
Any ideas? Maybe I have the syntax wrong? I don't understand because the "data" is JSON when I pass it to the view, but I can't pass it directly into my init function without getting that syntax error.
Take whatever you're calling with ng-init out of your view and put it in a controller or service.
There are tons of reasons not to use ng-init, so much so that the Angular team basically recommends you don't use it: https://docs.angularjs.org/api/ng/directive/ngInit
Update
I finally think I see what you're trying to do, and it's called bootstrapping. You can embed data into your view server-side like so:
<script>
angular.module("app").constant("myBootstrap", {{ data.stringified }});
</script>
Where data.stringified is your stringified data. Then in Angular you can inject into any controllers you want as a constant with myBootstrap, same as you would for $rootScope, etc., and the data will be available.
So while I am not entirely sure what was causing it to go so slow, I have found a solution, although 'hack' might more accurately describe it. The problem I was having was with Swig taking ages to template my data before passing it into the init function (which I now know is bad practice; that is, to use ng-init to call a function).
I should note for future readers that I am using Node.js, Swig for templating, and Angular for handling the the MVC side of things.
See the above question to see what my code was like before (slow version). Below is my solution:
Routing side
var rawSQLData = makeSQLCall();
var parsedAsJsonSQLData = parseData(rawSQLData);
var parsedDataAsString = JSON.stringify(parsedAsJsonSQLData);
res.render("path/to/view", { data: parsedDataAsString });
HTML
<div ng-init=" init( {{ data|json }} )"> </div>
Angular Controller
$scope.init = function(data){
$scope.dataInScope = JSON.parse(data);
}
As you can see, the only thing I changed was stringifying the JSON before shooting it to the HTML and then parsing it once it gets to the controller.
The reason I think this works is because I am essentially doing all of the JSON processing in parts other than the templating engine (Swig). I tried using no filter, but Swig defaults to converting the data to JSON which was breaking my HTML. The reason that I want to call this a hack rather than a solution is because we stringify the data, and then use the json filter for Swig, which, according to the documentation:
Return a string representation of an JavaScript object.
If I had to guess, I would say that by using the json filter on a string, Swig decides it has nothing to do as the object is already a string and just passes it along (just what I wanted all along!). It is incredible how much faster it is when Swig doesn't touch the data. The JSON stringify and parse are really quick for the size of data, while Swig was taking up to 40 seconds
The question may be a little ambiguous. Added a JsBin example below.
http://emberjs.jsbin.com/julimila/4/
I have two questions.
ONE:
As you can see in the example, for some reason Ember doesn't like properties starting with uppercase characters. In the example, Subject doesn't get rendered but subjectInLowercase does.
The API that I request data from always send data in this uppercase notation and I have no control over it. Currently I'm working around this by passing the data to a method that converts all the properties to camelCase. Fortunately, the server doesn't care if I send the data back in camelCase. How do I fix this?
TWO:
I need to modify some properties in the data before rendering them. In the example, I added a new property called formattedDate. This is the modified version of the Timestamp field. I usually use a Handlebars helper to do this formatting but this time, it is an input field. I don't want this formattedDate property going back to the server when the model is updated. Is there any better way than updating their relevant properties in the model and then manually deleting these extra fields.
You can put your format date logic in the controller since controller is a proxy for model.
App.IndexController = Ember.ObjectController.extend({
getFormattedDate: function(){
return moment(this.get('model.Timestamp')).format('DD/MM/YYYY');
}.property('id'),
actions: {
updateForm: function() {
var data = this.get('model');
console.log(data);
// Post this model back to the server
}
}
});
And in the view use
Formatted Date: {{input value=getFormattedDate}}
Ok so I have a template in Play! that receives a List as a parameter:
#(actions : List[RecipientAction])
RecipientAction is just a regular case class with a couple of fields. Within the template, I have a <script> tag where I want to use D3 to make a line chart. Inside the script I want to populate a JavaScript array with objects that contain the properties stored in RecipientAction in order to use them for my line chart later. I currently have this code:
testArray2=[];
for(var i=0; i < #actions.length;i++){
testArray2[i]= {};
testArray2[i].eventAt= #actions(i).eventAt.toString();
testArray2[i].action= #actions(i).action.id;
}
When i run it, i get the error "not found: value i". This is because i is a client side variable while actions is a server side variable, so scala cannot find i. What would be the best way to work around this and successfully populate the array?
You need to create a JSON serializer for your RecipientAction, then you'll just be able to print the list as JSON in the template. Say it looks something like this..
import play.api.libs.json._
case class RecipientAction(id: Int, description: String)
object RecipientAction {
// Define a `Writes` for `RecipientAction`
implicit val writes: Writes[RecipientAction] = Json.writes[RecipientAction]
}
I used one of the JSON macros included with Play that will automatically create a Writes for a case class, since all we care about is printing the list.
Then in your template:
#(actions : List[RecipientAction])
#import play.api.libs.json.Json
<script type="text/javascript">
var testArray = #Html(Json.stringify(Json.toJson(actions)));
</script>
The definition of an implicit Writes is required so that Json.toJson knows how to convert the class to JSON. For more about Json serialization/deserialization see the documentation.
I'm creating website with lots of AJAX logic. I started to wondering should I return JSON with object model (because I have to make some requests and then replace/insert some html nodes in response) like:
{ 'Author' : 'Name#Surname', 'Email': 'some#email', 'listOfSomething' = [...], ...} //very advanced JSON
and then use some js template engine to parse my object and insert in the right place in the DOM
OR
return JSON with parsed razor template so something like:
{listOfSomething: [{id:0, parsedView:ASP.NET.ParseViewWithModel(MyModel[0])},{id:1, parsedView:ASP.NET.ParseViewWithModel(MyModel[1])}, ... ]}
the pros of second choice is that it will require much less logic but. Which approach should be use and when? Is the second approach may be good solution?
If what is being returned is only used in one place, then I would say option two is a good approach since you can tailor the HTML specifically for where it is going to be used and all you have to do is simply inject it into the DOM.
Otherwise, if what the AJAX returns is used in multiple places, then I would stick to returning JSON and let each client do what it needs with the raw data.
Also, if third-party developers are using it, then JSON is definitely the way to go.