Save a question in database
Step 1: create a button
<h5 class="card-title mb-6">Question</h5>
<div className="serch">
<button
className="btn btn-block add-btn"
type="submit"
onClick={() => dispatch(openQuestionModal())}
>
+ Add Question
</button>
</div>
step2
Using a dispatch function call a state management system redux store
const dispatch = useDispatch()
step3
perform the action creator function
the action creator openQuestionModal used to dispatch the OPEN_QUESTION_MODAL action is processed by the relevant reducer
export const openQuestionModal = () => {
return (dispatch) => {
dispatch({ type: OPEN_QUESTION_MODAL })
}
}
step4
state is being updated based on the action type
switch (action.type) {
case OPEN_QUESTION_MODAL:
return { ...state, isAddQuestionModalOpen: true }
const initialState = {
isAddQuestionModalOpen: false,
}
step5
Controlling the visibility of the modal through a state variable
<Modal
show={isAddQuestionModalOpen}
onHide={() => dispatch(closeQuestionModal())}
aria-labelledby="contained-modal-title-vcenter"
centered
>
step6
show a popup modal form that contain textfield dropdown and button
<Modal.Header closeButton>
<Modal.Title>
{"add question"}
</Modal.Title>
</Modal.Header>
<Modal.Body>
<FormRow
type={"text"}
value={values.question}
name="question"
handleChange={handleChange}
labelText={"question"}
required={true}
/>
<FormRowSelect
labelText={"type"}
name="type"
value={values.type}
handleChange={handleChange}
list={["subjective", "multiple"]}
/>
{values.type === "multiple" && (
<button className="btn" onClick={hanndleAddOptions}>
add options
</button>
)}
{values.type === "multiple" &&
options.map((i) => {
return (
<div>
<FormRow
name={`${i}`}
value={values.options[i]}
handleChange={handleOptionChange}
labelText={`option ${i + 1}`}
/>
</div>
)
})}
<button className="btn" onClick={handleSubmit}>
submit
</button>
<button
className="btn"
onClick={() => dispatch(closeQuestionModal())}
>
cancel
</button>
</Modal.Body>
</Modal>
code explanation
how to use dropdown
<FormRowSelect
labelText={"type"}
name="type"
value={values.type}
handleChange={handleChange}
list={["subjective", "multiple"]}
/>
const initialState = {
question: "",
type: "subjective",
options: [],
}
how to dynamically sets name,value and labelText using button
{values.type === "multiple" && (
<button className="btn" onClick={hanndleAddOptions}>
add options
</button>
)}
{values.type === "multiple" &&
options.map((i) => {
return (
<div>
<FormRow
name={`${i}`}
value={values.options[i]}
handleChange={handleOptionChange}
labelText={`option ${i + 1}`}
/>
</div>
)
})}
When u select dropdown and type multiple
{values.type === "multiple" && (
<button className="btn" onClick={hanndleAddOptions}>
add options
</button>
)}
When we click add options then call hanndleAddOptions function
const [options, setOptions] = useState([0])
const hanndleAddOptions = () => {
const last = options[options.length - 1]//options.length=1==>(1-1)==>0
setOptions([...options, last + 1])
}
This function hanndleAddOptions is used to add new options to the options state array.
[0]==>[0,1]==>[0,1,2]==>[0,1,2,3]...etc
maps over the options state array
options.map((i) => { ... }): This maps over the options state array and renders a component for each option index i using conditional rendering statement
{values.type === "multiple" &&
options.map((i) => {
return (
<div>
<FormRow
name={`${i}`}
value={values.options[i]}
handleChange={handleOptionChange}
labelText={`option ${i + 1}`}
/>
</div>
)
})}
How to update value of particular initial state object property options is array type using event handler function handleOptionChange
const handleOptionChange = (e) => {
const position = parseInt(e.target.name)
const str = e.target.value
const arr = values.options
arr[position] = str//single value option1 or option2
setValues({ ...values, options: arr })
}
output
setValues({ ...values, options: arr })// in arr all arr[0],arr[1],arr[2]
options: ["Option1", "Option2", "Option3"],
Step7:after filling form submit the data
dispatches an action createQuestion action creator using the dispatch function
<button className="btn" onClick={handleSubmit}>
submit
</button>
const handleSubmit = async (e) => {
e.preventDefault()
console.log(values)
dispatch(createQuestion(values))
setValues(initialState)
}
step9
perform the action creator function
This action creator is used in a Redux-based application to asynchronously create a new question and update the state based on the response received from the server
How to update state(apply if condition) inside action creator based on the response received from the server
How different actions are dispatched based on response received from the server
export const createQuestion = (values) => {
return async (dispatch) => {
dispatch({ type: CREATE_QUESTION_BEGIN })
try {
const response = await authFetch.post("/question", values)
if (response.data.newQuestion.type === "subjective") {
dispatch({
type: CREATE_QUESTION_SUBJECTIVE_SUCCESS,
payload: { question: response.data.newQuestion },
})
}
if (response.data.newQuestion.type === "multiple") {
dispatch({
type: CREATE_QUESTION_MULTIPLE_SUCCESS,
payload: { question: response.data.newQuestion },
})
}
toast.success("question created successfully")
} catch (error) {
dispatch({ type: CREATE_QUESTION_ERROR })
console.log(error)
toast.error("something went wrong while creating question")
}
}
}
in controller
const createQuestion = async (req, res) => {
const { question, type } = req.body
if (!question) {
throw new BadRequestError("provide question")
}
const newQuestion = await Question.create(req.body)
res.status(201).json({ newQuestion })
}
Handle the state updates in response to two different success actions
case CREATE_QUESTION_SUBJECTIVE_SUCCESS:
return {
...state,
isAddQuestionModalOpen: false,
editingQuestion: null,
isEditingQuestion: false,
subjective: [...state.subjective, action.payload.question],
}
case CREATE_QUESTION_MULTIPLE_SUCCESS:
return {
...state,
isAddQuestionModalOpen: false,
editingQuestion: null,
isEditingQuestion: false,
multiple: [...state.multiple, action.payload.question],
}
Output
READ OR DISPLAY OR RENDER DATA IN REACT JS
<Tabs
activeTab="1"
className="tabss mb-3"
ulClassName=""
activityClassName="bg-success"
// onClick={(event, tab) => console.log(event, tab)}
>
<Tab title="Subjective" className="mr-3">
<Subjective />
</Tab>
<Tab title="Multiple" className="mr-3">
<Multiple />
</Tab>
</Tabs>
import Subjective from "./Subjective"
import Multiple from "./Multiple"
Subjective.js
Select specific data from the Redux store's state using useSelector
const dispatch = useDispatch()
const { subjective } = useSelector((state) => state.feedback)
In redux store
case GET_ALL_QUESTION_SUBJECTIVE_SUCCESS:
return { ...state, subjective: action.payload.questions }
How to get different data based on different route query parameter in same function controller
const getAllQuestion = async (req, res) => {
const { subjective, multiple } = req.query
let questions
if (subjective) {
questions = await Question.find({ type: "subjective" })
}
if (multiple) {
questions = await Question.find({ type: "multiple" })
}
res.status(200).json({ questions })
}
How to dispatch different action based on different boolean value parameter in action creator function getAllQuestion
export const getAllQuestion = (values) => {
return async (dispatch) => {
const { subjective, multiple } = values
dispatch({ type: GET_ALL_QUESTION_BEGIN })
try {
let response
if (subjective) {
response = await authFetch.get(`/question?subjective=true`)
dispatch({
type: GET_ALL_QUESTION_SUBJECTIVE_SUCCESS,
payload: { questions: response.data.questions },
})
}
if (multiple) {
response = await authFetch.get(`/question?multiple=true`)
dispatch({
type: GET_ALL_QUESTION_MULTIPLE_SUCCESS,
payload: { questions: response.data.questions },
})
}
// console.log(response)
} catch (error) {
dispatch({ type: GET_ALL_QUESTION_ERROR })
toast.error("error getting questions")
console.log(error)
}
}
}
if (subjective) {
dispatch(
getAllQuestion({
subjective: true,
startDate: values.startDate,
endDate: values.endDate,
})
)
}
In subjective.js
after apply filter display the data
add edit and delete in every subjective question
return (
<Wrapper>
<QuestionFilter subjective={true} />
{subjective.length > 0 &&
subjective.map((i) => {
return (
<div>
<p>
<ApiIcon fontSize="15px" style={{ marginRight:
"10px" }} />
{capitalizeFirstLetter(i.question)}
<DriveFileRenameOutlineSharpIcon
className="edit"
onClick={() => dispatch(setEditSubjective(i._id))}
/>
<DeleteIcon
className="del"
onClick={() => dispatch(deleteSingleQuestion(i._id))}
/>
</p>
</div>
)
})}
<section></section>
</Wrapper>
)
}
In multiple.js
Select specific data from the Redux store's state using useSelector
const dispatch = useDispatch()
const { multiple } = useSelector((state) => state.feedback)
In redux store
case GET_ALL_QUESTION_MULTIPLE_SUCCESS:
return { ...state, multiple: action.payload.questions }
after apply filter display the data
add edit and delete in every multiple question
<Wrapper>
<QuestionFilter multiple={true} />
{multiple.length > 0 &&
multiple.map((i) => {
return (
<div>
<h6>
<ApiIcon fontSize="15px" style={{ marginRight: "10px" }} />
{capitalizeFirstLetter(i.question)}
<DriveFileRenameOutlineSharpIcon
className="edit"
onClick={() => dispatch(setEditMultiple(i._id))}
/>
<DeleteIcon className="del" />
</h6>
<div className="options">
{i.options.map((o, i) => {
return (
<p key={i}>
<FiberManualRecordRoundedIcon
style={{ marginRight: "3px", fontSize: "5px" }}
/>{" "}
{o}
</p>
)
})}
</div>
</div>
)
})}
<section></section>
</Wrapper>
Output
Edit and Update question
In subjective.js
step1: create a button
Step2:Using a dispatch function call a state management system redux store
step3
perform the action creator function
the action creator setEditSubjective used to dispatch the SET_EDIT_SUBJECTIVE action is processed by the relevant reducer
export const setEditSubjective = (id) => {
return (dispatch) => {
dispatch({ type: SET_EDIT_SUBJECTIVE, payload: { id } })
}
}
above line defines line defines the setEditSubjective action creator function, which takes an id as its argument.
the dispatched action has a type of SET_EDIT_SUBJECTIVE and a payload containing the id of the
note: export function is used so that outside of this function anyone can access it
step4
state is being updated based on the action type
How to use find method to get data on the state.subjective array to search for a subjective question that matches the id
case SET_EDIT_SUBJECTIVE:
const question = state.subjective.find((i) => i._id === action.payload.id)
return {
...state,
editingQuestion: question,
isSubjectiveModalOpen: true,
isEditingQuestion: true,
}
const initialState = {
loading: false,
questions: [],
subjective: [],
multiple: [],
isAddQuestionModalOpen: false,
isSubjectiveModalOpen: false,
isMultipleModalOpen: false,
editingQuestion: null,
isEditingQuestion: false,
}
step5
Controlling the visibility of the modal through a state variable
useEffect(() => {
!editingQuestion &&
dispatch(getSubjectiveQuestion()).then((data) => {
setQuestion(data)
})
if (editingQuestion) {
console.log(editingQuestion)
setQuestion(editingQuestion)
}
}, [editingQuestion])
step6
show a popup modal form that contain textfield
step7: Update data when u submit using event handler function
const handleSubmit = async (e) => {
e.preventDefault()
// console.log(values)
if (isEditingQuestion) {
dispatch(
updateQuestion({
question: values.answer,
type: editingQuestion.type,
options: [],
_id: editingQuestion._id,
})
)
} else {
dispatch(
createFeedback({ answer: values.answer, question: question._id })
)
}
setValues(initialState)
}
step8
perform the action creator function
This action creator is used in a Redux-based application to asynchronously create a new question and update the state based on the response received from the server
How to update state(apply if condition) inside action creator based on the response received from the server while updating
How different actions are dispatched based on response received from the server while updating
export const updateQuestion = (values) => {
return async (dispatch) => {
dispatch({ type: UPDATE_QUESTION_BEGIN })
try {
const { _id } = values
console.log(values)
const response = await authFetch.patch(`/question/${_id}`, values)
console.log(response)
if (response.data.updatedQuestion.type === "subjective") {
dispatch({
type: UPDATE_SUBJECTIVE_QUESTION_SUCCESS,
payload: { updatedQuestion: response.data.updatedQuestion },
})
} else {
dispatch({
type: UPDATE_MULTIPLE_QUESTION_SUCCESS,
payload: { updatedQuestion: response.data.updatedQuestion },
})
}
} catch (error) {
console.log(error)
dispatch({ type: UPDATE_QUESTION_ERROR })
}
}
}
in controller function
const updateQuestion = async (req, res) => {
// get question and array of strings from req.body
const { id } = req.params
if (!id) {
throw new BadRequestError("please provide id")
}
const { question } = req.body
if (!question) {
throw new BadRequestError("please provide question")
}
const alreadyExist = await Question.findById(id)
if (!alreadyExist) {
throw new NotFoundError("no question with this id")
}
const updatedQuestion = await Question.findByIdAndUpdate(id, req.body, {
new: true,
})
res.status(200).json({ updatedQuestion })
}
In multiple.js
step1: create a button
Step2:Using a dispatch function call a state management system redux store
import { getAllQuestion, setEditMultiple } from "../../redux"
step3
perform the action creator function
the action creator setEditMultiple used to dispatch the SET_EDIT_SUBJECTIVE action is processed by the relevant reducer
export const setEditMultiple = (id) => {
return (dispatch) => {
dispatch({ type: SET_EDIT_MULTIPLE, payload: { id } })
}
}
above line defines line defines the setEditMultiple action creator function, which takes an id as its argument.
the dispatched action has a type of SET_EDIT_MULTIPLE and a payload containing the id of the
note: export function is used so that outside of this function anyone can access it
step4
state is being updated based on the action type
How to use find method to get data on the state.subjective array to search for a subjective question that matches the id
case SET_EDIT_MULTIPLE:
const multipleQuestion = state.multiple.find(
(i) => i._id === action.payload.id
)
return {
...state,
editingQuestion: multipleQuestion,
isMultipleModalOpen: true,
isEditingQuestion: true,
}
const initialState = {
loading: false,
questions: [],
subjective: [],
multiple: [],
isAddQuestionModalOpen: false,
isSubjectiveModalOpen: false,
isMultipleModalOpen: false,
editingQuestion: null,
isEditingQuestion: false,
}
step5
Controlling the visibility of the modal through a state variable
useEffect(() => {
!editingQuestion &&
dispatch(getMultipleQuestion()).then((data) => {
console.log(data)
setQuestion(data)
})
if (editingQuestion) {
setQuestion(editingQuestion)
}
}, [editingQuestion])
step6
show a popup modal form that contain textfield
const handleAddOptions = () => {
const length = question.options.length
console.log(length)
// setOptions([...options, last + 1])
const arr = question.options
arr[length] = ""
setQuestion({ ...question, options: arr })
}
const handleChange = (i) => {
const str = i.target.value.slice(0, -1)
const position = question.options.indexOf(str)
const arr = question.options
arr[position] = i.target.value
setQuestion({ ...question, options: arr })
}
step7: Update data when u submit using event handler function
const handleUpdate = () => {
console.log(question)
dispatch(updateQuestion(question))
}
step8
perform the action creator function
This action creator is used in a Redux-based application to asynchronously create a new question and update the state based on the response received from the server
How to update state(apply if condition) inside action creator based on the response received from the server while updating
How different actions are dispatched based on response received from the server while updating
export const updateQuestion = (values) => {
return async (dispatch) => {
dispatch({ type: UPDATE_QUESTION_BEGIN })
try {
const { _id } = values
console.log(values)
const response = await authFetch.patch(`/question/${_id}`, values)
console.log(response)
if (response.data.updatedQuestion.type === "subjective") {
dispatch({
type: UPDATE_SUBJECTIVE_QUESTION_SUCCESS,
payload: { updatedQuestion: response.data.updatedQuestion },
})
} else {
dispatch({
type: UPDATE_MULTIPLE_QUESTION_SUCCESS,
payload: { updatedQuestion: response.data.updatedQuestion },
})
}
} catch (error) {
console.log(error)
dispatch({ type: UPDATE_QUESTION_ERROR })
}
}
}
in controller function
const updateQuestion = async (req, res) => {
// get question and array of strings from req.body
const { id } = req.params
if (!id) {
throw new BadRequestError("please provide id")
}
const { question } = req.body
if (!question) {
throw new BadRequestError("please provide question")
}
const alreadyExist = await Question.findById(id)
if (!alreadyExist) {
throw new NotFoundError("no question with this id")
}
const updatedQuestion = await Question.findByIdAndUpdate(id, req.body, {
new: true,
})
res.status(200).json({ updatedQuestion })
}
HOW to delete question
In subjective.js
step1: create a delete icon
Step2:Using a dispatch function call a state management system redux store
import {
getAllQuestion,
setEditSubjective,
deleteSingleQuestion,
} from "../../redux"
step3
perform the action creator function
the action creator deleteSingleQuestion used to dispatch the DELETE_QUESTION_BEGIN action is processed by the relevant reducer
export const deleteSingleQuestion = (id) => {
return async (dispatch) => {
dispatch({ type: DELETE_QUESTION_BEGIN })
try {
const response = await authFetch.delete(`/question/${id}`)
if (response.data.deletedQuestion.type === "subjective") {
dispatch({
type: DELETE_SUBJECTIVE_QUESTION_SUCCESS,
payload: { deletedQuestion: response.data.deletedQuestion },
})
} else {
dispatch({
type: DELETE_MULTIPLE_QUESTION_SUCCESS,
payload: { deletedQuestion: response.data.deletedQuestion },
})
}
toast.success("question delete successfully")
} catch (error) {
console.log(error)
dispatch({ type: DELETE_QUESTION_ERROR })
toast.error("error deleting question")
}
}
}
case DELETE_SUBJECTIVE_QUESTION_SUCCESS:
const filterSub = state.subjective.filter(
(i) => i._id !== action.payload.deletedQuestion._id
)
in controller function
const deleteQuestion = async (req, res) => {
const { id } = req.params
if (!id) {
throw new BadRequestError("please provide id")
}
const question = await Question.findById(id)
if (!question) {
throw new NotFoundError("no question with this id")
}
const deletedQuestion = await Question.findByIdAndDelete(id)
res.status(200).json({ deletedQuestion })
}
Top comments (0)