Passing custom data into a template?
-
So to get data into a page there are obviously two methods, server side (pass into template then compile) or client side (ajax). I am very familiar with express, but I don't see a possible way of passing additional data to a template after
res.render
has been called, I am saying this because I know the home page is already being rendered somewhere in the core, so there is no way for me to inject data before it gets called is there?If not do I need to replicate all the json being passed in to the default render, add my custom data, then call
res.render
myself?Or is the only method rendering the data via ajax call, which would be my least preferable method.
I know things like this have been documented but it is not very clear to me how to pass in custom data to a template. My case for this is to pass in categories to a sub-header inside
header.tpl
here is what I have so far.(function(module) { "use strict"; var theme = {}; var catLength = [1,2,3,4,5,6,7]; var Categories = module.parent.require("./Categories"); theme.init = function(params, callback) { var app = params.router; var hostMiddleware = params.middleware; var hostControllers = params.controllers; var categories = {}; Categories.getCategoriesData(catLength, function(err, data) { categories = data; }); // TODO: make this a more nodebb like route // app.get('/api', function(req,res) { // res.render('/', {test:true}); // }); callback(); }; module.exports = theme; }(module));
Also I looked through
./Categories
andgetCategoriesData()
seemed like the only method to get categories, my question is why do I have to pass an array of how many categories I want, thats not fun. Why isn't there a method to get all without specifying anything?Thanks guys!
-
You can do what you want with the
filter:middleware.renderHeader
hook.In your plugin add the data you want into it like so
myPlugin.onRenderHeader(data, callback) { Categories.getAllCategories(data.req.uid, function(err, categories){ if (err) { return callback(err); } data.templateValues.categories = categories; callback(null, data); }); };
Now in your
header.tpl
you can access the categories it will be in an array calledcategories
, To print out their names.<!-- BEGIN categories --> <p>{categories.name}</p> <!-- END categories -->
-
WOW thanks man.
One thing though
myPlugin.onRenderHeader = function() {}
This works, thanks! So I am guessing
callback()
is where the data is sent to the core then that adds it before rendering?Great job!
-
@baris I am not sure my question is related to this topic, but I have searched a lot about how to get the specific post data from a specific category to put them on the customize home page for my current site. For example, I have a category called "News", and what I want is each time when I post a new post in this category, I want the post also to show up on the home page. Since I am using custom home page plugin, so all I can do is insert HTML and those data like categories, recent post or popular post. I am a bit of confusion about how to exactly get those data and linked them to the home page? Thank you.
-
@baris said in Passing custom data into a template?:
You can do what you want with the filter:middleware.renderHeader hook.
old topic, new developer
thanks.. that is very helpful
I have one question
I have a filter:post.shouldQueue plugin, it needs to check a list of data items on each post.
I load the data at plugin init time using meta...meta.settings.get(my_data_key, function(err, settings) {
my plugin registers the routes for the admin pages, which causes the static admin,js to run and the template to load, which loads or saves the data (separate from plugin operation code)
// copied from old category-queue plugin, admin.jsACP.init = function () { Settings.load(my_data_key, $('.key_class_settings')); $('#save').on('click', function () { Settings.save(my_data_key, $('.key_class_settings'), function () {
how do I inform the plugin that the data has changed on save? cause init should only run once.
is there some data/key 'onchange' (hook) I can register for to reload it so that my operational data is accurate?
seems bad to get it on every post, as it will almost never change (except when admin/save is checked
i haven't figured out template code to add/delete items from the list yet.. (more js event handlers I presume)
-
'action:settings.set'
this hook fires when you save plugin settings. It will receive the name of the settings object.plugins.hooks.fire('action:settings.set', { plugin: hash, settings: { ...values, ...sortedListData }, });
So in your plugin you can update your settings in this hook like so.
myPlugin.actionSettingsSet = async function (hookData) { if (hookData.plugin === my_data_key) { my_local_settings = await meta.settings.get(my_data_key); } };
-
@baris so, I am SO close.. just adding admin pages...
repo here https://github.com/sdetweil/nodebb-plugin-moderation_on_links
the postqueue function works
the link shows for adminthe admin template shows when u click the link,
but no data, the header hook for data doesn't fire
and I get that error
the static/lib/admin.js doesn't fire
its the '.' I am sure, but why and from where.. the log shows status 200 for loading content.. no 404..
npm i the repo,
activate
rebuild and relaunch
go to admin, plugins, click the link post_link_listnpmi the
-
I think you are missing the plugin.json entry for your admin page javascript, take a look at how persona adds the admin page javascript. https://github.com/NodeBB/nodebb-theme-persona/blob/master/plugin.json#L16
You need an try in your plugin.json like that.
-
@baris this page shows the format required by the 2.4.5 version I am on..
https://docs.nodebb.org/development/plugins/plugin.json/
it is similar to minealso, my admin.js IS loaded and run
as the messages from the run are shown at the client
(browser dev winbow console)/plugins/post_link_list admin define running
/plugins/post_link_list admin define ending returning acp keys= ['init']but the actual init() method is not called.
adding the module entry to plugin.json solved the error and the init is now called...
-
Yeah you need your admin.js file in the modules section,
acpScripts
is for scripts that will be run whenever the admin site is loaded, think of them as global javascript that you want to include on the ACP site. modules section is for new pages for plugins or custom js modules. They are loaded on demand when the user navigates to your page. -
@baris ok, thanks. but none of that makes sense.. sorry.. 'user' is only admin in my case.
added on the ACP site (for what purpose if not for when the user navigates)?
i don't want it to run twice.. so it sounds like do NOT use acpScripts..
but. back on the custom data to the template
I see two different approaches used.. (neither work for me)
some modules use admin to use the settings api to load the values into a css class using jquery $('.someclassname')
which the template uses somehow, but unclear ${'../name'}
https://github.com/oplik0/nodebb-plugin-category-queue.gitadmin.js Settings.load('category-queue', $('.category-queue-settings')); template <form role="form" class="category-queue-settings"> <!-- BEGIN categories --> <div class="form-group col-sm-4 col-xs-6"> <label for="{../cid}">{../name}</label>
and the other passes data in the call to res.render(page, {data structure})
in lib/controllers/renderAdmin()
then the template uses the data structure elements clearly.my data is an array.. no internal named elements (presumably that is the ${../name} thing...accessing the object elements
and there is no for loop construct in the template, so I don't see how it generates 4 instances in the output...sorry, one more question on templates.. is there any way to test them outside trying to load the plugin.. cause they are not generating the content I expect, but don't see any errors during build or run
-
In your plugin's case you would need to move your admin js file to the modules section like so
"modules": { "../admin/plugins/post_link_list.js": "static/lib/admin.js", }
And remove it from
acpScripts
.When you do this
static/lib/admin.js
will be loaded and itsinit
method will be called when the user(admin) navigates to your plugin page.Now settings.load uses some client side code to load the settings and fill in the input elements on the plugin page. So when that is called from the init function of the admin page. It will populate the forum fields. If you are storing a list of urls I suggest storing them as a string and displaying them in a text area. You can inspect https://github.com/ninenine/nodebb-plugin-beep it does something similar.
-
@baris thanks.. I want to have a field for each url string. (from the array)
have an input field to add another with a click
and some selector (minus sign, checkbox...) and click to remove..but the templating engine is killing me.. I don't know what the syntax is for non structure objects..
{{{each post_link_list}}}
gets me a line for each.. good.. what is its value?
hm... now it works ok?
@value says object.. (oops, put in {}), now compiler says use {} as required in 3.x)hm.. could use its array index tho...
this post_link_list comes from the render..
can I use meta from admin (as module) ? (button click handler) ..
hm.. can't import meta in admin.. -
@baris well, got almost all of it working, list, add, delete, save button
now to update the database
I have the hook on save, so I can reload the operational list and use it to inform the admin page
it will be loaded via meta.get in the index.js (it doesn't return any data now, as there isn't any)
but meta isn't usable in admin..settings is, but I don't see a save or (or load) method in the src/settings.js
but from quickstart admin.js
settings.load('quickstart', $('.quickstart-settings'), function () {i want to save from a JS variable. but that causes some error not in the log, and I get the spinning circle saying my plugin is taking a long time.,
so close..
the admin code that gets the save click to savevar selected = []; $('#urls').find('input[type="text"]').each(function() { selected.push($(this).attr('value')); }); console.log("urls to save=",selected) try { Settings.save(our_keya,selected, (err,sss)=>{
and the dev window console log
post_link_list save clicked urls to save= (4) ['github.com', 'pastebin.com', 'forum.magicmirror.builders', 'docs.magicmirror.builders'] post_link_list settings save executed settings save completed
the node bb log capturing from index
this is the output of setting save(), have the right 'hash', well its the 'key' I sent in
similar to all the other plugins I looked atbut no data
io: 1 on [ { type: 2, nsp: '/', id: 8, data: [ 'admin.settings.set', { hash: 'post_link_list', values: {} } ] } ]
in index , the hook
settings saved for { plugin: 'post_link_list', settings: {}, caller: { uid: 1 } }
-
@baris debugging why my settings don't save
I see the value in the hook now.. the 'value' MUST be a keyed object... not flat
but still no persistence.
I see the action hook is called before informing meta to reload..
but even when I stop and restart nodebb the data is not current
-