Reputation: 438
I have an API that provides me with objects that have the following properties: id, title, url, thumbnailUrl.
I have a module that's responsible for the card that has the following code:
export interface Manual {
id?: string | number;
url: string;
title: string;
thumbnail?: string | null;
}
I have a module that's responsible for creating the actual HelpCard components, and the code for it is as follows:
interface Props {
card: Manual;
deleteProduct: Function;
editProduct: Function;
type: "videos" | "manuals";
}
interface State {
editedCard: Manual;
imageLoading?: boolean;
tooManyRequests?: boolean;
}
export default class HelpCard extends Component<Props, State> {
state = {
editedCard: {
id: -1,
url: "",
title: "",
thumbnail: ""
},
imageLoading: true,
tooManyRequests: false
};
componentDidMount() {}
onEditClick = (card: Manual): void => {
this.setState({ editedCard: card });
};
updateEditCard = (event: React.FormEvent<HTMLInputElement>, key: "url" | "title" | "thumbnail"): void => {
const value = event.currentTarget.value;
this.setState((prevState: State) => {
return { editedCard: { ...prevState.editedCard, [key]: value } };
});
};
render() {
const { card } = this.props;
const { editedCard } = this.state;
return (
<React.Fragment>
<div className="card">
<div className="card-img">
{this.state.imageLoading ? <img src={placeholder} style={{ width: "100%", height: "100%" }}></img> : null}
<img
className="cardImage"
style={
this.state.tooManyRequests
? { display: "none" }
: this.state.imageLoading
? { display: "null" }
: { display: "block" }
}
onLoad={() => this.setState({ imageLoading: false })}
onError={() => this.setState({ tooManyRequests: true })}
src={card.thumbnail ? card.thumbnail : placeholder}
/>
</div>
<div className="card-body">
<div style={{ textAlign: "center" }}>
<span className="card-title">{card.title}</span>
<hr></hr>
</div>
<div className="card-buttons">
<div className="group">
<Modal
trigger={
<Button
onClick={() => this.onEditClick(card)}
style={{ width: "90px" }}
icon="mode_edit"
className="btn blue-outline"
href="#!">
Edit
</Button>
}>
<form
onSubmit={(e) => e.preventDefault()}
id="videoCardEdit"
style={{ width: "auto", height: "auto" }}>
<div>
<div>
<label>Title:</label>
<input
className="input"
style={{ width: "100%" }}
name="videoCardTitle"
onChange={(e: React.FormEvent<HTMLInputElement>) => this.updateEditCard(e, "title")}
value={editedCard.title}></input>
</div>
<div>
<label>URL:</label>
<input
className="input"
style={{ width: "100%" }}
name="videoCardURL"
onChange={(e: React.FormEvent<HTMLInputElement>) => this.updateEditCard(e, "url")}
value={editedCard.url}></input>
</div>
<div>
<label>Thumbnail URL:</label>
<input
className="input"
style={{ width: "100%" }}
name="videoCardThumbnail"
onChange={(e: React.FormEvent<HTMLInputElement>) => this.updateEditCard(e, "thumbnail")}
value={editedCard.thumbnail}></input>
</div>
<br></br>
</div>
<Button
type="submit"
className="btn green-outline"
icon="check"
length="fullwidth"
style={{
float: "left"
}}
onClick={() =>
this.props.editProduct(
card.id,
editedCard.title,
editedCard.url,
editedCard.thumbnail,
this.props.type
)
}>
confirm
</Button>
<br></br>
</form>
</Modal>
<Button
icon="delete"
style={{ width: "90px" }}
onClick={() => this.props.deleteProduct(card.id, this.props.type)}
className="btn red-outline">
Delete
</Button>
</div>
</div>
</div>
</div>
</React.Fragment>
);
}
}
The card is then displayed on a HelpList component with the following code:
export default class HelpList extends Component<Props, State> {
state = {};
async componentDidMount() {}
render() {
console.log(this.props.data);
return (
<div className="row">
{this.props.data.map((card: Manual) => (
<HelpCard
card={card}
key={card.id}
deleteProduct={this.props.onDelete}
editProduct={this.props.onEdit}
type={this.props.type}
/>
))}
</div>
);
}
}
The final list in the displayed on my HelpAdmin.view.tsx module which loads my cards, and has all the API functions such as my create / delete / edit calls.
The state and load function is as follows:
export class HelpAdminView extends Component<Props, State> {
state = {
title: "",
thumbnail: "",
url: "",
error: null,
isEditProduct: true,
isAddProduct: true,
whichRadioSelected: "video",
videos: [],
manuals: []
};
componentDidMount() {
this.loadAdminHelpCard("videos");
this.loadAdminHelpCard("manuals");
}
loadAdminHelpCard = (type: "videos" | "manuals"): void => {
const url = `${BASE_API_URL}/${type}`;
axios
.get(url)
.then((res) => {
this.setState({ [type]: res.data } as any);
})
.catch(function(error) {
// handle error
console.log(error);
});
};
Finally, my edit function is like so:
editProduct = (id: any, title: string, url: string, thumbnail: string, type: "videos" | "manuals") => {
const apiUrl = `${BASE_API_URL}/${type}/${id}`;
axios
.put(apiUrl, {
title: title,
url: url,
thumbnail: thumbnail
})
.then((response: any) => {
// ? UPDATE the list with new card information here
})
.catch(function(error) {
console.log(error);
});
};
When a user clicks "Edit", the card is copied from props and put into a state. Now only the state of the card is edited. (this.state.editedCard) When users click on submit the editedCard details are given to editProduct(id, title, thumbnail, etc...). In HelpAdmin.view.tsx an API call is being made, that will change the database with the new card details.
What I'm trying to figure out is how to update our card in either videos/manuals so it's reflected in the UI. (ON Successfull API call)
Thank you in advance for reading and helping!
Upvotes: 0
Views: 255
Reputation: 17858
You can get the current data, when the update operation ends.
.then((response: any) => {
//here get the recent data from your api
// ? UPDATE the list with new card information here
this.loadAdminHelpCard("videos");
this.loadAdminHelpCard("manuals");
})
So this will update the state, causing the parent component rerender, which will also rerender child components, so your Card component will get the new data.
All editProduct function:
editProduct = (id: any, title: string, url: string, thumbnail: string, type: "videos" | "manuals") => {
const apiUrl = `${BASE_API_URL}/${type}/${id}`;
axios
.put(apiUrl, {
title: title,
url: url,
thumbnail: thumbnail
})
.then((response: any) => {
//here get the recent data from your api
// ? UPDATE the list with new card information here
this.loadAdminHelpCard("videos");
this.loadAdminHelpCard("manuals");
})
.catch(function(error) {
console.log(error);
});
};
Upvotes: 1