json-schema-form / angular-schema-form

Generate forms from a JSON schema, with AngularJS!
https://json-schema-form.github.io/angular-schema-form
MIT License
2.47k stars 653 forks source link

Walkaround for "oneOf" in schema? #125

Closed luckylooke closed 9 years ago

luckylooke commented 9 years ago

How can I solve if the array can have multiple type of object items? oneOf is not supported :(

{
    "id": "http://some.site.somewhere/entry-schema#",
    "$schema": "http://json-schema.org/draft-04/schema#",
    "description": "schema for an fstab entry",
    "type": "object",
    "required": [ "storage" ],
    "properties": {
        "storage": {
            "type": "object",
            "oneOf": [
                { "$ref": "#/definitions/diskDevice" },
                { "$ref": "#/definitions/diskUUID" },
                { "$ref": "#/definitions/nfs" },
                { "$ref": "#/definitions/tmpfs" }
            ]
        }
    },
    "definitions": {
        "diskDevice": {},
        "diskUUID": {},
        "nfs": {},
        "tmpfs": {}
    }
}
davidlgj commented 9 years ago

There are two problem with the example code, one is $ref which we don't support yet, and oneOf.

As far as I know tv4, which we use to validate, actually supports validating oneOf, but there is no automatic UI for it. One of the problems is how it should look. We'd like to support this one day, It's on the list but not that high up at the moment.

Extedning with your own type to get a good ui is probably the only way to go if you need this now, see docs https://github.com/Textalk/angular-schema-form/blob/master/docs/extending.md

luckylooke commented 9 years ago

@davidlgj Thanks, I will try to extend or bypass it somehow. ;)

TrevorPage commented 9 years ago

I'm currently using https://github.com/jdorn/json-editor for a project and I'd like to consider angular-schema-form as an alternative, but I rely on oneOf support, which json-editor presently has. The way json-editor approaches this is to provide a select menu whose options are populated with the titles of the oneOf options. This is excellent for me, as my use case is to provide a UI that lets you build an array of different types. So I add an array element, and then use the select to choose the element type. Quite cleverly, json-editor sets those selects to the right oneOf types when loading a JSON that the UI created beforehand, probably helped by the fact that each of my 'oneOf' object types has a property that is unique to it.

davidlgj commented 9 years ago

@TrevorPage We're in need of anyOf and oneOf support soonish ourselves, and for basic support a select and a subform feels like a natural thing. I'm not sure I understand what you mean with "to the right"? Could you make a screengrab?

For the arrays with anyOf or oneOf I was thinking of having extra add buttons, how does that sound?

TrevorPage commented 9 years ago

Hi @davidlgj - sorry, my post was written when tired and was rather vague wasn't it!

json-editor's support for oneOf is very good for my use case. However it would be nice to have the option to switch to ASF, because ASF seems more active (with PRs being merged) and I'm also having great success with ASF for other projects.

Using json-editor's handy online demonstrator, here's an example I just prepared to demonstrate my use case.

demo

My particular use case is for a graphics application, where I am allowing the user to build an array of different 'Painter' subclasses. The resulting JSON is used to build a real set of Painter classes in an Android application.

What you see in the demo is a simple schema that contains two painters (very much simplified, just for demo): NeedlePainter, and CirclePainter. You will note that each one has a unique, fixed "$type" property, e.g. "$type" : "CirclePainter". This is used in the Android app so that GSON can deserialise to the correct subclass type.

When you first run it with a 'blank' JSON model output, you can start adding elements to the array. For each element, a select menu exists that allows you to choose the particular 'oneOf' type. This select menu isn't a property in the schema; it is being added by the library itself so you can choose which oneOf object you want at each element. This, I believe, is the most intuitive way of handing it and is how ASF could handle it.

Another approach instead of the select control would be to have it so that the user application must tell the library which oneOf object to use, through a registered callback. The application could then use whatever means it wants to choose the type. In my use case this would be very nice, as I would have it so that when the user hits [+] to add a new Painter element, my application could fire a pop-up dialogue to offer a choice of painter types to add. Once a selection has been made, the ASF library would be informed (perhaps via a promise?) and it would add the desired element to the array.

