Template helpers not working in in NodeBB v2
-
I'm at the moment adapting my plugins for v2 and ran into an issue with template helper functions. I've until now included them as below, so they work both when rendered on the server and the client.
'use strict'; /* globals */ (function (factory) { if (typeof module === 'object' && module.exports) { factory(require.main.require('benchpressjs')); } else { require(['benchpress'], factory); } }((Benchpress) => { const number_of_answers = (data) => { const replies = data.postcount - 1; switch (replies) { case 0: return 'No comments'; case 1: return '1 comment'; default: return `${replies} comments`; } }; const customHelpers = { number_of_answers, }; function register() { Object.keys(customHelpers).forEach((helperName) => { Benchpress.registerHelper(helperName, customHelpers[helperName]); }); } register(); if (typeof module === 'object' && module.exports) { module.exports = customHelpers; } }));
This has worked great but now that I'm running v2 (2.0.0) it only works server side. I'm including the file in
plugin.json
under scripts,"lib/helpers.js"
.One guess is that I should move it to modules as other client scripts, but I'm not sure how I should do that with template helpers.
Appreciate all help.
-
Here is a sample that adds a custom helper to persona. You can make the necessary changes to add to your own theme.
Create the files
lib/customHelpers.js
(server side)
'use strict'; module.exports = require('../public/modules/customHelpers-common')( require.main.require('benchpressjs') );
public/modules/customHelpers.js
(client side)
'use strict'; const factory = require('./customHelpers-common'); define(['benchpress'], function (Benchpressjs) { return factory(Benchpressjs); });
public/modules/customHelpers-common.js
(shared)
'use strict'; /* globals */ module.exports = function (Benchpress) { const number_of_answers = (data) => { const replies = data.postcount - 1; // see where the helper is called from console.log('CALLED!', typeof window !== 'undefined' ? 'window' : 'node'); switch (replies) { case 0: return 'No comments'; case 1: return '1 comment'; default: return `${replies} comments`; } }; const customHelpers = { number_of_answers, }; function register() { Object.keys(customHelpers).forEach((helperName) => { Benchpress.registerHelper(helperName, customHelpers[helperName]); }); } register(); return customHelpers; };
With those files in place you can link them up so that the new helper is available on client/server. See the diff below
diff --git a/library.js b/library.js index e7b7b6c..0641b03 100644 --- a/library.js +++ b/library.js @@ -19,6 +19,8 @@ library.init = async function (params) { middleware.canViewUsers, middleware.checkAccountPermissions, ], controllers.renderThemeSettings); + + require('./lib/customHelpers'); // register for server side }; library.addAdminNavigation = async function (header) { diff --git a/plugin.json b/plugin.json index 4716e49..f317129 100644 --- a/plugin.json +++ b/plugin.json @@ -15,7 +15,9 @@ "modules": { "../admin/plugins/persona.js": "public/admin.js", "persona/quickreply.js": "public/modules/quickreply.js", - "../client/account/theme.js": "public/settings.js" + "../client/account/theme.js": "public/settings.js", + "persona/customHelpers.js": "public/modules/customHelpers.js", + "persona/customHelpers-common.js": "public/modules/customHelpers-common.js" }, "languages": "languages" } \ No newline at end of file diff --git a/public/persona.js b/public/persona.js index d3699ed..50e0476 100644 --- a/public/persona.js +++ b/public/persona.js @@ -12,6 +12,8 @@ $(document).ready(function () { $(window).on('resize', utils.debounce(configureNavbarHiding, 200)); $(window).on('resize', updatePanelOffset); + require(['persona/customHelpers']); // register client side + function updatePanelOffset() { const headerEl = document.getElementById('header-menu'); diff --git a/templates/topic.tpl b/templates/topic.tpl index a42dfa3..6c6cb69 100644 --- a/templates/topic.tpl +++ b/templates/topic.tpl @@ -3,6 +3,10 @@ {{widgets.header.html}} {{{end}}} </div> {number_of_answers(@root)} <!-- use helper --> <div class="row"> <div class="topic <!-- IF widgets.sidebar.length -->col-lg-9 col-sm-12<!-- ELSE -->col-lg-12<!-- ENDIF widgets.sidebar.length -->"> <div class="topic-header">
-
I get the following error client side:
Uncaught TypeError: can't access property "registerHelper", Benchpress is undefined
-
Can you try putting a console.log in the if statement to check which one works?
-
@magnusvhendin said:
One guess is that I should move it to modules as other client scripts, but I'm not sure how I should do that with template helpers.
I didn't end up doing it that way. I was writing a custom plugin that needed a helper, and I ended up doing it via a script added to
scripts
inplugin.json
.I cannot share the code as it is in a private repo, but —
require(['benchpress'], (benchpress) => { benchpress.registerHelper('myHelper', (data) => { // ... }); });
I only used a client-side helper. I believe I looked into it and for whatever reason, no server-side helper needed to be registered, it just worked
-
You might have to follow the same pattern we do in core. Take a look at these 3 files in core for helpers.
// client side
https://github.com/NodeBB/NodeBB/blob/master/public/src/modules/helpers.js// server side
https://github.com/NodeBB/NodeBB/blob/master/src/helpers.js// common
https://github.com/NodeBB/NodeBB/blob/master/public/src/modules/helpers.common.js -
Here is a sample that adds a custom helper to persona. You can make the necessary changes to add to your own theme.
Create the files
lib/customHelpers.js
(server side)
'use strict'; module.exports = require('../public/modules/customHelpers-common')( require.main.require('benchpressjs') );
public/modules/customHelpers.js
(client side)
'use strict'; const factory = require('./customHelpers-common'); define(['benchpress'], function (Benchpressjs) { return factory(Benchpressjs); });
public/modules/customHelpers-common.js
(shared)
'use strict'; /* globals */ module.exports = function (Benchpress) { const number_of_answers = (data) => { const replies = data.postcount - 1; // see where the helper is called from console.log('CALLED!', typeof window !== 'undefined' ? 'window' : 'node'); switch (replies) { case 0: return 'No comments'; case 1: return '1 comment'; default: return `${replies} comments`; } }; const customHelpers = { number_of_answers, }; function register() { Object.keys(customHelpers).forEach((helperName) => { Benchpress.registerHelper(helperName, customHelpers[helperName]); }); } register(); return customHelpers; };
With those files in place you can link them up so that the new helper is available on client/server. See the diff below
diff --git a/library.js b/library.js index e7b7b6c..0641b03 100644 --- a/library.js +++ b/library.js @@ -19,6 +19,8 @@ library.init = async function (params) { middleware.canViewUsers, middleware.checkAccountPermissions, ], controllers.renderThemeSettings); + + require('./lib/customHelpers'); // register for server side }; library.addAdminNavigation = async function (header) { diff --git a/plugin.json b/plugin.json index 4716e49..f317129 100644 --- a/plugin.json +++ b/plugin.json @@ -15,7 +15,9 @@ "modules": { "../admin/plugins/persona.js": "public/admin.js", "persona/quickreply.js": "public/modules/quickreply.js", - "../client/account/theme.js": "public/settings.js" + "../client/account/theme.js": "public/settings.js", + "persona/customHelpers.js": "public/modules/customHelpers.js", + "persona/customHelpers-common.js": "public/modules/customHelpers-common.js" }, "languages": "languages" } \ No newline at end of file diff --git a/public/persona.js b/public/persona.js index d3699ed..50e0476 100644 --- a/public/persona.js +++ b/public/persona.js @@ -12,6 +12,8 @@ $(document).ready(function () { $(window).on('resize', utils.debounce(configureNavbarHiding, 200)); $(window).on('resize', updatePanelOffset); + require(['persona/customHelpers']); // register client side + function updatePanelOffset() { const headerEl = document.getElementById('header-menu'); diff --git a/templates/topic.tpl b/templates/topic.tpl index a42dfa3..6c6cb69 100644 --- a/templates/topic.tpl +++ b/templates/topic.tpl @@ -3,6 +3,10 @@ {{widgets.header.html}} {{{end}}} </div> {number_of_answers(@root)} <!-- use helper --> <div class="row"> <div class="topic <!-- IF widgets.sidebar.length -->col-lg-9 col-sm-12<!-- ELSE -->col-lg-12<!-- ENDIF widgets.sidebar.length -->"> <div class="topic-header">
-