howto: inject hidden data into composer?
-
Goal: I want to inject some hidden data to the default composer so that when user submitted the topic, the data will be processed.
I want to avoid setting the data in the textarea (of composer) as I do not want the data to be modified and visible.
So I explored the composer.js and found two possible area where I can inject the data:
var handleEl = postContainer.find('.handle');
var thumbEl = postContainer.find('input#topic-thumb-url');
What is
handleEl
andthumbEl
used for?
Or is there any better way to inject hidden data into composer? Thanks! -
I don't think this is possible right now since we don't have the necessary hooks in place.
That part of the code doesn't allow you to add more data into
composerData
so we need a hook there.Once that is done the server side code needs to be changed to accept that data here. https://github.com/NodeBB/NodeBB/blob/master/src/socket.io/topics.js#L25-L34
Actually I am a bit surprised that no one has run into this before.
-
I'm trying to do this now.
-
Okay, I added 'action:composer.submit' which passes the composerData with an extra property 'extraFields' for a plugin to edit. Then the 'extraFields' is passed to the server filter hook, action hook, and return socket calls.
This was the fastest/easiest way I got it to work.
-
@Bruce-Lee Just a small thing. Anything on the client is going to be modifiable by anyone who know how to use their browser console. You will want to verify the data on the server side when it reaches the filter hooks.
-
This is on master now, here is how it works.
You can edit composer.tpl and add a new input field. Then you will use the new hook
action:composer.submit
.// in your plugin client side $(window).on('action:composer.submit', function(ev, data) { // data.composerEl is the dom element for the composer // data.action can be `topics.post`, `posts.reply` or `posts.edit` // data.composerData is the object that will be submitted to the server. // lets add our new field into the data to be submitted for new topics if (data.action === 'topics.post') { data.composerData.myCustomField = data.composerEl.find('#myCustomField').val(); } });
Now
myCustomField
will be available server side to your plugin in the hookfilter:topics.create
. Here is a sample showing how to use it.myPlugin.onTopicCreate = function(hookData, callback) { // hookData.topic, this is the topic that will be saved to the database // hookData.data, this is the data that is submitted from the client side // Now all you have to do is validate `hookData.data.myCustomField` and set it in hookData.topic. if (isValid(hookData.data.myCustomField))) { hookData.topic.myCustomField = hookData.data.myCustomField; } callback(null, hookData); };
This will cause
myCustomField
to be saved in the topic hash along with the regular data.Also thanks to @yariplus for the initial work on this.
-
@baris My method was objectively better. In your method:
- Extra data is not passed to action hooks.
- No way for a plugin to respond to data after the post is made.
- Extra data is not sent to the socket events.
- No way for the client to respond to data after the post is made. Such as if the extra field is meant to add something to the displayed post.
- Data is duplicated
- We only need the extra fields, but the entire data variable is passed. No way to loop over just the extra data. Using
extraFields
also avoids adding another parameter to hook methods.
- We only need the extra fields, but the entire data variable is passed. No way to loop over just the extra data. Using
- Uses awkward
data.data.variable
data.extraFields.variable
is more readable and less likely to have typing derps.
- Passes extra data to
filter:topic.create
- I missed this hook in my commit.
- Extra data is not passed to action hooks.
-
Extra data is not passed to action hooks.
It should be. Anything you set on the
data.topic
will come back to the create methods and get sent to the action hooks.Extra data is not sent to the socket events.
Same as above, since we are changing the topicData/postData objects they will go back to the client with the fields added.
Data is duplicated
Not sure if this matters, the
filter:topics.create
hook and the other related hooks iefilter:posts.create
gets 2 objects.topic
is the object that will be written to the database anddata
is the data sent from the client, the plugin is responsible for setting any new fields intotopic
fromdata
.Uses awkward data.data.variable
Yeah maybe we can call it
data.submittedData
etc.Also in case I missed it your PR was just setting
.extraFields
but there was no actual way to set those values in the database. That's why I am passing 2 objects to thefilter:topic.create
filter:post.create
hooks. Unless you meant to write to the database in the action hooks, which isn't great because action hooks don't have callbacks to send back errors and execution just keeps going. -
@baris said in howto: inject hidden data into composer?:
the plugin is responsible for setting any new fields into
topic
fromdata
.Ahhh, okay! Now I get it. The plugin needs to alter the postdata in the
create
andedit
hooks, and that data is passed to the action and sockets.Also in case I missed it your PR was just setting
.extraFields
but there was no actual way to set those values in the database. That's why I am passing 2 objects to thefilter:topic.create
filter:post.create
hooks. Unless you meant to write to the database in the action hooks, which isn't create because action hooks don't have callbacks to send back errors and execution just keeps going.Yes, that makes total sense now. I was indeed altering the database in the action hook. Altering the postdata in the create hooks is the right way.