Change button depending on UserCustomField?

plugins

#1

Part of the plugin I’m developing requires that I show different buttons depending on the value of a custom field I’m saving. Now using handle bars I know I can do something like this.

{{#if customField}}
    showbutton1
{{/if}}

However the problem I’m having is that since there is no UI level way to access a UserCustomField eg. Discourse.CreateCustomField that I’m aware of this requires me to access a method declared in my plugin.rb file via an xhr request and I’m attempting to check the value of that on init however it fires before the user has loaded. Anyone know which would be the best way to approach this?


(Rafael dos Santos Silva) #2

Sorry I’m on mobile but add a method on the controller that will handle your template that uses Discourse.User.currentProp(‘custom_fields.my_field’) or something like that

:sweat_smile:


#3

I’m not entirely following how you make use of currentProp to save a custom field as it never populates to the database, eg. Discourse.User.currentProp('custom_fields.my_field', [1,2,3]) will only create a variable that isn’t preserved during refresh. Right now I’m saving the custom_fields via database transaction from my plugin.rb file. Like so…

UserCustomField.where(user_id: user_id, :value => value)

If there is a way to save these fields via javascript it’s not very apparent how to do so. Even attempting to reference the fields saved in the database will return a null response, Discourse.User.currentProp('custom_fields.my_field') even though I know for a fact this user has a value present in the custom_fields table.


#4

I’m able to save new values like so

model.set('custom_fields.my_field', 1);
model.save();

Doing either of the following however doesn’t return the values

model.get(‘custom_fields.my_field’)
Discourse.User.currentProp(‘custom_fields.my_field’)

Additionally it appears that you cannot save the Discouse.User.current() model, and can only save the model of the user I’m viewing.

Discourse.User.current().save() results in an error

Uncaught TypeError: Cannot read property 'map' of undefined(…)

Discourse.User.currentProp("custom_fields.myfield") returns undefined as Discourse.User.currentProp("custom_fields.myfield", 1) is not persisted beyond a refresh.

Though I’m able to save them when viewing the user of the UserCard model it self, there does not appear to be anyway to access them which is what I need.


#5

I even attempted to mimick the functionality from Suppress updating of URL during topic navigation and even after registering my custom field it is NOT available from javascript by doing Discourse.User.currentProp('custom_fields.my_field') using the rails console we can see the values are available on the user object serverside but those fields are never serialized onto the User model. I have absolutely no idea what you mean by > or something like that I posted to the forum looking for assistance and instead I feel like I’ve been sent down a rabbit hole of misinformation.


(Rafael dos Santos Silva) #6

Sorry that I tried to help.


Your topic title is “Change button depending on UserCustomField” so I reply on how to get the User Custom field on your controller:

Discourse.User.currentProp('custom_fields') // Object with all Custom Fields

//or

Discourse.User.currentProp('custom_fields.my_custom_field') 

On the reply #3 you start to talk about saving a field, an entirely different topic, that can be accomplished on various forms:

  1. Add the field on the Admin > Customize
  2. Make the field editable
  3. Expose the field on settings, so it will be serialized with the user object

OR

  1. Add fields that appear on preferences using the existing outlet
  2. It will be persisted on preferences save
  3. Add the fields to the serializer trough after initialize block on plugin.rb

Good luck! :four_leaf_clover:


#7

I think you misunderstood what im saying, doing what you suggest never
populates the values client side. Custom fields is an empty object, the
values are never serialized into the user model. Additionally if they have
to be set via admin then that makes their functionality as explained in
another support forum request inadequate for the original purpose. Which is
i need the ability to store custom database fields for use with my plugin,
custom fields does not look like it was ever built with that in mind. The
values never make it to the JavaScript side, im not sure which version of
discourse youre using but im running 14 beta 9 and i cant upgrade beyond
that. CurrentProp does not work.


(cpradio) #8

It may help if you actually look at another plugin that uses custom fields.

You can see you have to specify you want it serialized.


#9

I’ve done that, I’m not sure where you found the source to that specific plugin as I scoured the internet and forums for hours trying to find a good example to follow. My plugin file looks like this.

DiscoursePluginRegistry.serialized_current_user_fields << "my_field"

after_initialize do

	User.register_custom_field_type('my_field', :string)

	 add_to_serializer(:user, :my_field, true) {
        object.user.custom_fields['my_field']
    }

and when I run

Discourse.User.currentProp('custom_fields.my_field') I get a null response


(Rafael dos Santos Silva) #10

That code above makes the field get serialized.

Now you need to set the field. Look at the same repository, on connectors folder, and use the code to add a field to your preferences page where you can set the field to something.

There are several example plugins on Discourse repositorioes or looking trough the plugins categorie here on meta.


#11

That code above makes the field get serialized.

Now you need to set the field

I think this is where the break down in communication is coming from, what I need to be able to do is set these values programatically. When a user is visiting another user’s profile page I have a button and when that button is clicked I need it to save a relation to each user…something like CustomField.save('my_field', user_id) but from what you are suggesting custom_fields are only applicable for user_preferences from the settings themselves? Currently I can set these values using ruby logic in my plugin.rb file but if I cannot access them through the user model then this isn’t a solution to my problem and now i’m confused as to how no plugin ever ran into this problem before.


(cpradio) #12

Then I don’t think you want user custom fields. I think you will want to implement the PluginStore as shown in Profile Notes.

That way you have a place to store your data and retrieve it without any UI requirement.


#13

Thanks but I do have a UI requirement, I cannot eliminate the need for two different buttons depending on the value being present, which leaves me in the same position I was in previously if I understand what you are saying correctly.

I need inside my javascript something like this…

relationExists: function() {
  var value = PluginStore.find('user_id', 1);
  if(value) {
   return true;
  }
  return false;
}

So my handlebars can be like this…

{{#if relationExists}}
   //show button 1
{{else}}
  //show button 2
{{/if}}

(cpradio) #14

Exactly. That is why you will want to use the PluginStore. Profile Notes, does exactly that. As it outputs data to the UI (on the Profile page specifically), but it doesn’t add any fields to the User Preference screen. And the data is stored per user. So it should be a good plugin to look at.


#15

Looking at the profile notes page there is a slight difference between the implementations that I’m seeing as a blocker. Right now looking at it it leads me to the same problem I had before which was timing, since these buttons are displayed both on the user profile page and the user card page I need to load the values before the page has rendered, which leads me into a race condition because the init function will run before the page has finished rendering and loading the appropriate model then my AJAX request cannot fire at that time because the data it needs to function isn’t yet available.

Then if i try to load it after the page has rendered the handlebars template has already expected its value to be returned, profile notes gets away with this because its loading a list , not displaying different buttons depending on the value. I hope that made it clear what my problem is, I appreciate the help I’m just struggling to understand how to get around this as it’s the same problem regardless of how I load the data (custom fields or plugin store).


#16

Nevermind, this works for User controller just UserCard is slightly different and will require additional modifications. For anyone else who needs to set some values for UserController this is what finally worked for me.

  _loadValue: function() {
    this.get('model').set('loading', true);
    Discourse.ajax("/mypath/endpoint", {
      data: {
        user: Discourse.User.currentProp('id'),
        value: this.get('model.id')
      }
    }).then(function(json) {
      this.get('model').set('loading', false);
      this.set("model.value", json.value);
    }.bind(this));
  }.observes('content').on('loaded'),

For those who need to load data on UserCard then you’ll need to use this observer .observes('user').on('loaded')

Thanks again cpradio & Falco