I need to react to the next click in the material ui stepper. I want to slide up to the top of the form on nexthandler

Due to some long forms users want to have next and previous click to go to the top of the #stepper form. Need some tips on how to make this happen. I guess a customrender, but since a stepper with navbuttons already exists i need some pointers:)

Hi @trillian74,

Yes, a custom renderer is the way to go. The stepper renderer is quite simplistic so I would like to suggest to copy it and modify it your needs. You can find it here.

Thanks for the suggestion. I’ll do a copy of the code and transform it to my needs.

Ole

I tried creating a second version in my source, but the form disappears after the final rendering when i use it. Do i have to create my own “version” of the material renderers package?

Ole

Hi @sdirix

I tried creating a second version in my source, but the form disappears after the final rendering when i use it. Do i have to create my own “version” of the material renderers package?

Ole

Hi @trillian74,

You need to create a custom renderer which is added to renderer registry (i.e. an array of tester/renderer pairs). There is no need to build an own version of the Material renderers.

You can see how this is done in the tutorial or the React seed.

thanxs @sdirix - i’ve done some custom renderes with success. This one though, gives me problems. The way i see it is that i can copy that file into my code - exactly as it is and set another rank number and this one should be selected instead. when i add it to my renderes… eventhough i have materials renderes in my form?


const renderers = [
  ...materialRenderers,
  //register custom renderers
  {
    tester: materialCategorizationStepperTester, // this one is mine (but equal)
    renderer: MaterialCategorizationStepperLayoutRenderer,// this one is mine (but equalish... have rank number 3 instead of 2)
  },
  {
    tester: contactPickerManagementControlTester,
    renderer: ContactPickerManagementControl,
  },
  {
    tester: peoplePickerManagementControlTester,
    renderer: PeoplePickerManagementControl,
  },
  {
    tester: singleChipSelectControlTester,
    renderer: SingleChipSelectSingleControl,
  },
  { tester: multiChipSelectControlTester, renderer: MultiChipSelectControl },
];

so when i apply the uischema it just dissapears from the gui… without an error message.
Any suggestions?

@sdirix i found out why in the end. I don’t properly understand why it differs, but the property visible was undefined on the contrary to the one in material renderers.

