guillotinaweb / ngx-schema-form

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

Collapsible Group Widget #60

Open AlmogShaul opened 7 years ago

AlmogShaul commented 7 years ago

Hi I need help to make new widget that take one or more properties and group them in a collapsible section There is not Wiki for Widget making so I will appreciate your help.

fbessou commented 7 years ago

Hi, To create a custom widget you need to create a component and register it the provided WidgetRegistry. A good start is to take a look at the angular2-schema-form demo which contains a wizard widget. The following component permits to display your form with collapsible sections (using ngx-accordion):

import { Component } from '@angular/core';
import { ObjectLayoutWidget } from 'angular2-schema-form/src';
@Component({
  selector: 'sf-collapsible',
  template: `
  <accordion>
    <accordion-group *ngFor="let fieldset of schema.fieldsets; let index = index">
      <accordion-heading>{{fieldset.title || "Section "+index}}</accordion-heading>
      <sf-form-element *ngFor='let fieldId of fieldset.fields' [formProperty]='formProperty.getProperty(fieldId)' >
      </sf-form-element>
    </accordion-group>
  </accordion>
  `
})
export class CollapsibleWidget extends ObjectLayoutWidget {
}

Then add this component in the declarations and entryComponents of a module and register it in the WidgetRegistry (for example in the AppModule):

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { SchemaFormModule, WidgetRegistry, DefaultWidgetRegistry } from 'angular2-schema-form/src';
import { CollapsibleWidget } from './collapsible.widget';
import { AccordionModule } from 'ngx-accordion';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent,
   CollapsibleWidget
  ],
  entryComponents: [CollapsibleWidget],
  imports: [
    BrowserModule,
    SchemaFormModule,
    AccordionModule
  ],
  bootstrap: [AppComponent]
})
export class AppModule {
  constructor(widgetRegistry: WidgetRegistry) {
    widgetRegistry.register("collapsible", CollapsibleWidget)
  }
}

The following schema will then be rendered using this widget:

{
  "type": "object",
  "properties": {
    "firstName":{"type": "string", "description": "First Name"},
    "lastName":{"type": "string", "description": "Last Name"},
    "age":{"type": "number", "description": "Age"},
    "address":{
      "type": "object",
      "properties":{
        "city": {"type": "string", "description": "City"},
        "streetNbr": {"type": "string", "description": "City"}
      }
    }
  },
  "fieldsets": [{
    "fields": ["firstName", "lastName", "age"]
  },{
  "title": "Address",
  "fields": ["address"]
  }]
}

PS: Currently there is no official documentation for how to make custom widgets but you can take inspiration from the default ones to see how they are made.

AlmogShaul commented 7 years ago

@fbessou : Thanks for the detailed answer!

AlmogShaul commented 7 years ago

I tried using your code, and after installing the ngx-accordion adn adding the right stuff to the app moduel, I got the follosing exception:

Unhandled Promise rejection: Template parse errors: Can't bind to 'formProperty' since it isn't a known property of 'sf-form-element'.

my app module loloks like this:

@NgModule({ declarations: [ AppComponent, MaterialComponent, FormComponent, CollapsibleWidget ], entryComponents: [CollapsibleWidget], imports: [ AccordionModule, AppRoutingModule, SchemaFormModule, MaterialModule.forRoot(), BrowserModule, FormsModule, HttpModule ], providers: [{provide: WidgetRegistry, useClass: DefaultWidgetRegistry}], bootstrap: [AppComponent] }) export class AppModule { constructor(widgetRegistry: WidgetRegistry) { widgetRegistry.register('collapsible', CollapsibleWidget) } }

AlmogShaul commented 7 years ago

After 0.5a day... You changed the selectors.... I think that a change log will be very helpful.