Where to put a particular template helper - javascript

I have a pageTitle template variable that is in the header element () of each section of my site, and I would like it to be dynamic, rather than hard-coded, so site maintenance is easier.
Using Meteor (I'm currently reading Discover Meteor), would it be best to put it in a Session variable, and then return the value from a Template helper (i.e. as in the example in the Session chapter of Discover Meteor), or is there an Atmosphere package that would handle this better?
Also, if I do put it in a Template helper, I'm a little fuzzy about where is the appropriate file in which to put the helper. That is, if I have a .js file for (almost) every template (because I'm following along with the book), would I really need to put the same helper code that returns the pageTitle variable from the Session in each template's .js file?
It seems inefficient to have so many redundancies, but if I had a single instance of that Template.templateName.helper() code, I'm not sure where to put it.
Any help is much appreciated. Thanks!

I'd put it inside a global helper. You can use Template.registerHelper for that. I usually put these helpers inside client/helpers/global.js. I'm not sure why you would want to use a session variable for this. But here's a simple example of how this helper could look like:
client/helpers/global.js
Template.registerHelper('setPageTitle', function (newTitle) {
document.title = newTitle
})
Usage:
{{ setPageTitle 'Hi' }}

I'm also fairly new to Meteor, but it looks like you could use the Observe Collection from the docs - http://docs.meteor.com/#/full/observe and have a collection with your pageTitles in it.
So it would be something like
document.title = yourCursor.observe(function({
changed: function(id, field){return field.pageTitle}
})
As for location, anywhere on the client side should work.
Not sure if this is best way to do it, but hope it helps!

Related

pathFor for iron router meteor

I am pretty confused about this issue.
I have template which has two paths as follows:
Router.route('/companyDataManagement',{
path:['/companyDataManagement','/companyDataManagement/:_id'],
name: 'companyDataManagement',
yieldTemplates:{
'companyData':{to:'showCompanyData'},
'companyDetails':{to:'showCompanyDetails'}
}
});
This works perfectly fine. But how do I use pathFor for this template.
Click does not work
Can you confirm if the companyDataManagement in the link is a name being passed from a helper or if you intend this to be the name of the route called? if it is the latter it needs to be encapsulated in single quotation marks like below
Click
If you want to then pass the :_id into the pathFor this comes from the data context which the link is in, if the data context does not supply the id you need to declare an object to pass into the template inside a helper:
Template.yourTemplate.helpers({
myContextHelper: function(){
return {_id:'XXXXXXXXX'}
}
});
{{#with myContextHelper}}
Click
{{/with}}
Which should give you /companyDataManagement/XXXXXXXXX
You can also pass in the query, hash and data variables using for example query="q=1" or query=qstring where qstring is an object from a helper or a field in the myContextHelper object.
Click
Additionally and not strictly to do with the question but is hopefully helpful, it looks from your code like you are just having the :id as an optional route part in your path and that the templates themselves do not require an :_id to be specified, in which case you can just use a ? to make the part optional:
path:'/companyDataManagement/:_id?',
You can also use this for your opening argument for the route to eliminate having to specify the path in the function:
Router.route('/companyDataManagement/:_id?',{
Hope this helps! Let me know if the above doesn't work happy to help troubleshoot if you can post a bit more of the code surrounding it

Bindings on self-written HandlebarsHelper?

i am trying add internationalization-abilities to my website.
I have written my own I18n.js which uses translation-objects out of the DS.store instead of its own (so there is a translation model and Ember preloads it on Application-start).
To get my translations into the Templates i have written this handlebars-helper
Ember.Handlebars.registerHelper('i18n', function(key) {
return Application.I18n.t(key);
});
so i could easily use it like:
{{i18n example_key}}
So far, everything works just perfect.
But the translations visible on screen are not bind to its translation-models.
If i change a translation in the administration-page which is places there too, i have to reload the page.
is it possible to add bindings between the helper and the translation model the helper have to display?
Thanks
Use registerBoundHelper instead of registerHelper. I don't even think registerHelper is part of the public API.
What does Application.I18n look like exactly? In order to make the {{i18n}} helper refresh its content when something changes, it needs to observe something that is observable.
Ember.Handlebars.helper is useful if you pass an object with observable properties (see http://emberjs.com/guides/templates/writing-helpers/#toc_dependencies). But if you only pass a key as a string, you'll have to set up the binding yourself in some way.

Change / unregister Handlebars helper (Meteor)

Once I register a helper function for Handlebars using Handlebars.registerHelper(), is it possible for me to change and/or remove the helper? Can I just use registerHelper() again to overwrite the current helper, or is there such a thing as Handlebars.unregisterHelper()? Or should I use a different approach if I need a helper to change during an application?
The use case for me is with the Iron Router plugin for Meteor. I am using a layoutTemplate as the general structure of my page. I wanted to use a helper in the layout template right before I yield the main content of the page body (via a <template>, per se) so that each individual template can define its own page title but not have to specify the location in the page every time. For example, my layout template could look like this:
{{pageTitle}}
{{yield}}
And then in the .js file for the rendered template, I would use the following to fill in the {{pageTitle}} placeholder:
Handlebars.registerHelper("pageTitle", function() {
return "My Page Title";
};
Perhaps there is an alternative way to solve this problem.
What you can do is something like this
Handlebars.registerHelper("pageTitle", function() {
return Session.get('pt');
};
function changePageTitle(str){
Session.set('pt', str);
}
Meteor, being reactive, should update the page when a session variable changes. When you switch to another page, simply run changePageTitle.

Play 2.x: How to use two jsRoutes files in one scala template

I'm using jsRoutes in my Play 2.1.x app. Part of my routes file looks the following way:
GET /assets/template/js/routes/admin.js controllers.Admin.jsRoutes
GET /assets/template/js/routes/salonManagement.js controllers.SalonManagement.jsRoutes
And I would like to use both references in my scala template (that is by design, one controller contains necessary api functions, the other one necessary form submission urls).
So in my scala template I have the following part:
<script type="text/javascript" src="#routes.Admin.jsRoutes()"></script>
<script type="text/javascript" src="#routes.SalonManagement.jsRoutes()"></script>
Unfortunately, each generated javascript file starts with var jsRoutes = {};. Therefore, #routes.SalonManagement.jsRoutes() overrides properties of #routes.Admin.jsRoutes() and I can use only the last jsRoutes object.
Now, I know only one workaround. After each jsRoutes declaration I can insert a script that copies old jsRoutes object to a temporary object and then extends new jsRoutes with itself. But that doesn't look like the right way to go.
Isn't there any better way?
There's nothing special about the "jsRoutes" name. You can keep the same method name for consistency among the various controllers, but just pass a different name to the Routes.javascriptRouter method.
Put this in your template. I put it in a main template that wraps the other pages.
<script src="#controllers.routes.Application.jsRoutes()" type="text/javascript"></script>
and put this in your routes file
#jsroutes for ajax calls
GET /assets/js/routes controllers.Application.jsRoutes()
And then in your Application controller, refer to whatever method in whatever controller you want by implementing this method
public Result jsRoutes()
{
response().setContentType("text/javascript");
return ok(Routes.javascriptRouter("jsRoutes",
routes.javascript.Signup.forgotPassword(),
routes.javascript.Customers.findByName(),
routes.javascript.Customers.findByNumber()
));
}
These correspond with routes like
GET /customerfind/:name controllers.Customers.findByName(name: String)
Note there is no need to include parameters for the calls configured in the jsroutes method. Keeping all of this in one place, the Application controller, seems reasonable as long as it refers to methods implemented in their appropriate controller. Like in this example, a find on customer is in the Customers controller. Also, is kindof nice just having to check the one controller (Application) to see all the methods available through javascript routes for ajax calls.

Where does data returned by ember-data 'live'?

ya'll I have a bit of a structural/procedural question for ya.
So I have a pretty simple ember app, trying to use ember-data and I'm just not sure if I'm 'doing it right'. So the user hits my index template, I grab their location coordinates and encode a hash of it (that part works). Then on my server I have a db that stores 'tiles' named after there hash'd coords (if i hit my #/tiles/H1A2S3H4E5D route I get back properly formatted JSON).
What I would like to happen next, if to display each of the returned tiles to the user on the bottom of the first page (like in a partial maybe? if handlebars does that).
I have a DS.Model for the tiles, if I hard code the Hash'd cords into a App.find(H1A2S3H4E5D); I can see my server properly responding to the query. However, I cannot seem to be able to figure out how to access the returned JSON object, or how to display it to the user.
I did watch a few tutorial videos but they all seem to be outdated with the old router.
Mainly I would like to know:
1. Where does the information returned by App.find(); live & how to access it?
2. what is the 'correct' way to structure my templates/views to handle this?
3. how should I pass that id (the hash'd coords) to App.find? as a global variable? or is there a better way?
the biggest problem(to me) seems to be that the id I search by doesn't exist until the user hit the page tho first time. (since its dynamically generated) so I can't just grab it when the page loads.
I can post a fiddle if required, but I'm looking for more of a conceptual/instructional answer rather then some one to just write my code for me
I'm still learning a lot with Ember as well, but this is my understanding. When you follow the guides and the tutorials out there, you'll have something like this:
App.TileController = Ember.ObjectController.extend();
App.TileRoute = Ember.Route.extend({
setupController: function(controller) {
controller.set('content', App.Tile.find(MYHASH));
}
});
What it does is set the special content object to the result. So since we're declaring an object controller, and calling find with a parameter, it knows that a single result is expected. So a view & template that follow the naming convention of Tile will be loaded. And in there you can access properties on the Tile object:
<p>{{lat}}</p><p>{{lng}}</p>
I have to admit that this feels a bit mystical at times. The core to it is all in the naming convention. You need to be pretty specific in how you name all your various controllers, routes, etc. Once that's nailed down, it's a matter of binding what data you want to the controller's content.
1) Aside from the generic answer of "in memory", the .find() calls live where ever you return it to. Generally speaking, this is meant to be set on a 'content' property of a controller.
2) I more or less answered this, but generally speaking you take the name of your route, and base it off that. So for a route TileRoute, you have:
TileController = Ember.ObjectController.extend
Tile = DS.Model.extend
TileView = Ember.View.extend
tile.handlebars
I generally store all my handlebars files in a templates/ folder. If you nest them deeper, just specify the path in your view object:
App.TileView = Ember.View.extend({
templateName: "tiles/show"
});
3) This really depends on your app. Generally speaking its better for the id to be either obtained from the URL, or constructed locally in a function. Since you are encoding a hash, i imagine you're doing this in a function, and then calling find. I do something a bit similar for an Array controller.
I don't know at what point you are generating a hash, so let's say it's onload. You should be able to generate the hash just in the setupController function.
App.TileRoute = Ember.Route.extend({
generateHashBasedOnCoords: function() {
// ...
},
setupController: function(controller) {
var MYHASH = this.generateHashBasedOnCoords();
controller.set('content', App.Tile.find(MYHASH));
}
});
I hope that helps.
I believe that you can make use of the data binding in ember and basically have an array controller for tiles and set the content initially to an empty array. Then we you get back your response do a App.find() and set the content of the tiles controller with the data that is returned. This should update the view through the data binding. (Very high level response)
The data itself is stored in a store that is setup with ember data. You access it with the same method you are using the model methods App.Tile.find() ect. It checks to see if the data that is needed is in the store if so it returns the data otherwise it makes a call to the api to get the data.

Categories