참고
위의 링크를 참고하여 아래의 예시에서 시작한다.
import React, { useState } from "react";
import TextField from "@mui/material/TextField";
import Autocomplete from "@mui/material/Autocomplete";
import Stack from "@mui/material/Stack";
const top100Films = [
{ title: "The Shawshank Redemption", year: 1994 },
...
{ title: "Monty Python and the Holy Grail", year: 1975 },
];
const MyAutoComplete = () => {
const defaultProps = {
options: top100Films,
getOptionLabel: (option) => option.title,
};
const [value, setValue] = useState(null);
return (
<div>
<p>{value ? value.title : null}</p>
<Stack spacing={1} sx={{ width: 300, marginLeft: 5 }}>
<Autocomplete
{...defaultProps}
id="auto-complete"
autoComplete
includeInputInList
value={value}
onChange={(event, newValue) => {
setValue(newValue);
}}
renderInput={(params) => (
<TextField {...params} label="목록" variant="standard" />
)}
/>
</Stack>
</div>
);
};
export default MyAutoComplete;
top100Films의 Title이 순서대로 출력되는 것을 알 수 있다.
목록 라벨 변경하기
목록의 라벨을 변경하려면 getOptionLabel을 수정하면 된다.
top100Films에 있는 정보인 year도 같이 출력하도록 해보자.
const defaultProps = {
options: top100Films,
getOptionLabel: (option) => `${option.year} : ${option.title}`,
};
그러면 year : title 형식으로 목록이 변경된다.
카테고리, 그룹화
year : title 형식보다는 연도별로 영화 제목을 정리하는 것이 더 깔끔해보인다.
Autocomplete에는 그룹화 기능이 제공된다.
먼저 defaultProps 삭제하고 아래와 같이 코드를 추가하자.
options에서 top100Films를 연도가 작은 순서대로 정렬하였다.
그리고 groupBy를 이용해 연도별로 영화를 묶는다.
getOptionLabel은 다시 title만 출력하도록 하였다.
<Stack spacing={1} sx={{ width: 300, marginLeft: 5 }}>
<Autocomplete
/* group */
options={ top100Films.sort((a,b) => (a.year - b.year))}
groupBy={(option) => option.year}
getOptionLabel={(option) => option.title}
id="auto-complete"
autoComplete
includeInputInList
value={value}
onChange={(event, newValue) => {
setValue(newValue);
}}
renderInput={(params) => (
<TextField {...params} label="목록" variant="standard" />
)}
/>
</Stack>
연도별로 영화 타이틀이 카테고리화 되었지만, 너무 세분화되어서 정신이 없어보인다.
그러므로 10년 단위로 그룹을 나눠보자.
top100Films에서 year10 변수를 추가하여 top100Films10Year를 만든다.
(ex. year : 1931이라면 year10은 1930이 된다.)
그리고 options에서 year10 기준으로 정렬, groupBy도 year10으로 그룹을 묶는다.
const top100Films10Year = top100Films.map((item) => {
const year10 = item.year - (item.year % 10);
return {
...item,
year10,
};
});
return (
<div>
<p>{value ? value.title : null}</p>
<Stack spacing={1} sx={{ width: 300, marginLeft: 5 }}>
<Autocomplete
/* group */
options={ top100Films10Year.sort((a,b) => (a.year10 - b.year10))}
groupBy={(option) => option.year10}
getOptionLabel={(option) => option.title}
id="auto-complete"
autoComplete
includeInputInList
value={value}
onChange={(event, newValue) => {
setValue(newValue);
}}
renderInput={(params) => (
<TextField {...params} label="목록" variant="standard" />
)}
/>
</Stack>
</div>
);
다음과 같이 10년 단위로 그룹이 나눠지게 되어 조금 더 깔끔해졌다.
필터링 옵션
기본적으로 Autocomplete가 제공하는 필터링 옵션은 대소문자를 구분하지 않고 입력한 문자열을 포함하는 것이다.
이제 대소문자를 구분하도록 직접 myFilter를 구현해보자.
filterOptions={(list, input) ... } 에서 list는 현재 Autocomplete의 목록임을 알 수 있다.
그리고 input의 inputValue에 현재 입력된 값이 들어있다.
myFilter에서 inputValue가 없는 경우는 모두 출력하고, 그 외에는 해당 문자열을 포함하는 경우만 출력한다.
여기서 대소문자를 구분하지 않는 로직이 없으므로, 정확히 입력된 값을 포함하는 경우만 필터링된다.
const myFilter = (item, inputValue) => {
if (inputValue === "") return true;
return item.title.includes(inputValue);
};
return (
<div>
<p>{value ? value.title : null}</p>
<Stack spacing={1} sx={{ width: 300, marginLeft: 5 }}>
<Autocomplete
/* group */
options={top100Films10Year.sort((a, b) => a.year10 - b.year10)}
groupBy={(option) => option.year10}
getOptionLabel={(option) => option.title}
/* filter */
filterOptions={(list, input) =>
list.filter((item) => myFilter(item, input.inputValue))
}
...
renderInput={(params) => (
<TextField {...params} label="목록" variant="standard" />
)}
/>
</Stack>
</div>
);
위와 같이 바뀐 경우 "the"가 포함된 목록만 나타나며, "The"만 있는 경우는 볼 수 없게 된다.
다중 선택
여러 옵션을 출력하기 위해 useState로 변수를 추가하자.
const [multipleValue, setMultipleValue] = useState([]);
multiple과 filterSelectedOptions 옵션을 추가하면 여러 옵션을 선택할 수 있다.
<Autocomplete
multiple
id="tags-outlined"
options={top100Films}
getOptionLabel={(option) => option.title}
//defaultValue={[top100Films[13]]}
filterSelectedOptions
renderInput={(params) => (
<TextField
{...params}
label="filterSelectedOptions"
placeholder="Favorites"
/>
)}
onChange={(event, newValue) => {
const util = require("util");
let str = newValue.map((data) => {
if (typeof data === "object") {
return util.inspect(data);
}
return data;
});
console.log(str);
setMultipleValue(str);
}}
/>
<p>{multipleValue}</p>
전체 코드는 다음과 같다.
import React, { useState } from "react";
import TextField from "@mui/material/TextField";
import Autocomplete from "@mui/material/Autocomplete";
import Stack from "@mui/material/Stack";
const top100Films = [
{ title: "The Shawshank Redemption", year: 1994 },
{ title: "The Godfather", year: 1972 },
{ title: "The Godfather: Part II", year: 1974 },
{ title: "The Dark Knight", year: 2008 },
{ title: "12 Angry Men", year: 1957 },
{ title: "Schindler's List", year: 1993 },
{ title: "Pulp Fiction", year: 1994 },
{
title: "The Lord of the Rings: The Return of the King",
year: 2003,
},
{ title: "The Good, the Bad and the Ugly", year: 1966 },
{ title: "Fight Club", year: 1999 },
{
title: "The Lord of the Rings: The Fellowship of the Ring",
year: 2001,
},
{
title: "Star Wars: Episode V - The Empire Strikes Back",
year: 1980,
},
{ title: "Forrest Gump", year: 1994 },
{ title: "Inception", year: 2010 },
{
title: "The Lord of the Rings: The Two Towers",
year: 2002,
},
{ title: "One Flew Over the Cuckoo's Nest", year: 1975 },
{ title: "Goodfellas", year: 1990 },
{ title: "The Matrix", year: 1999 },
{ title: "Seven Samurai", year: 1954 },
{
title: "Star Wars: Episode IV - A New Hope",
year: 1977,
},
{ title: "City of God", year: 2002 },
{ title: "Se7en", year: 1995 },
{ title: "The Silence of the Lambs", year: 1991 },
{ title: "It's a Wonderful Life", year: 1946 },
{ title: "Life Is Beautiful", year: 1997 },
{ title: "The Usual Suspects", year: 1995 },
{ title: "Léon: The Professional", year: 1994 },
{ title: "Spirited Away", year: 2001 },
{ title: "Saving Private Ryan", year: 1998 },
{ title: "Once Upon a Time in the West", year: 1968 },
{ title: "American History X", year: 1998 },
{ title: "Interstellar", year: 2014 },
{ title: "Casablanca", year: 1942 },
{ title: "City Lights", year: 1931 },
{ title: "Psycho", year: 1960 },
{ title: "The Green Mile", year: 1999 },
{ title: "The Intouchables", year: 2011 },
{ title: "Modern Times", year: 1936 },
{ title: "Raiders of the Lost Ark", year: 1981 },
{ title: "Rear Window", year: 1954 },
{ title: "The Pianist", year: 2002 },
{ title: "The Departed", year: 2006 },
{ title: "Terminator 2: Judgment Day", year: 1991 },
{ title: "Back to the Future", year: 1985 },
{ title: "Whiplash", year: 2014 },
{ title: "Gladiator", year: 2000 },
{ title: "Memento", year: 2000 },
{ title: "The Prestige", year: 2006 },
{ title: "The Lion King", year: 1994 },
{ title: "Apocalypse Now", year: 1979 },
{ title: "Alien", year: 1979 },
{ title: "Sunset Boulevard", year: 1950 },
{
title:
"Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb",
year: 1964,
},
{ title: "The Great Dictator", year: 1940 },
{ title: "Cinema Paradiso", year: 1988 },
{ title: "The Lives of Others", year: 2006 },
{ title: "Grave of the Fireflies", year: 1988 },
{ title: "Paths of Glory", year: 1957 },
{ title: "Django Unchained", year: 2012 },
{ title: "The Shining", year: 1980 },
{ title: "WALL·E", year: 2008 },
{ title: "American Beauty", year: 1999 },
{ title: "The Dark Knight Rises", year: 2012 },
{ title: "Princess Mononoke", year: 1997 },
{ title: "Aliens", year: 1986 },
{ title: "Oldboy", year: 2003 },
{ title: "Once Upon a Time in America", year: 1984 },
{ title: "Witness for the Prosecution", year: 1957 },
{ title: "Das Boot", year: 1981 },
{ title: "Citizen Kane", year: 1941 },
{ title: "North by Northwest", year: 1959 },
{ title: "Vertigo", year: 1958 },
{
title: "Star Wars: Episode VI - Return of the Jedi",
year: 1983,
},
{ title: "Reservoir Dogs", year: 1992 },
{ title: "Braveheart", year: 1995 },
{ title: "M", year: 1931 },
{ title: "Requiem for a Dream", year: 2000 },
{ title: "Amélie", year: 2001 },
{ title: "A Clockwork Orange", year: 1971 },
{ title: "Like Stars on Earth", year: 2007 },
{ title: "Taxi Driver", year: 1976 },
{ title: "Lawrence of Arabia", year: 1962 },
{ title: "Double Indemnity", year: 1944 },
{
title: "Eternal Sunshine of the Spotless Mind",
year: 2004,
},
{ title: "Amadeus", year: 1984 },
{ title: "To Kill a Mockingbird", year: 1962 },
{ title: "Toy Story 3", year: 2010 },
{ title: "Logan", year: 2017 },
{ title: "Full Metal Jacket", year: 1987 },
{ title: "Dangal", year: 2016 },
{ title: "The Sting", year: 1973 },
{ title: "2001: A Space Odyssey", year: 1968 },
{ title: "Singin' in the Rain", year: 1952 },
{ title: "Toy Story", year: 1995 },
{ title: "Bicycle Thieves", year: 1948 },
{ title: "The Kid", year: 1921 },
{ title: "Inglourious Basterds", year: 2009 },
{ title: "Snatch", year: 2000 },
{ title: "3 Idiots", year: 2009 },
{ title: "Monty Python and the Holy Grail", year: 1975 },
];
const MyAutoComplete = () => {
// const defaultProps = {
// options: top100Films,
// getOptionLabel: (option) => `${option.year} : ${option.title}`,
// };
const [value, setValue] = useState(null);
const [multipleValue, setMultipleValue] = useState([]);
const top100Films10Year = top100Films.map((item) => {
const year10 = item.year - (item.year % 10);
return {
...item,
year10,
};
});
const myFilter = (item, inputValue) => {
if (inputValue === "") return true;
return item.title.includes(inputValue);
};
return (
<div>
<p>{value ? value.title : null}</p>
<Stack spacing={1} sx={{ width: 300, marginLeft: 5 }}>
<Autocomplete
/* group */
options={top100Films10Year.sort((a, b) => a.year10 - b.year10)}
groupBy={(option) => option.year10}
getOptionLabel={(option) => option.title}
/* filter */
filterOptions={(list, input) =>
list.filter((item) => myFilter(item, input.inputValue))
}
id="auto-complete"
autoComplete
includeInputInList
value={value}
onChange={(event, newValue) => {
setValue(newValue);
}}
renderInput={(params) => (
<TextField {...params} label="목록" variant="standard" />
)}
/>
</Stack>
<hr style={{borderColor: "black"}} />
<Autocomplete
multiple
id="tags-outlined"
options={top100Films}
getOptionLabel={(option) => option.title}
//defaultValue={[top100Films[13]]}
filterSelectedOptions
renderInput={(params) => (
<TextField
{...params}
label="filterSelectedOptions"
placeholder="Favorites"
/>
)}
onChange={(event, newValue) => {
const util = require("util");
let str = newValue.map((data) => {
if (typeof data === "object") {
return util.inspect(data);
}
return data;
});
console.log(str);
setMultipleValue(str);
}}
/>
<p>{multipleValue}</p>
</div>
);
};
export default MyAutoComplete;
결과는 링크에서 확인하자.
댓글