guillotinaweb / ngx-schema-form

HTML form generation based on JSON Schema
MIT License
485 stars 173 forks source link

Help with making a GUI form builder #357

Open aahventures opened 4 years ago

aahventures commented 4 years ago

Hi! Thanks for your great work. I'm trying to create a GUI form builder similar in idea to https://github.com/json-schema-form/json-schema-builder, but with a different interface.

I've hacked a proof of concept together using custom bindings and temporarily a text area to edit the form property schema.

this.fieldBindings['/firstName'] = [{
   'click': this.selectPropertyToEdit.bind(this)
}];

selectPropertyToEdit(event, formProperty: FormProperty) {
  this.selectedProperty = formProperty.schema; // for display in the text area
  // use arrow function for closure
  this.onTextAreaChange = (data) => {
    const newSchema = JSON.parse(data);
    formProperty.schema.title = newSchema.title;
  }
}
<textarea (change)="onTextAreaChange($event.target.value)" [value]="selectedProperty | json"></textarea>

I'm having some problems and therefore questions:

  1. Can I bind all the fields without explicitly specifying the path? Something like a wildcard bind, e.g. this.fieldBindings['/*']?
  2. Can I modify an existing form property schema without explicitly setting each property? I've tried Object.assign(formProperty.schema, newSchema) and formProperty.schema = newSchema which both produces weird results, i.e. both end up duplicating the form field. There is nothing similar to formProperty.setValue() like formProperty.setSchema().

Any tips would be helpful also. Please point me in the right direction (if I'm going in the wrong one) or to any library/feature like this that already exists. Thanks.

daniele-pecora commented 4 years ago

Could you provide an example on Stackblitz?

aahventures commented 4 years ago

@daniele-pecora here is a crudely put together Stackblitz: https://stackblitz.com/edit/ngx-schema-form-gui-editor

The only two fields that are clickable are indicated with "CLICK ME." The only two property changes that will be applied back are title and placeholder. It's kind of an incomplete example, with no styling to help the user.

daniele-pecora commented 4 years ago

Question

  1. Can I bind all the fields without explicitly specifying the path? Something like a wildcard bind,

Answer
No you can't unless you specify a validator for every property you are interested in but in your example this will bind a validator to the very root property

    this.fieldValidators['/']=(value, property, form) => {
        console.log('##### validator / ',value, property, form)
    };

every time a child property changes the validator gets called.

Question

  1. Can I modify an existing form property schema without explicitly setting each property?

Answer
Currently it works in a way where you may change some settings of the schema definition like title or description with Object.assign but you can't add any elements or change the type of the widgets. You would have to pass a new schema to the sf-form component.

aahventures commented 4 years ago

Thanks for the response. For question 1 I'm using the custom bindings, in this case 'click', to detect when a field is selected to "be edited." Binding on the root property doesn't tell me which field in particular is being selected? Am I correct?

Also if you have any other thoughts or even libraries that could help us make a GUI form builder that would be helpful. Thanks.

aahventures commented 4 years ago

@daniele-pecora I have a somewhat working GUI form editor using custom bindings, but I'm hitting a performance issue now.

I have a fairly large form and I allow removing/changing requiredness of a field. The best way I could figure out how to update the <sf-form> is to give it a new schema. The performance was mostly fine until I added in the oneOf list options. Now it is unbearably slow (~10 seconds for the update).

I was doing some analysis of the performance using the browser developer tools and found most of the time was spent on this._runValidation() in the FormProperty class. I commented it out and the performance was much better. Of course, I don't want to carelessly remove the validation, but it seems like the source of slow performance.

The directions I can see:

  1. Use some internal mechanism of ngx-schema-form to remove/add properties and change its requiredness, so we don't need to revalidate the form each time. However, I'm not sure this is supported.
  2. In my project, extend somehow the FormProperty class to not run this._runValidation()
  3. In a pull request, somehow extend ngx-schema-form to allow turning on/off validation.

Any advice and help clarifying how "somehow" I would do any of the above would be appreciated.

daniele-pecora commented 4 years ago

@aahventures

I would provide a custom SchemaValidatorFactory which would be used in the UI Editor (See doc for details). The implementation of the SchemaValidatorFactory simply contains no validation at all. This should speed up the validation process.

aahventures commented 4 years ago

Thanks. Works well.

If I wanted to keep the validation and performance, then I would probably need to look into optimizing z-schema or replacing it?

daniele-pecora commented 4 years ago

@aahventures Probably 😁