The next important thing (which I didn't explain well before) is that json-editor does a nice job of correctly inferring the oneOf selections (i.e. setting the oneOf select menus to the correct titles) when you initialise it with an existing model. To illustrate this point, go to the demo and do these steps:

  1. Ensure the existing model is set to [ ] and hit Update Form.
  2. Copy this into the model and update form again:
[
  {
    "$type": "CirclePainter",
    "property2": "",
    "segments": []
  },
  {
    "$type": "NeedlePainter"
  },
  {
    "$type": "CirclePainter",
    "property2": "",
    "segments": []
  }
]

When the UI is built up, you see that the selects for the oneOf types are all correctly populated. In my real application this works even with there being quite a number of oneOf object (painter) types. How it does this under the hood I don't know; I've not looked at the source, but presumably to do this it has to cycle through each oneOf schema and determine which one "fits", i.e. validates.

davidlgj commented 9 years ago

Wooh, thanks for the feedback! Nearly needed a TL;DR; there ;)

Good with a demo to look at. Yep, this is what I thought a basic first support should look like. I hadn't really thought it through with which of the possible forms pre-populated array items should have, that was very helpful. Looping over and picking the first one that validates (sans required if its a partially filled out form) is probably the best way.

The biggest hurdle is to get the fields in one of the anyOf or oneOf is that each field needs to be matched against its little part of the schema (this is how asf works internally), which means we either need to let the key be just the sub part and not the absolute path, or come up with some sort of annotation that signifies which part of anyOf or oneOf that is to be used.

The second approach is the one I'm going to be trying out since its basically how array works. Items in arrays have keys like persons[].name, so in the case of a simple anyOf, not in an array but just a property, the key could be something like person{0}.name, person{1}.name etc, and inside an array that would be person[]{0}.

I'm probably not making any sense :) But anyhow something like what json-editor does is probably what we want.

stevezau commented 9 years ago

Any update on anyOf and oneOf support? Is this something that is being worked on or future roadmap?

We are in the middle of designing a webui for https://github.com/Flexget/Flexget. ALL of our configuration is json schema v4 with heavy use of anyOf and oneOf.

There are other options such as https://github.com/jsonary-js/jsonary but i'd prefer to use Angular Schema Form as we using Angular for the webui..

thanks!

davidlgj commented 9 years ago

@stevezau anyOf and oneOf is in the pipeline. The goal is to have that + basic $ref support mid august.

stevezau commented 9 years ago

@davidlgj great thanks.

I will starting development on the webui for Flexget next week. We already well defined json schema def's and a full API interface.

I'm happy to test anyOf and oneOf? I'd help with the effort but i don't think i'll be skilled up on angular in time.

SylvainEstevez commented 6 years ago

Any news regarding oneOf support guys? I'm looking for a library to create forms for my JSON schemas, but I highly depend on oneOf.

Anthropic commented 6 years ago

@SylvainEstevez the main issue with oneOf is that it is part of validation and not of display logic, I don't feel the previous solutions are adequate and we are discussing options within the json-schema org about how best to approach it. In the meantime I'm trying to split out the tv4 validator so we don't rely on it any more as it is no longer supported. This will allow us to use a validator with draft 6+ support which will help with alternative methods of representing the data.

All that said, it is already very possible to make a simple directive that validates a form key that does have oneOf/anyOf/allOf applied to it, I've done it myself for quite a while, it really depends on what you want to achieve, if you just want to validate values a directive is easy for that. If you want a selector to decide which parts of a form to display that's where things aren't clear enough yet.

skidvd commented 6 years ago

Just curious what the latest status and plans are with respect to anyOf, allOf, oneOf?

I have been doing some investigations with 1.0.0-alpha.4 as well as 1.0.0-alpha.5, but they still do not appear to be recognized/supported.

Any updates would be greatly appreciated.

Anthropic commented 6 years ago

@skidvd there is no reason you can't roll an add-on easily to do the validation, I've already done it several times. The problem being there are far too many different ways to handle it so it is hard to make a standard handler for it. I am hoping to come up with a few alternative widget types that can be used to display them in a few different ways while still processing validation but my first job is upgrading how asf does validation and removing tv4 which is in progress at the moment.