Dynamic defaults

Hi All,

I’m looking for a way to have properties set automatically based on the value of another property. For instance I have an object called entity and the entity has a property called “name”, the entity object also has a property called “tableName” which I want to use the value I put into “name” suffixed with the term _table in my “tableName” property. So if I had entity.name = “person”, I want to set the entity.tableName = “person_table” without having to type it manually.

I was thinking that I could potentially extend the functionality around defaults so that you could reference another field when you configure a default and then also include a suffix.

Have you ever considered something like this or got any ideas on a good way to implement this?

Thanks again!

Hi @james-morris,

The default behavior is very non-standard. You can use the default mechanism of AJV to save some implementation time but this is also restricted to use cases where the value was not set at all beforehand.

If you always want to set an additional property Y when changing property X then you have two potential approaches:

  • Implement a custom renderer for X. The custom renderer behaves the same as the normal renderer, but additionally sets property Y whenever X is changed.
  • Listen to the data changes outside of JSON Forms and adapt property Y whenever property X changes and hand over the changed data back to JSON Forms.

In practice we already implemented both approaches. It depends on your requirements and use cases which one is better suited for you.

1 Like

Hi @sdirix ,

Getting round to trying out your suggestion now. I started out by trying your first suggestion but then realised I needed my configuration to sit on the schema property that results in Y and not X and so hence don’t think I can use that first approach.

I’m now looking into the second approach you mentioned.

How do you suggest listening to the changes outside of JSON forms. I know I could write something that goes into the onChange function that I pass to JSON forms but the arguments to that function are only data and errors as far as i’m aware? Would that mean then to diff the data between changes would require me to store locally and do the diff myself? or is there some way of listening to exactly what bit of the data has changed and making changes to the other parts of my data?

Hi @james-morris,

Getting round to trying out your suggestion now. I started out by trying your first suggestion but then realised I needed my configuration to sit on the schema property that results in Y and not X and so hence don’t think I can use that first approach.

I don’t fully understand what the problem is for you. Can you elaborate?

How do you suggest listening to the changes outside of JSON forms. I know I could write something that goes into the onChange function that I pass to JSON forms but the arguments to that function are only data and errors as far as i’m aware? Would that mean then to diff the data between changes would require me to store locally and do the diff myself? or is there some way of listening to exactly what bit of the data has changed and making changes to the other parts of my data?

Yes we only emit the whole of the updated data so you need to check for the changes yourself. Depending on your requirements I see two approaches:

  • If such a dependent change is “always on” you don’t really need to check what changed. You could just check whether the data confirms to your needs. For example if longerName is just name + XYZ then you could check for that every time without needing to check whether name actually changed.
  • If you need fine-grained deltas then you can use a library like fast-json-patch and compare against the previous data you received from JSON Forms. With this you can easily check for and react to changes accordingly.

Hi @sdirix,

Thanks again for your response, Apologies for the first part of my above comment it was quite vague. What I meant is, using you example where Y is changing based on X, i tried to implement a custom control for X and added config to X in the schema which had the path of the dependent schema property, in this case Y. So essentially Ys dependence on X was configuered at schema property X. However in my system I need the configuration to be the other way round, so I need to configure schema property Y to have dependence on X. This made it difficult for me to implement a custom renderer for X because I would have to look at the properties of other parts of the schema (i.e. Y) to know that something else has a dependence on X and hence to use my custom control. I hope this makes sense and I’m happy to pursue this option again if you think there’s something I could do to solve the problems I mentioned.

With regards to the second part of your response, I want the dynamic default variable to be overridable so if I edit X it updates Y but if I edit Y it keeps my edits to Y unless I go and update X again. So I don’t think I could use the “always on” approach you suggested

Hey i’m just getting back to looking at this actually for another use case where I want to have two fields where the text in one field is the same as the text in the other plus a suffix. I decided to try your first suggestion where we have two components X and Y where Y is dependent on X. On X I configure that Y is dependent on it and also the suffix to apply.
So if in my person.name = “James” person.description = “James is learning jsonforms” where ‘is learning jsonforms’ is my configured suffix.

I think I’m really close to getting this working but my current issue is that i’m issuing two handleChange statements, one for the person.name and one for the person.description and i’m getting the following error:

Uncaught Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.

Is there a better way to issue changes to two places in my data?

I was able to get it to not error by adding a timeout between each of the handleChange

Calling handleChange an arbitrary number of times should be no issue at all, assuming that they are called right after each other (i.e. within the same JS cycle). The rerender will only happen once after all of them.

So if you’re running into a maximum update depth issue then this means that there is a problem in either the code invoking JSON Forms or in one of the custom renderers. I would like to recommend fixing this problem properly instead of relying on a timeout to avoid future problems.

Just to be sure: The handleChange is called from the control which originates the change and not within a useEffect in the dependent control to update its own value, right?

To investigate I would like to recommend looking at the code which is invoked whenever JSON Forms emits the change event and all custom renderer code, especially suspicious are any useEffect or if a handleChange is called directly during rendering.