Framework bootstrap memiliki css yang sudah untuk menampilkan kondisi error pada sebuah form. Mari kita gunakan css tersebut.
Untuk contoh, kita akan tambahkan validasi pada element input title.
Buka file src/components/AddEditAnime.js, lalu lakukan penambahan code berikut.
Pertama, pada state, kita tambahkan array errors.
constructor(props){
super(props);
this.state ={
anime:{
id:0,
title: "",
desc: "",
year: "",
},
isLoaded : false,
error : null,
errors : [],
}
this.handleChg = this.handleChg.bind(this)
this.handleSubm = this.handleSubm.bind(this)
}
Tambahkan fungsi helper untuk memeriksa apakah suatu element terdapat error.
hasError(key){
return this.state.errors.indexOf(key) !== -1;
}
Lalu pada fungsi handleSubm, tambahkan validasi form. Contoh dibawah adalah untuk element input title.
let errors = [];
if (this.state.anime.title === ''){
errors.push("title");
}
this.setState({errors:errors});
if (errors.length>0){
return false;
}
Kemudian pada element input title, tambahkan code untuk mengubah tampilan bila ada error.
<div className="mb-3">
<label htmlFor="title" className="form-label">Title</label>
<input type="text" className= {this.hasError("title")?"form-control is-invalid":"form-control"} id="title" name="title" value={anime.title} onChange={this.handleChg}/>
<div className={this.hasError("title")?"text-danger":"d-none"}>Please enter title...</div>
</div>
Bila input title dikosong dan tombol save ditekan, maka error message akan ditampilkan, dan input akan disorot seperti gambar diatas.
Latihan
Tambahkan validasi untuk 2 element input description dan year.
Solusi
Berikut hasil akhir code setelah ditambahkan form validasi
import React, {Component, Fragment} from "react";
// import Input from "./FormComponents/Input";
export default class AddEditAnime extends Component{
constructor(props){
super(props);
this.state ={
anime:{
id:0,
title: "",
desc: "",
year: "",
},
isLoaded : false,
error : null,
errors : [],
}
this.handleChg = this.handleChg.bind(this)
this.handleSubm = this.handleSubm.bind(this)
}
handleSubm = (evt) =>{
evt.preventDefault();
// validasi form
let errors = [];
if (this.state.anime.title === ''){
errors.push("title");
}
if (this.state.anime.desc === ''){
errors.push("desc");
}
if (this.state.anime.year === ''){
errors.push("year");
}
this.setState({errors:errors});
if (errors.length>0){
return false;
}
};
handleChg = (evt)=>{
let value = evt.target.value;
let name = evt.target.name;
this.setState((prevstate)=>({
anime:{
...prevstate.anime,
[name] : value,
}
}));
}
hasError(key){
return this.state.errors.indexOf(key) !== -1;
}
componentDidMount(){
const id = this.props.match.params.id;
if (id > 0){
fetch("http://localhost:4000/v1/anime/" +id)
.then((response)=>{
if(response !== "200"){
let err = Error;
err.Message = "Invalid response code: " + response.status;
this.setState({error : err});
}
return response.json();
})
.then((json) => {
this.setState({
anime:{
id: id,
title: json.anime.title,
year: json.anime.year,
desc: json.anime.desc,
},
isLoaded : true,
},
(error) => {
this.setState({
isLoaded : true,
error,
})
}
)
})
}else{
this.setState({isLoaded:true});
}
}
render(){
let {anime, isLoaded, error} = this.state;
if (error){
return <div>Error : {error.Message}</div>
}else if (!isLoaded){
return <p>Loading...</p>
}else{
return(
<Fragment>
<h2>Add/Edit Anime</h2>
<hr/>
<form onSubmit={this.handleSubm}>
<input type="hidden" name="id" id="id" value={anime.id} onChange={this.handleChg}/>
<div className="mb-3">
<label htmlFor="title" className="form-label">Title</label>
<input type="text" className={this.hasError("title")?"form-control is-invalid":"form-control"} id="title" name="title" value={anime.title} onChange={this.handleChg}/>
<div className={this.hasError("title")?"text-danger":"d-none"}>Please enter title...</div>
</div>
<div className="mb-3">
<label htmlFor="des" className="form-label">Description</label>
<textarea type="text" className={this.hasError("desc")?"form-control is-invalid":"form-control"} id="desc" name="desc" rows="3" onChange={this.handleChg} value={anime.desc}/>
<div className={this.hasError("desc")?"text-danger":"d-none"}>Please enter description...</div>
</div>
<div className="mb-3">
<label htmlFor="year" className="form-label">Year</label>
<input type="text" className={this.hasError("year")?"form-control is-invalid":"form-control"} id="year" name="year" value={anime.year} onChange={this.handleChg}/>
<div className={this.hasError("year")?"text-danger":"d-none"}>Please enter year...</div>
</div>
<hr/>
<button className="btn btn-primary">Save</button>
</form>
<div className="mt-3">
<pre>{JSON.stringify(this.state, null, 3)}</pre>
</div>
</Fragment>
);
}
}
}
Perhatian, untuk solusi hanya dilakukan pengecekan sederhana. Anda bisa bereksperimen dengan melakukan validasi yang lebih detail seperti mengecek angka untuk input year dan lainnya.
Pada modul selanjutnya kita akan bekerja pada backend untuk melakukan proses update di database.