<div id="app"></div>
h2{
position:absolute;
}
.main-container{
width:100%;
display:flex;
justify-content:center;
}
.flex-wrapper{
display:flex;
margin-left:100px;
}
.flex-container{
width:100%;
display:flex;
flex-direction:column;
align-items:center;
}
.searchbar{
border:solid black;
width:250px;
height:25px;
}
.search-results{
text-align:left;
width: 250px;
border:solid black;
margin-top:5px;
}
.search-result-item{
margin: 0 0 8px 2px;
}
.search-result-item:hover{
cursor:pointer;
color:red;
}
.shopping-list{
display:flex;
flex-direction:column;
margin-top:78px;
width: 300px;
}
/*
* https://frontendeval.com/questions/shopping-list
*
* Create a shopping list app with autocomplete item entry
*/
const SearchBar=()=>{
const[userInput,setUserInput]=React.useState(null)
const [searchResults,setSearchResults]=React.useState(null)
const apiBaseUrl="https://api.frontendeval.com/fake/food/"
const [shoppingList,setShoppingList] = React.useState([])
const [isChecked,setIsChecked]=React.useState(false)
//render input element
//call api upon input element change
//
const debounce = (func, wait) => {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
};
React.useEffect(()=>{
let apiUrl = apiBaseUrl+userInput
//debounce userInput
if(userInput!==null || userInput!==''){
fetch(apiUrl)
.then(response => response.text())
.then(data =>debounce(setSearchResults(JSON.parse(data)),500))
}
},[userInput])
const handleInputChange=(e)=>{
let value=e.target.value===''?null:e.target.value
setUserInput(value)
}
const addItem=(item)=>{
//set state to clicked item
let updatedShoppingList=[...shoppingList]
updatedShoppingList.push(item)
setShoppingList(updatedShoppingList)
}
const removeItem=(id)=>{
let filteredList=shoppingList.filter((itemObj)=>itemObj.id!==id)
console.log("id",id)
setShoppingList(filteredList)
}
const checkedHandler=(e,id)=>{
//map through shoppingListCopy
//if same id => update isChecked val
let shoppingListCopy=[...shoppingList]
let newShoppingList=shoppingListCopy.map((itemObj)=>{
if(itemObj.id===id){
itemObj.isChecked=e.target.checked
return itemObj
}
else{
return itemObj
}
})
setShoppingList(newShoppingList)
}
return(
<div className="flex-wrapper">
<div className="flex-container">
<h1>My Shopping List</h1>
<input className="searchbar" onChange={handleInputChange}/>
{searchResults && searchResults.length>0&&
<div className="search-results">
{searchResults.map((item,index)=>
<div className="search-result-item" onClick={()=>setShoppingList(shoppingList.concat({item,id:shoppingList.length,isChecked:false}))}>{item}</div>
)}
</div>
}
</div>
<div className="shopping-list">
{shoppingList.length>0 && shoppingList.map((itemObj,index)=>
<span className="shopping-list-item">
<input onChange={(e)=>checkedHandler(e,itemObj.id)} type="checkbox" name={itemObj.item} id={`${itemObj.item}-${index}`}/>
<label style={{textDecoration:itemObj.isChecked?'line-through':'none'}} id ={`label-${itemObj.id}`} for={`${itemObj.item}-${index}`}>
{itemObj.item}
</label>
<span onClick={()=>removeItem(itemObj.id)} style={{color:'red', marginLeft:'6px', cursor:'pointer'}}>
X
</span>
</span>)}
</div>
</div>
)
}
const App = () => {
return(
<div className="main-container">
<SearchBar/>
</div>
)
}
ReactDOM.render(<App />, document.getElementById('app'));
View Compiled
This Pen doesn't use any external CSS resources.