howto: inject hidden data into composer?

Moved Solved Developer FAQ
  • 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 and thumbEl 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.

    https://github.com/NodeBB/nodebb-plugin-composer-default/blob/master/static/lib/composer.js#L546-L573

    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.

  • @baris Thanks for creating the enhancement ticket. Yes, this will be a useful feature.

    Thanks man!

  • 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.

  • @yariplus Nice! I will explore other features first while waiting for the merge and release.

    Yes, got your point that "anything on the client is modifiable" :).

  • 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 hook filter: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:

    1. Extra data is not passed to action hooks.
      • No way for a plugin to respond to data after the post is made.
    2. 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.
    3. 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.
    4. Uses awkward data.data.variable
      • data.extraFields.variable is more readable and less likely to have typing derps.
    5. Passes extra data to filter:topic.create
      • I missed this hook in my commit.
  • @yariplus

    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 ie filter:posts.create gets 2 objects. topic is the object that will be written to the database and data is the data sent from the client, the plugin is responsible for setting any new fields into topic from data.

    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 the filter: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 from data.

    Ahhh, okay! Now I get it. The plugin needs to alter the postdata in the create and edit 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 the filter: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. 👍


Suggested Topics