Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass in parameters to custom field when applying component to AutoField. #1231

Closed
emmett08 opened this issue Feb 28, 2023 · 4 comments
Closed
Assignees
Labels
Type: Question Questions and other discussions

Comments

@emmett08
Copy link

emmett08 commented Feb 28, 2023

Firstly, thank you to make uniforms open source. I'm trying to create a generic checkbox list to show in AutoForm (below). The function takes parameters so I can reuse it. I'm missing something obvious with UnknownObject -> Record so not sure if this is a feature request or usage issue? (Nor how to style custom components so that the background changes colour like OOTB autofields do).

export function CheckboxList({ checkboxes }: CheckboxListProps) {
  return (
    <FormControl component="fieldset">
      <FormGroup>
        {checkboxes.map((checkbox) => (
          <FormControlLabel
            key={checkbox.key}
            control={
              <Checkbox
                checked={checkbox.checked}
                onChange={checkbox.onChange}
              />
            }
            label={checkbox.label}
          />
        ))}
      </FormGroup>
    </FormControl>
  );
}

const default Options = connectField<CheckboxListProps, unknown>(CheckboxList);

<AutoField name="environments" field="environments" component={Options} with={checkboxes} />

@radekmie radekmie self-assigned this Feb 28, 2023
@radekmie radekmie added the Type: Question Questions and other discussions label Feb 28, 2023
@radekmie
Copy link
Contributor

Hi @emmett08. It looks like you are creating a custom component. In that case, you probably want to wire it up with the form's model. Here's my first question - what is the checkboxes in your example? Or rather, how would you like to use it?

Second thing is the AutoField usage: are the field and with props specific application? These are not used in uniforms.

And lastly, remember that all fields rendered by uniforms have to be a part of the schema, and if you'd like to render some fields dynamically (e.g., make the number of fields depend on other fields), it has to be reflected in the schema too.

@emmett08
Copy link
Author

emmett08 commented Mar 1, 2023

Hi @radekmie - field was a github copilot addition which I didn't check. with is what I'd like to have to pass an array to the component but not needed since I haven't wired the component to the forms model (I thought that was the function of connectField e.g. connectField<CheckboxListProps, unknown>(CheckboxList);).

How do I pass in the choices array to the component when registering it in an AutoForm please?

const choices = [
  {key: 'aws', label: 'AWS', checked: false, onChange: (event: React.ChangeEvent<HTMLInputElement>) => {console.log(event.target.checked)}},
  {key: 'gcp', label: 'GCP', checked: false, onChange: (event: React.ChangeEvent<HTMLInputElement>) => {console.log(event.target.checked)}}
];

// custom uniforms component
// <CheckboxList checkboxes={choices} />

This is where I use the component and connectField:

export type VaultProps = HTMLFieldProps<string, HTMLDivElement> &
  CheckboxListProps;

export const sourceApplicationLocations: CheckboxListProps = {
  checkboxes: [
    {
      key: "aws",
      label: "AWS",
      checked: false,
      onChange: (event: React.ChangeEvent<HTMLInputElement>) => {
        console.log(event.target.checked);
      },
    },
    {
      key: "gcp",
      label: "GCP",
      checked: false,
      onChange: (event: React.ChangeEvent<HTMLInputElement>) => {
        console.log(event.target.checked);
      },
    },
  ],
};

const XOptions = connectField<CheckboxListProps, unknown>(CheckboxList);
export default XOptions;

@emmett08
Copy link
Author

emmett08 commented Mar 8, 2023

In case this helps anyone else...

import { Autocomplete, Box, Paper, TextField } from "@mui/material";
import { connectField, HTMLFieldProps } from "uniforms";

export type EnvironmentProps = HTMLFieldProps<string, HTMLDivElement> & {
  environments: string[];
};

function Environment({ value, label, environments }:EnvironmentProps) {

  const CustomPaper = (props: any) => {
    return <Paper elevation={8} {...props} />;
  };
  
  return (
    <Box sx={{ mt: 1, mb: 1 }}>
      <Autocomplete
        multiple
        id="selected-environments-outlined"
        // onChange={onSelectedValuesChange}
        options={environments.map((option) => option)}
        getOptionLabel={(option) => option} 
        isOptionEqualToValue={(a, b) => a === b}
        PaperComponent={CustomPaper}
        filterSelectedOptions
        renderInput={(params) => (
          <TextField
            {...params}
            variant="outlined"
            label={label} // TODO: add props. This has no context
            placeholder={value} // TODO: add props. This has no context
            // onChange={handleOnChange}
          />
        )}
      />
    </Box>
  );
}

export default connectField(Environment);


Usage:

export type EnvironmentsData = {
    globalPlatform: string[];
};

const schema: JSONSchemaType<EnvironmentsData> = {
    title: 'Environments Required',
    type: 'object',
    properties: {
        globalPlatform: {
            type: 'array',
            minItems: 0,
            items: {
              type: 'string'
            },
            uniforms: { component: EnvironmentField, value: "Desired Platforms", label: 'Global', environments: ['Dev', 'Stage', 'Prod', 'Mgmt'] }
        },
    },
    required: [],
};

@radekmie
Copy link
Contributor

radekmie commented Mar 8, 2023

I'm glad you figured it out! Just to make it clear: what you proposed in this comment could work, but is not in-align with how uniforms are meant to be used. The onChange should not be passed to any field, as a field is "just" a part of the form, not a standalone input.

And as for this code - you could simplify it a little. The Environment components has no need to be wrapped in connectField and it'd be enough to forward all of the props from it to the TextField inside. If you'd need to read a value or other prop, you can always use useField to do that.

I'll close this one, but feel free to comment further.

@radekmie radekmie closed this as completed Mar 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Question Questions and other discussions
Projects
Archived in project
Development

No branches or pull requests

2 participants