hsuanyi-chou / shadcn-ui-expansions

More components built on top of shadcn-ui.
https://shadcnui-expansions.typeart.cc/
MIT License
832 stars 38 forks source link

Multiselect doesn't work with another objets ? #59

Closed philippedemaria closed 4 months ago

philippedemaria commented 6 months ago

Hi, I am a beginner withReact. And I follow your code but it doesn't work... I need help please. Your design is very nice...


const allSubjects: Subject[] = [
  {
    id: 1,
    title: "Nextjs",
    color: "purple",
    shorttitle: "N",
    ranking: 1,
    isActive: true,
  },
  {
    id: 2,
    title: "vite",
    color: "purple",
    shorttitle: "N",
    ranking: 2,
    isActive: true,
  },
  {
    id: 3,
    title: "nuxt",
    color: "purple",
    shorttitle: "N",
    ranking: 3,
    isActive: true,
  },
];

const OPTIONS: { value: string; label: string }[] = allSubjects.map(subject => ({
  value: subject.id.toString(),  
  label: subject.title,  
  disabled:false
}));
.......

<FormField
                control={form.control}
                name="subjects"
                render={({ field }) => (

                  <FormItem>
                    <FormLabel>Matières enseignées</FormLabel>
                    <FormControl>
                      <MultipleSelector
                        value={field.subjects} // The error is here but What is the error ???????? 
                        onChange={field.onChange}
                        defaultOptions={OPTIONS}
                        placeholder="Selectionner la ou les matières enseignées..."
                        emptyIndicator={
                          <p className="text-center text-lg leading-10 text-gray-600 dark:text-gray-400">
                            Aucune matière trouvée.
                          </p>
                        }
                      />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />```

but the options are disabled ! THANKSSSSSSS for your help.
hsuanyi-chou commented 6 months ago

Your value should fit the Option[] type.

{ 
   value: string; 
   label: string; 
   disable?: boolean; 
   fixed?: boolean; 
   /** The following is for `groupBy` key. You need to provide the above 4 props at least. */
   [key:string]: string | undefined; 
}
philippedemaria commented 6 months ago

I saw this type on the code but I need and object... I try :


<Form {...form}>
        <form onSubmit={form.handleSubmit(onSubmit)}>
              <FormField
                control={form.control}
                name="subjects"
                render={({ field }) => (

                  <FormItem>
                    <FormLabel>Matières enseignées</FormLabel>
                    <FormControl>
                      <MultipleSelector
                        value={field.value ? field.value.map(item => ({ value: item.id.toString(), label: item.title, disabled:false,fixed:true })) : []}
                        onChange={field.onChange}
                        defaultOptions={allSubjects.map(item => ({ value: item.id.toString(), label: item.shorttitle, disabled:false,fixed:true }))}
                        placeholder="Selectionner la ou les matières enseignées..."
                        emptyIndicator={
                          <p className="text-center text-lg leading-10 text-gray-600 dark:text-gray-400">
                            Aucune matière trouvée.
                          </p>
                        }
                      />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />
          <Button type="submit">Enregistrer</Button>
        </form>
      </Form>`

but the option of subjects are disabled. Even with this :
```javascript  const allsubjects = [
    { value: "1", label: "FR", disabled:false, fixed:false},
    { value: "2",      label: "M", disabled:false, fixed:false},
    { id: 3, value: "3", label: "SP" , disabled:false, fixed:false},
  ];```
hsuanyi-chou commented 6 months ago

It’s disable. Not disabled. Would you please provide a minimal reproducible example?

philippedemaria commented 6 months ago
import { Button } from "@/components/ui/button";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form";
import MultipleSelector from "@/components/ui/multipleSelector";
import { zodResolver } from "@hookform/resolvers/zod";

type TeacherSchoolFormProps = {
  allSubjects: FullSubject[];
};

export const TeacherSchoolForm = ({
  allSubjects,
}: TeacherSchoolFormProps) => {

  const form = useForm<TeacherSchool>({
    resolver: zodResolver(TeacherSchoolSchema),
    defaultValues: {
      levels: user?.teacher?.subjects,
    },
  });

const onSubmit = async (data: any) => {
    const result = await upsertUserTeacher(data, Number(user?.id));
  };

  return (
    <div>
      <Form {...form}>
        <form onSubmit={form.handleSubmit(onSubmit)}>
          <div className="grid sm:grid-cols-1 md:grid-cols-3 gap-4">
              <FormField
                control={form.control}
                name="subjects"
                render={({ field }) => (  
                  <FormItem>
                    <FormLabel>Matières enseignées</FormLabel>
                    <FormControl>
                      <MultipleSelector
                        value={field.value ? field.value.map(item => ({ value: item.id.toString(), label: item.title, disable:true,fixed:true })) : []}
                        onChange={field.onChange}
                        defaultOptions={allSubjects.map(item => ({ value: item.id.toString(), label: item.shorttitle, disable:true,fixed:true }))}
                        placeholder="Selectionner la ou les matières enseignées..."
                        emptyIndicator={
                          <p className="text-center text-lg leading-10 text-gray-600 dark:text-gray-400">
                            Aucune matière trouvée.
                          </p>
                        }
                      />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />
            </div>
          </div>
          <Button type="submit">Enregistrer</Button>
        </form>
      </Form>
    </div>
  );
};

export default TeacherSchoolForm;

and the types FullSubject and TeacherSchool are



export  const FullSubjectSchema = z.object({
  id         : z.coerce.number().positive(), //.transform((ranking) => Number(ranking)), 
  title      : z.string().trim().max(50,{ message: "Moins de 50 caractères."}),
  color      : z.string().trim(),  
  shorttitle : z.string().trim().max(5,{ message: "Moins de 5 caractères."}),
  ranking   : z.number(),
  isActive  : z.boolean().default(true),
})
export type FullSubject = z.infer<typeof FullSubjectSchema> 

export const TeacherSchoolSchema = z.object({
  subjects: z.array(FullSubjectSchema),
});

export type TeacherSchool = z.infer<typeof TeacherSchoolSchema>;
hsuanyi-chou commented 6 months ago

Is there mock data? It’d better to provide a repo Thanks.

philippedemaria commented 6 months ago

This one ? : https://github.com/philippedemaria/sacadoNextjs.git

or : git@github.com:philippedemaria/sacadoNextjs.git

or : gh repo clone philippedemaria/sacadoNextjs

but there is not mock data.. need a database....

hsuanyi-chou commented 6 months ago

Is this repo private? I can’t access to it. You’d better create a minimal example for your use case. I am not pretty sure how the issue happened. I think the default options won’t be disabled by default.

BTW, What’s your cmdk version? If it is 1.0.0, you’d better downgrade to 0.2.1.

downgrade reason

philippedemaria commented 6 months ago

yes the repo is private. I can get you an access. I search you on Git hub to invite you but I didn't find your name.

The default option is disabled by default. You are right : my cmdk version is 1.0.0

philippedemaria commented 6 months ago

But dosn't word !!! Sorry....

philippedemaria commented 6 months ago

OK, I clone your repo and I made again step by step and now it works !!!

philippedemaria commented 6 months ago

what I have to write in value ? ... field.value does not work and mine not either.... THANKSSS


const allSubjectsItems: Option[] = allSubjects.map((s)=> ({value:s.id+"",label : s.title }))

  <FormField
                control={form.control}
                name="subjects"
                render={({ field }) => (
                  <FormItem>
                    <FormLabel>Matières enseignées</FormLabel>
                    <FormControl>
                    <MultipleSelector
                        value={field.value ? field.value.map(item => ({
                          value: item.id+"",
                          label: item.title
                        })) : []}
                        onChange={field.onChange}
                        defaultOptions={allSubjectsItems}
                        placeholder="Selectionner un ou plusieurs niveaux..."
                        emptyIndicator={
                          <p className="text-center text-lg leading-10 text-gray-600 dark:text-gray-400">
                            Aucun niveau trouvé.
                          </p>
                        }
                      />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />
hsuanyi-chou commented 6 months ago

There is a bug related to shadcn's Command. (with version 1.0.0 of cmdk.) You can fix it by updating shadcn's Command.tsx.

hsuanyi-chou commented 6 months ago

You don't have to adjust the field value. just giving field.value.

The onChange in react-hook-form will give the new value to value.

All you have to do is to give the options that fit the Option[] and with your key. for example:

{ 
   value: string; 
   label: string; 
/**----- following is your key. --------*/
     id: number;
  title      : string;
  color      : string;
  shorttitle : string;
  ranking   : number;
  isActive  : boolean;
}

The react-hook-form will do the rest. and you can get all the values when form submit.

React-hook-form has a devTool. It's a good tool for debugging.

const allSubjectsItems: Option[] = allSubjects.map((s)=> ({value:s.id+"",label : s.title }))

 <FormField
               control={form.control}
               name="subjects"
               render={({ field }) => (
                 <FormItem>
                   <FormLabel>Matières enseignées</FormLabel>
                   <FormControl>
                   <MultipleSelector
+                       value={field.value}  // <--  just `field.value`
                       onChange={field.onChange}
                       defaultOptions={allSubjectsItems}
                       placeholder="Selectionner un ou plusieurs niveaux..."
                       emptyIndicator={
                         <p className="text-center text-lg leading-10 text-gray-600 dark:text-gray-400">
                           Aucun niveau trouvé.
                         </p>
                       }
                     />
                   </FormControl>
                   <FormMessage />
                 </FormItem>
               )}
             />

Do you familiar with react-hook-form? I think you may need to understand how to use react-hook-form first.