public render() {
    const {
      data,
      path,
      renderers,
      schema,
      uischema,
      visible = true, // i just hardcoded this - but i would like it not to be
      cells,
      config,
      ajv,
    } = this.props;
    const categorization = uischema as Categorization;
    const activeCategory = this.state.activeCategory;
    const appliedUiSchemaOptions = merge({}, config, uischema.options);
    const buttonWrapperStyle = {
      textAlign: "right" as "right",
      width: "100%",
      margin: "1em auto",
    };
    const buttonNextStyle = {
      float: "right" as "right",
    };
    const buttonStyle = {
      marginRight: "1em",
    };
    const childProps: MaterialLayoutRendererProps = {
      elements: categorization.elements[activeCategory].elements,
      schema,
      path,
      direction: "column",
      visible,
      renderers,
      cells,
    };

Not sure how this can happen. Our bindings should make sure that visible is set. Can you debug to find the cause of the issue? Are @jsonforms/core, @jsonforms/react and @jsonforms/material-renderers on the exact same version?

@jsonforms/core”: “2.5.2”,
@jsonforms/material-renderers”: “2.5.2”,
@jsonforms/react”: “2.5.2”,

@sdirix Find my code below only edit is that the next button is named Next123 and rank is 3

The stepper from the package works alright, but this one makes it dissapear when it enter

 <div>
          <MaterialLayoutRenderer {...childProps} />
        </div>
import * as React from "react";
import merge from "lodash/merge";
import { Button, Hidden, Step, StepButton, Stepper } from "@material-ui/core";
import {
  and,
  Categorization,
  categorizationHasCategory,
  Category,
  isVisible,
  optionIs,
  RankedTester,
  rankWith,
  StatePropsOfLayout,
  uiTypeIs,
} from "@jsonforms/core";
import { RendererComponent, withJsonFormsLayoutProps } from "@jsonforms/react";
import {
  AjvProps,
  MaterialLayoutRenderer,
  MaterialLayoutRendererProps,
  withAjvProps,
} from "@jsonforms/material-renderers";

export const myMaterialCategorizationStepperTester: RankedTester = rankWith(
  3,
  and(
    uiTypeIs("Categorization"),
    categorizationHasCategory,
    optionIs("variant", "stepper")
  )
);

export interface CategorizationStepperState {
  activeCategory: number;
}

export interface MaterialCategorizationStepperLayoutRendererProps
  extends StatePropsOfLayout,
    AjvProps {
  data: any;
}

export class MyMaterialCategorizationStepperLayoutRenderer extends RendererComponent<
  MaterialCategorizationStepperLayoutRendererProps,
  CategorizationStepperState
> {
  constructor(props: MaterialCategorizationStepperLayoutRendererProps) {
    super(props);
    this.state = { activeCategory: 0 };
  }

  public handleStep = (step: number) => {
    this.setState({ activeCategory: step });
  }

  public render() {
    const {
      data,
      path,
      renderers,
      schema,
      uischema,
      visible,
      cells,
      config,
      ajv,
    } = this.props;
    const categorization = uischema as Categorization;
    const activeCategory = this.state.activeCategory;
    const appliedUiSchemaOptions = merge({}, config, uischema.options);
    const buttonWrapperStyle = {
      textAlign: "right" as "right",
      width: "100%",
      margin: "1em auto",
    };
    const buttonNextStyle = {
      float: "right" as "right",
    };
    const buttonStyle = {
      marginRight: "1em",
    };
    const childProps: MaterialLayoutRendererProps = {
      elements: categorization.elements[activeCategory].elements,
      schema,
      path,
      direction: "column",
      visible,
      renderers,
      cells,
    };
    console.log(childProps);
    const categories = categorization.elements.filter((category: Category) =>
      isVisible(category, data, undefined, ajv)
    );
    return (
      <Hidden xsUp={!visible}>
        <Stepper activeStep={activeCategory} nonLinear>
          {categories.map((e: Category, idx: number) => (
            <Step key={e.label}>
              <StepButton onClick={() => this.handleStep(idx)}>
                {e.label}
              </StepButton>
            </Step>
          ))}
        </Stepper>
        <div>
          <MaterialLayoutRenderer {...childProps} />
        </div>
        {!!appliedUiSchemaOptions.showNavButtons ? (
          <div style={buttonWrapperStyle}>
            <Button
              style={buttonNextStyle}
              variant="contained"
              color="primary"
              disabled={activeCategory >= categories.length - 1}
              onClick={() => this.handleStep(activeCategory + 1)}
            >
              Next123
            </Button>
            <Button
              style={buttonStyle}
              color="secondary"
              variant="contained"
              disabled={activeCategory <= 0}
              onClick={() => this.handleStep(activeCategory - 1)}
            >
              Previous
            </Button>
          </div>
        ) : (
          <></>
        )}
      </Hidden>
    );
  }
}

export default withJsonFormsLayoutProps(
  withAjvProps(MyMaterialCategorizationStepperLayoutRenderer)
);

Are you actually registering the wrapped default export or did you by accident register the raw renderer? That would explain why the props are not properly determined. Did you debug the withJsonFormsLayoutProps binding? Is it called?

@sdirix thanx for your patience with me:)
I’m not sure what you mean about register the raw renderer. Do you mean that i import from is wrong and that i should create my own?

import {
  AjvProps,
  MaterialLayoutRenderer,
  MaterialLayoutRendererProps,
  withAjvProps,
} from "@jsonforms/material-renderers";

Hi @trillian74,

I meant the way how your custom control is registered. Can you show where you add the renderer and the tester to the renderers registry and how you import your custom renderer?

@sdirix Hi again. You are so right. i had

 {
    tester: myMaterialCategorizationStepperTester,
    renderer: MyMaterialCategorizationStepperLayoutRenderer,  // this was my bad
  },

changed it to

 {
    tester: myMaterialCategorizationStepperTester,
    renderer: MyMaterialCategorizationStepperLayout,
  },

man, it was right in front of me. thank you for your patience.

1 Like