2 votes

React Material UI - Comment supprimer automatiquement des éléments d'une liste déroulante en fonction d'une autre valeur ?

J'ai 2 boîtes de sélection que je construis en utilisant le composant d'autocomplétion dans l'interface utilisateur - https://mui.com/material-ui/react-autocomplete/#checkboxes

J'ai un cas de bord que j'essaie de réparer :

  1. Un utilisateur sélectionne à la fois "Consumer Electronics" et "Fashion & Apparel" dans le premier champ de sélection des industries principales.
  2. Un utilisateur sélectionne ensuite, dans la deuxième boîte de sélection des sous-secteurs, "Ordinateurs et portables" et "Lunettes". (1 dans chaque groupe).
  3. Si un utilisateur supprime ensuite "Mode et habillement" de la première boîte de sélection, tous les articles sélectionnés dans cette catégorie doivent être supprimés dans la deuxième boîte de sélection.

enter image description here

exemple :

https://codesandbox.io/s/checkboxestags-demo-material-ui-forked-qox19g?file=/demo.tsx

Vous pouvez voir que dans le second "Autocomplete", j'utilise "filterOptions" pour n'afficher que les options qui dépendent du premier "Autocomplete".

Voir aussi data.json dans l'exemple pour les données brutes.

code :

    return (
      <Autocomplete
        multiple
        options={subIndustries}
        filterOptions={(x) =>
          x.filter((x) =>
            getValues("main_industries").find((m) => m.name === x.category)
          )
        }
        groupBy={(option) => option.category}
        disableCloseOnSelect
        getOptionLabel={(option) => option.name}
        onChange={(_, newValue: any) => {
          setValue("sub_industries", newValue, { shouldValidate: true });
        }}
        defaultValue={getValues("sub_industries")}
        onInputChange={(_, val) => {
          console.log(val);
        }}
        renderOption={(props, option, { selected }) => (
          <li {...props}>
            <Checkbox
              icon={uncheckedIcon}
              checkedIcon={checkedIcon}
              style={{ marginRight: 8 }}
              checked={selected}
            />
            {option.name}
          </li>
        )}
        renderInput={(params) => (
          <TextField
            {...params}
            label="Sub Industries"
            placeholder="Sub Industries"
          />
        )}
      />
    );
  };

2voto

Luis Paulo Pinto Points 2661

Avant tout, quelques points relatifs à votre code :

  1. Sur Autcocomplete de SubIndustrySelector vous devez utiliser la fonction value au lieu de defaultValue . defaultValue doit être utilisé lorsque le composant n'est pas contrôlé.

  2. Vous devez également inclure le isOptionEqualToValue prop aux deux Autocomplete . Votre code prétend l'utiliser. D'après Mui documents , isOptionEqualToValue est nécessaire pour :

Permet de déterminer si l'option représente la valeur donnée. Utilise par défaut une égalité stricte. Les deux arguments doivent être traités, une option ne peut correspondre qu'à une seule valeur.

Il suffit donc de garantir que l'option est égale à la valeur de :
isOptionEqualToValue={(option, value) => option.id === value.id}

En rapport avec le problème auquel vous êtes confronté, le SubIndustrySelector n'est pas mise à jour parce que vous contrôlez les balises qui doivent être rendues à l'aide de la fonction getValues au lieu de watch de react-hook-form .

Según react-hook-form docs, getValues sont :

Une aide optimisée pour la lecture des valeurs de formulaire. La différence entre watch et getValues est que getValues ne déclenchera pas de re-rendu et ne s'abonnera pas aux changements de saisie

(Vous pouvez en savoir plus ici y ici .)

Ainsi, votre SubIndustrySelector devrait ressembler à ceci :

// WATCH ON sub_industries
  const watchSubIndustries = watch("sub_industries");

  const SubIndustrySelector = () => {
    if (!dataJson) {
      return <Skeleton height={"100%"} variant="text" />;
    }

    const subIndustries = dataJson
      .map((i) => {
        return i.industries;
      })
      .flat()
      .filter(Boolean);

    return (
      <Autocomplete
        multiple
        options={subIndustries}
        filterOptions={(x) =>
          x.filter((x) =>
            getValues("main_industries").find((m) => m.name === x.category)
          )
        }
        groupBy={(option) => option.category}
        disableCloseOnSelect
        getOptionLabel={(option) => option.name}
        // isOptionEqualToValue CONTROL
        isOptionEqualToValue={(option, value) => option.id === value.id}
        onChange={(_, newValue: any) => {
          setValue("sub_industries", newValue, { shouldValidate: true });
        }}
        //defaultValue={watchSubIndustries}
        value={watchSubIndustries}
        renderOption={(props, option, { selected }) => {
          return (
            <li {...props}>
              <Checkbox
                icon={uncheckedIcon}
                checkedIcon={checkedIcon}
                style={{ marginRight: 8 }}
                checked={selected}
              />
              {option.name}
            </li>
          );
        }}
        renderInput={(params) => {
          return (
            <TextField
              {...params}
              label="Sub Industries"
              placeholder="Sub Industries"
            />
          );
        }}
      />
    );
  };

Vous pouvez vérifier que le code ci-dessus fonctionne comme suit exemple de code .

Comme vous pouvez le voir, les changements que j'ai effectués sont les suivants :

  1. avant le SubIndustrySelector j'ai ajouté une surveillance à sub_industries -> watchSubIndustries .
  2. Ajouté isOptionEqualToValue étai
  3. Modifié defaultValue a value et ajouter watchSubIndustries comme valeur.

Si vous avez des questions, n'hésitez pas à les poser dans les commentaires.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X