Connector Classes and Actions

I am using the plugin outlet composer-fields to add a new text field to the compose window for a new topic. When the user clicks the “Create Topic” button I would like the data in that field to be stored as a custom field for the topic.

Under the “old” approach of extending a controller I am reasonably confident with doing this, but I am having difficulties using the new connector classes approach outlined in the post Important changes to Plugin Outlets for Ember 2.10.

In particular, I don’t know how to run code in response to the topic being created. I am guessing it is not an action, since the code execution is not being triggered in response to an action on that particular control. I am instead trying to observe model.createdPost but cannot figure out how to get this working.

I have put this underneath setupComponent in the connector class, but it never runs:

saveAfterCreating: function() {
    console.log(createdPost);
  }.observes('model.createdPost')

Any suggestions appreciated!

EDIT: Am I also somehow still able to reopen the ComposerController to implement a save() method, which I assume will be called automatically when the composer saves its content?

ComposerController.reopen({
   actions: {
      save() {
         console.log("save");
      }
   }
})
3 Likes

I think the problem here is you need an event callback for when a topic is created and no such hook exists. We probably need something like this.appEvents.trigger('composer:saved', result) if the promise succeeds after the composer controller calls .save().

If you listen for that event in your plugin, you could then send the custom field data across.

4 Likes

Thanks for the info @eviltrout . I am still a bit confused about how to be passing around the custom field data. When I was experimenting last night I created a plugin.js file in an initalizers directory and reopened the ComposerController so that I could override the save method, which works as that is now called whenever a post is saved.

So, right now the general plugin initalizer file just has the ComposerController code and the connector class (specific for the outlet) contains setupComponent which gets a reference to the model (via args.model) and sets up the control being inserted at the outlet. Is this workflow right? Or should I be doing all this in the connector class (which didn’t work on my first attempt, see above question)?

The immediate problem I am encountering is how to access the custom field data from the initalizer class, so that it can be used in the overriden save method on the ComposerController. Any ideas on how to approach this?

I imagine this issue will also exist if the event listener is implemented in the initializer class too.

I have looked through the sample code for many other plugins, but since the connector class pattern is so new I can’t really find anything that helps.

1 Like

So, a quick update. I have managed to add an event listener to the plugin.rb file. For sake of testing, I just am monitoring the post_edited event so I can edit an existing topic, rather than having to create topic after topic for testing (when it’s all working I’ll change the event to topic_created).

Just so I could verify it’s working, this is my code thus far:

DiscourseEvent.on(:post_edited) do |post, topic_changed|
   puts "ZZZZZZZZAAAAAAAAAAAAAAAAAAAAA" + post.topic.title
end

…which prints the topic title to the logs/console (on the development server). The random text is just so I could easily search for the output in the logs to make sure it is coming through.

However, I still have no idea how to get access to the custom field and it’s data, so that I can then pass it along to where it needs to go?

I feel that I am half way there now, since I have access to the post/topic (and it’s ID) - so once I get the data from the custom field I can then write the logic to insert that as a custom field for the topic in the database (UPDATE: Done successfully, using hardcoded dummy data at the moment - so the only missing piece of the puzzle is getting the actual data from that custom field in the composer window).

1 Like

Like I said above, I think you are going to need a new hook added to Discourse to solve this problem. Basically, when a topic is created, Discourse should send an event. Then in your connector class you can listen for that event, and then make a new AJAX request with your fields.

It’s a somewhat complicated thing to do, unfortunately. You are going to need to submit changes to discourse to get it to work.

3 Likes

Okay, thanks for the reply @eviltrout. Before going further into looking at changes to Discourse, is there any alternative way to achieve the same thing?

I was using the discourse-basic-links plugin as example code, since it inserted a “link url” field into the composer window. Looking at the source code, it managed to get the custom field data by reopening the ComposerController and overriding the save() action.

https://github.com/joebuhlig/discourse-basic-links/blob/master/assets/javascripts/discourse/pre-initializers/basic-links.js.es6#L68

The field is inserted via a connector on the composer-fields plugin outlet, but all the logic is contained within the above pre-initializer class rather than a class connector (since the plugin was developed prior to class connectors being introduced).

Unfortunately the plugin doesn’t work with the latest Discourse from GitHub - so I am not holding my breath that this approach will work anymore!

I’m happy you’re looking and learning about Discourse but replying to this topic is taking quite a bit of my time. If you are prepared to approach this the way I’ve suggested twice now I will help, but otherwise you’ll have to go at this on your own.

3 Likes

Got it, appreciate all your help and advice :slight_smile: Will keep looking into the Discourse source and figure out the best way of approaching the hook with a view to opening a PR to get it included.

1 Like