Change / unregister Handlebars helper (Meteor) - javascript

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.

Related

Where to put a particular template helper

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!

Pass another controller when instantiating a fragment in SAPUI5

In the SAPUI5 / OpenUI5 xmlfragment documentation the third parameter is a controller for handling actions from the fragment.
This is critical for a dialog fragment where there are buttons to press etc.
Most of the time I have seen this instantiated as this or sap.ui.getCore().byId('<element>').getController())
See an example at Fragment not get correct Controller
Because of the complexity in a particular dialog I would like to have a separate controller for it.
I have looked around at this and had a few attempts but so far not successful.
I have put a working example on github of using this.
But I would like to instantiate Dialog.js as the controller for the Dialog.fragment.xml from initial.view.controller
Any takers?
Pull requests gladly received.
The Crux of the example is as follows (this is the initial.controller.js) :
sap.ui.controller("sc.test.view.initial", {
oDialog: null,
openTestDialog: function(){
console.log("in open dialog");
// instantiate the other controller
var oDialogController = new sc.test.view.Dialog();
// this next commented line is the 'normal' way to do it
// oDialog = new sap.ui.xmlfragment( "sc.test.view.Dialog", this); //oDialogController);
// this is what I would like to achieve
oDialog = new sap.ui.xmlfragment( "sc.test.view.Dialog", oDialogController);
oDialog.open();
},
onCartDialogCancel:function(oEvent){
// this function would then be in the other controller but how to get a handle on the dialog?
oDialog.close();
}
});
Thanks.
(Just got to SYD airport)
All you're missing is the
jQuery.sap.require("sc.test.view.Dialog");
in your initial.controller.js.
Pushed a quick fix in a branch to your repo and opened a PR
only example i could find close to yours was in the Material Shortage Fiori app
oCtrl = sap.ui.controller("myapp.fragments.DirectCallDialog");
oDirectCallDialog = sap.ui.xmlfragment("myapp.fragments.DirectCallDialog", oCtrl);
lots of examples of injecting a controller when the fragment was called from a helper class. The helper class promotes reuse, eg same dialog fragment can be called from multiple views/components. The helper class method for the dialog setup is called from within a controller and the oController parameter is set to 'this'.
hth
jsp
I copied an existing controller.js, and renamed it.
Then, instantiated that as a below, and passed it through with the fragment.
var oNewController = new sap.ui.core.mvc.Controller("myProject.DialogController");
this._oDialog = sap.ui.xmlfragment("myPopup","myProject.fragments.myPopup", oNewController);
All eventing is now handled in oNewController, rather than the previously used "this"...

How to trigger function after render template

I am using marionette in my application. I am showing ItemView through regions like in the following.
var productInfoViewObj=new productInfoView.ProductInfoView({model:tagInformationModel.tagInformationModelObj});
exports.MyApp.bodyContainer.show(productInfoViewObj);
This is the code, I written inside view.
exports.ProductInfoView=Backbone.Marionette.ItemView.extend({
domInfo:{
mainTemplateId:"tagProductListTpl",
tableTemplateId:"taginfoViewTpl",
tableContentDiv:"taginfoViewDiv",
//tad Info
tagInfoTabId:"tagInfoBtn",
productInfoTabId:"productInfoBtn"
},
template:function(){
return commonFunctions.templateCompilation("tagProductListTpl","");
},
onRender:function(){
console.log(document.getElementById("productInfoBtn"));
}
});
I am passing templateId and data as arguments to commonFunctions.templateCompilation. It will compile and return compiled string. That compiled result passing to template.
As per my assumption, after completion of template, onRender function will trigger. What I mean before onRender, dom will available whatever we are templating using template.
But I am getting null inside onRender function.
I want a callback, it should trigger after template available in dom. so I can access elements whatever I templated using template.
I can do one thing, whatever I written inside onRender, I can setup time like in the following way.
onRender:function(){
setTimeout(function(){console.log(document.getElementById("productInfoBtn"));},1000);
}
If I set time, working fine but it's not correct way to implement.
can anyone help me.
Thanks.
It's resolved, I have to use onShow instead of onRender function. Now it's working fine.

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.

Routing for flexible JavaScript Single-Page-App?

I'm building a single page web app (because I want flexibility and speed when moving across pages/states) but I'm struggling with routing / urls ...
In the traditional paradigm I would have urls such as:
example.com/tools/population-tool/#currentYear=1950
example.com/tools/income-tool/#country=usa
example.com/nice-story/
example.com/nice-chapter/nice-story/
Now I'd like to replace this with a Router (for example using Backbone) that loads templates and controllers for the corresponding routes.
I'm thinking about having a pages object that stores the necessary page information:
pages : {
tools : {
template : "#tools",
breadcrumb : ["Home","Tools"]
}
nice-story : {
template : "#nice-story",
breadcrumb : ["Home","Stories","Nice Story"]
}
}
With a router, I'd now like load the right content and page state, given a url like:
example.com/#!/tools/population-tool/?currentYear=1950
or like this if not using Hashbang:
example.com/tools/population-tool/?currentYear=1950
How would you organize this routing so that the url scheme makes sense while still being flexible and allow for redirects and new query string paramaters?
This is not a complete answer to your question, but a few tips on Backbone...
You may want to define a method like loadPage() on your router which can empty and replace your main page container with a view that corresponds to each "page" in your app. Each route action can call that to load up the right view.
If you will be using pseudo query strings, make sure to add a matcher for them explicitly in your Backbone routes. For example:
'/tools/population-tool/?*params'
That will call your route action with the entire params string as the first parameter. You'll need to parse that...

Categories