RTK createEntityAdapter not getting relational data in list after save user in database - laravel

i have a list of users which getting data from database by using RTK createEntityAdapter.
API function code for getting list of users
public function index(){
$roles = Role::all();
$all_roles = [];
foreach ($roles as $key => $role) {
$obj_role = new \stdClass();
$obj_role->id = $role->id;
$obj_role->name = $role->title;
array_push($all_roles,$obj_role);
}
return response()->json([
'users' => User::with('roles')->paginate(10),
'roles' => $all_roles
]);
}
In the above code getting users and roles in response & showing list in react app by using RTK createEntityAdapter
userSlice.js
import { createSlice,createEntityAdapter} from "#reduxjs/toolkit";
import { HTTP_STATUS } from "../../src/constants";
import { fetchUsers, deleteUsers, saveUser } from "services/userService";
const userAdapter = createEntityAdapter({
selectId: (user) => user.id,
})
const userSlice = createSlice({
name:'user',
initialState: userAdapter.getInitialState(
{ loading: false,
page: 1,
total_pages: null,
status: null,
message: null,
roles: []
} ),
reducers:{
pageByNumber: (state,{payload}) => {
state.page = payload.page
},
nextPage: (state, {payload}) => {
state.page = state.page++
},
previousPage: (state, {payload}) => {
state.page = state.page--
},
clear: (state) => {
state.status = null,
state.message = null
}
},
extraReducers: {
[fetchUsers.pending]: (state) => {
state.loading = true,
state.status = HTTP_STATUS.PENDING
},
[fetchUsers.fulfilled]: (state, {payload}) => {
state.loading = false,
state.page = payload.users.current_page,
state.total_pages = Math.ceil(payload.users.total/payload.users.per_page),
userAdapter.setAll(state, payload.users.data),
state.status = HTTP_STATUS.FULFILLED,
state.roles = payload.roles
},
[fetchUsers.rejected]: (state, {error}) => {
state.loading = false,
state.status = HTTP_STATUS.REJECTED,
state.message = error.message
},
[deleteUsers.pending]: (state) => {
state.loading = true,
state.status = HTTP_STATUS.PENDING
},
[deleteUsers.fulfilled]: (state, { payload }) => {
state.loading = false,
userAdapter.removeOne(state, payload.id)
},
[deleteUsers.rejected]: (state) => {
state.loading = false
},
[saveUser.pending]: (state) => {
state.loading = true,
state.status = HTTP_STATUS.PENDING
},
[saveUser.fulfilled]: (state, { payload }) => {
state.loading = false,
state.status = HTTP_STATUS.FULFILLED
if(!payload.errors){
userAdapter.addOne(state, payload.id),
state.message = payload.message
}
},
[saveUser.rejected]: (state,{error}) => {
state.loading = false,
state.status = HTTP_STATUS.REJECTED,
state.message = error.message
}
},
});
export const userSelectors = userAdapter.getSelectors(
(state) => state.user,
)
export const {pageByNumber, nextPage, previousPage,clear} = userSlice.actions
export default userSlice.reducer
user/index.js
const roles = useSelector(state => state.user.roles);
const allUsers = useSelector(userSelectors.selectAll);
useEffect(() => {
dispatch(
fetchUsers(currentPage))
.then(unwrapResult)
.then((obj) => console.log(obj))
.catch((obj) => console.log({objErr: obj}))
}, [dispatch])
//listing HTML
{
allUsers.map((ls,index) => (
<tr key={ls.id}>
<td>{ls.id}</td>
<td>{ls.name}</td>
<td>{ls.email}</td>
<td>
{ls.status =="ACTIVE" ? <Badge color="success" pill>Active</Badge>:<Badge color="danger" pill>Inactive</Badge>}</td>
<td>
{ls.roles.map((role) => (
role.title+" "
))}
</td>
<td><Moment fromNow ago>{ls.created_at}</Moment> </td>
<td>
<Button variant="warning" size="sm" onClick={handleShow} >Edit</Button>{' '}
<Button
onClick={e =>
window.confirm("Are you sure you wish to delete this user?") &&
deleteUser(ls.id)
}
variant="danger"
size="sm">Delete</Button>
</td>
</tr>
))
}
create.js
import {Modal, Button, Form,Dropdown} from "react-bootstrap";
import propTypes from "prop-types";
import React, {useState} from "react";
import Multiselect from 'multiselect-react-dropdown';
import { saveUser } from 'services/userService';
import {useDispatch,useSelector} from 'react-redux';
import { unwrapResult } from '#reduxjs/toolkit';
import Notify from "components/Common/Notify";
function Create({handleClose,show,roles}) {
const [selectedRoles, setSelectedRoles] = useState([]);
const dispatch = useDispatch();
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [errors, setErrors] = useState([]);
function onSelectRoles(selectedList, selectedItem) {
selectedRoles.push(selectedItem.id)
}
function onRemoveRole(selectedList, removedItem) {
var index = selectedRoles.indexOf(removedItem.id)
selectedRoles.splice(index, 1);
}
const message = useSelector(state => state.user.message);
const status = useSelector(state => state.user.status);
function onSubmit(e){
e.preventDefault();
let data ={
name:name,
email:email,
password:password,
roles:selectedRoles,
}
dispatch(
saveUser(data))
.then(unwrapResult)
.then((obj) => {
if(obj.errors){
setErrors(obj.errors);
}else{
setErrors([]);
handleClose();
}
}
)
.catch((obj) => {
console.log({objErr: obj})
})
}
return (
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>New User</Modal.Title>
</Modal.Header>
<Modal.Body>
{status && message && (
<Notify status={status} message={message}/>
)}
<Form onSubmit={onSubmit} >
<Form.Group className="mb-3">
<Form.Label>Name</Form.Label>
<Form.Control className={errors['name'] ? "is-invalid" : ""} type="text" onChange={e => setName(e.target.value) } placeholder="Enter Name" />
{errors['name'] ?
<Form.Text className="text-danger">
{errors['name']}
</Form.Text>
:''
}
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Label>Email address</Form.Label>
<Form.Control className={errors['email'] ? "is-invalid" : ""} type="email" onChange={e => setEmail(e.target.value) } placeholder="Enter email" />
{errors['email'] ?
<Form.Text className="text-danger">
{errors['email']}
</Form.Text>
:''
}
</Form.Group>
<Form.Group>
<Form.Label>Select Role</Form.Label>
<Multiselect
options={roles}
// selectedValues={selectedValue}
onSelect={onSelectRoles}
onRemove={onRemoveRole}
displayValue="name"
className={errors['roles'] ? "is-invalid" : ""}
/>
{errors['roles'] ?
<Form.Text className="text-danger">
{errors['roles']}
</Form.Text>
:''
}
</Form.Group>
<Form.Group>
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicPassword">
<Form.Label>Password</Form.Label>
<Form.Control className={errors['password'] ? "is-invalid" : ""} type="password" onChange={e => setPassword(e.target.value)} placeholder="Password" />
{errors['password'] ?
<Form.Text className="text-danger">
{errors['password']}
</Form.Text>
:''
}
</Form.Group>
<Button variant="success" size="sm" type="submit">
Create
</Button>
</Form>
</Modal.Body>
</Modal>
);
}
Create.prototype= {
handleClose: propTypes.func.isRequired,
show: propTypes.bool.isRequired,
roles: propTypes.array.isRequired
}
export default Create;
when i add new user by using saveUser createEntityAdapter, not getting relational data "role" & getting error

i found the problem in my code, actually createEntityAdpter addone works looks like below
Adapter.addOne(state, payload.data);
i was passing only id in addOne function, as below
[saveUser.fulfilled]: (state, { payload }) => {
state.loading = false,
state.status = HTTP_STATUS.FULFILLED
if(!payload.errors){
userAdapter.addOne(state, payload.id), //wrong approach
state.message = payload.message
}
it should be pass full object in addOne function of createEntityAdapter
[saveUser.fulfilled]: (state, { payload }) => {
state.loading = false,
state.status = HTTP_STATUS.FULFILLED
if(!payload.errors){
userAdapter.addOne(state, payload.user),
state.message = payload.message
}
Now, this will work fine. now i am getting all relational data too in response.

Related

Change the options passed to formik (Field) form after selecting the value from other dropdown

Below is the code which I am using. When I am changing the data for Division the state of district list is changed but it is not shown in the form. I need to click on the form and the changed state data is reflected. I want it to get reflected once the state is changed.
function Input(props) {
const { label, name, ...rest } = props
return (
<div>
{/* <label htmlFor={name}>{label}</label> */}
<Field id={name} name={name} {...rest} />
<ErrorMessage name={name} component={TextError}/>
</div>
)
}
function Select(props) {
const { label, name, options, ...rest } = props
return (
<div className="form-group">
{/* <label htmlFor={name}>{label}</label> */}
<Field as='select' id={name} name={name} {...rest} >
{
options.map(option => {
return(
<option key={option.value} value={option.value}>
{option.key}
</option>
)
})
}
</Field>
<ErrorMessage name={name} component={TextError}/>
</div>
)
}
function Test() {
const [divisions, setDivisions] = useState([])
const [districts, setDistricts] =useState([])
const [blocks, setBlocks] = useState([])
const [initialValues,setInitialValues] = useState({
divisionCode:"",
districtCode:"",
blockCode : "",
name : "",
})
const validationSchema = Yup.object({
divisionCode :Yup.string().required('Required!!'),
districtCode :Yup.string().required('Required!!'),
blockCode : Yup.string().required('Required!!'),
name : Yup.string().required('Required!!'),
})
async function getDivisionList() {
try {
const res = await axios.get("APIURL")
return (res.data.response)
} catch (error) {
console.error(error);
}
}
function getDistrictList(divisionCode) {
axios.get("APIURL")
.then(res=>{
setDistricts(res.data.response)
return res.data.response[0].value
})
}
function getBlockList(districtCode) {
axios.get("APIURL")
.then(res => {
setBlocks(res.data.response)
})
}
useEffect(() => {
getDivisionList().then(res => {
setDivisions(res)
});
}, [])
const onSubmit = values => {
console.log('Form data ',values)
console.log('Saved data ',JSON.parse(JSON.stringify(values)))
}
return (
<Formik
initialValues = {initialValues}
validationSchema = {validationSchema}
onSubmit = {onSubmit}
>
{
formik => <Form>
<Select control='select' label='Division' onBlur={e => { var data = getDistrictList(e.currentTarget.value)}} name='divisionCode' options={divisions} />
<Select control='select' label='District' onBlur={e => { getBlockList(e.currentTarget.value)}} name='districtCode' options={districts} />
<Select control='select' label='Block' name='blockCode' options={blocks} />
<Input control='input' type='text' label='Name' name='name' />
<button type="submit" disabled={!formik.isValid}>Submit</button>
</Form>
}
</Formik>
)
}
export default Test
Thanks in Advance. It will be very helpful.

Unable to insert data in the database in laravel projet with vuejs and vuetify

I have setup a laravel project with Vuejs and vuetify to insert data in the database. But for some reason I not able to insert data in the database. When I compile my code I can see no error but when I inspect my code I can see error in my console saying "Internal service error" . I assuming that the error may be in my controller.
Here are m code:
Location.vue
<template>
<v-app id="inspire">
<v-data-table
item-key="code"
class="elevation-1"
color="error"
:loading = "loading"
loading-text="Loading... Please wait"
:headers="headers"
:options.sync="options"
:server-items-length="locations.total"
:items="locations.data"
show-select
#input="selectAll"
:footer-props="{
itemsPerPageOptions: [5,10,15],
itemsPerPageText: 'Roles Per Page',
'show-current-page': true,
'show-first-last-page': true
}"
>
<template v-slot:top>
<v-toolbar flat color="dark">
<v-toolbar-title>My Stage</v-toolbar-title>
<v-divider
class="mx-4"
inset
vertical
></v-divider>
<v-spacer></v-spacer>
<v-dialog v-model="dialog" max-width="500px">
<template v-slot:activator="{ on }">
<v-btn color="error" dark class="mb-2" v-on="on">Add New Stage</v-btn>
<v-btn color="error" dark class="mb-2 mr-2" #click="deleteAll">Delete</v-btn>
</template>
<v-card>
<v-card-title>
<span class="headline">{{ formTitle }}</span>
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col cols="12" sm="12" >
<v-text-field autofocus color="error" v-model="editedItem.code" label="Code"></v-text-field>
</v-col>
<v-col cols="12" sm="12" >
<v-text-field autofocus color="error" v-model="editedItem.name" label="Name"></v-text-field>
</v-col>
<v-col cols="12" sm="12" >
<v-text-field autofocus color="error" v-model="editedItem.description" label="Description"></v-text-field>
</v-col>
</v-row>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="error darken-1" text #click="close">Cancel</v-btn>
<v-btn color="error darken-1" text #click="save">Save</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-toolbar>
<v-row>
<v-col cols="12">
<v-text-field #input="searchIt" label="Search..." class="mx-4" ></v-text-field>
</v-col>
</v-row>
</template>
<template v-slot:item.action="{ item }">
<v-icon
small
class="mr-2"
#click="editItem(item)"
>
mdi-content-save-edit-outline
</v-icon>
<v-icon
small
#click="deleteItem(item)"
>
mdi-delete
</v-icon>
</template>
<template v-slot:no-data>
<v-btn color="error" #click="initialize">Reset</v-btn>
</template>
</v-data-table>
<v-snackbar v-model="snackbar" >
{{text}}
<v-btn
color="error"
text
#click="snackbar = false"
>
Close
</v-btn>
</v-snackbar>
</v-app>
</template>
<script>
export default {
data: () => ({
dialog: false,
loading: false,
snackbar: false,
selected: [],
text: '',
options:{
itemsPerPage: 5,
sortBy:['id'],
sortDesc: [false]
},
headers: [
{text: '#',align: 'left', sortable: false,value: 'id'},
{ text: 'Code', value: 'code' },
{ text: 'Name', value: 'name' },
{ text: 'Description', value: 'description' },
{ text: 'Actions', value: 'action'},
],
locations: [],
editedIndex: -1,
editedItem: {
id: '',
code: '',
name: '',
description: '',
},
defaultItem: {
id: '',
code: '',
name: '',
description: '',
},
}),
computed: {
formTitle () {
return this.editedIndex === -1 ? 'New Stage' : 'Edit Stage'
},
},
watch: {
dialog (val) {
val || this.close()
},
options:{
handler(e){
console.dir(e);
const sortBy = e.sortBy.length>0 ? e.sortBy[0].trim() : 'id';
const orderBy = e.sortDesc[0] ? 'desc' : 'asc';
axios.get(`/api/locations`,{params:{'page':e.page, 'per_page':e.itemsPerPage, 'sort_by': sortBy, 'order_by': orderBy}})
.then(res => {
this.locations = res.data.locations
})
},
deep: true
}
},
created () {
this.initialize()
},
methods: {
selectAll(e){
this.selected = [];
if(e.length > 0){
this.selected = e.map(val => val.id)
}
},
deleteAll(){
let decide = confirm('Are you sure you want to delete these items?')
if(decide){
axios.post('/api/locations/delete', {'locations': this.selected})
.then(res => {
this.text = "Records Deleted Successfully!";
this.selected.map(val => {
const index = this.locations.data.indexOf(val)
this.locations.data.splice(index, 1)
})
this.snackbar = true
}).catch(err => {
console.log(err.response)
this.text = "Error Deleting Record"
this.snackbar=true
})
}
},
searchIt(e){
if(e.length > 3){
axios.get(`/api/locations/${e}`)
.then(res => this.locations = res.data.locations)
.catch(err => console.dir(err.response))
}
if(e.length<=0){
axios.get(`/api/locations`)
.then(res => this.locations = res.data.locations)
.catch(err => console.dir(err.response))
}
},
paginate(e){
const sortBy = e.sortBy.length>0 ? e.sortBy[0].trim() : 'code';
const orderBy = e.sortDesc[0] ? 'desc' : 'asc';
axios.get(`/api/locations`,{params:{'page':e.page, 'per_page':e.itemsPerPage, 'sort_by': sortBy, 'order_by': orderBy}})
.then(res => {
this.locations = res.data.locations
})
},
initialize () {
// Add a request interceptor
axios.interceptors.request.use((config) => {
this.loading = true;
return config;
}, (error) => {
this.loading = false;
return Promise.reject(error);
});
// Add a response interceptor
axios.interceptors.response.use( (response) => {
this.loading = false;
return response;
}, (error) => {
this.loading = false
return Promise.reject(error);
});
},
editItem (item) {
this.editedIndex = this.locations.data.indexOf(item)
this.editedItem = Object.assign({}, item)
this.dialog = true
},
deleteItem (item) {
const index = this.locations.data.indexOf(item)
let decide = confirm('Are you sure you want to delete this item?')
if(decide){
axios.delete('/api/locations/'+item.id)
.then(res => {
this.text = "Record Deleted Successfully!";
this.snackbar = true
this.locations.data.splice(index, 1)
}).catch(err => {
console.log(err.response)
this.text = "Error Deleting Record"
this.snackbar=true
})
}
},
close () {
this.dialog = false
setTimeout(() => {
this.editedItem = Object.assign({}, this.defaultItem)
this.editedIndex = -1
}, 300)
},
save () {
if (this.editedIndex > -1) {
const index = this.editedIndex
axios.put('/api/locations/'+this.editedItem.id, {'code': this.editedItem.code, 'name': this.editedItem.name, 'description': this.editedItem.description})
.then(res => {
this.text = "Record Updated Successfully!";
this.snackbar = true;
Object.assign(this.locations.data[index], res.data.location)
})
.catch(err => {
console.log(err.response)
this.text = "Error Updating Record"
this.snackbar=true
})
// Object.assign(this.locations[this.editedIndex], this.editedItem)
} else {
axios.post('/api/locations',{'code': this.editedItem.code, 'name': this.editedItem.name, 'description': this.editedItem.description})
.then(res => {
this.text = "Record Added Successfully!";
this.snackbar=true;
this.locations.data.push(res.data.location)
})
.catch(err => {
console.dir(err.response)
this.text = "Error Inserting Record"
this.snackbar=true
})
}
this.close()
},
},
}
</script>
<style scoped></style>
Location.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Location extends Model
{
protected $guarded = [];
}
LocationController.php
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Location;
class LocationController extends Controller
{
public function index(Request $request)
{
$per_page = $request->per_page ? $request->per_page : 5;
$sort_by = $request->sort_by;
$order_by = $request->order_by;
return response()->json(['locations' => Location::orderBy($sort_by, $order_by)->paginate($per_page)],200);
}
public function store(Request $request)
{
$location= Location::create([
'code' =>$request->code
'name' =>$request->name
'description' =>$request->description
]);
return response()->json(['location'=>$location],200);
}
public function show($id)
{
$locations = Location::where('code', 'name','description''LIKE', "%$id%")->paginate();
return response()->json(['locations' => $locations],200);
}
public function update(Request $request, $id)
{
$location = Location::find($id);
$location->code = $request->code;
$location->name = $request->name;
$location->description = $request->description;
$location->save();
return response()->json(['location'=>$location], 200);
}
public function destroy($id)
{
$location = Location::find($id)->delete();
return response()->json(['location'=>$location],200);
}
public function deleteAll(Request $request){
Location::whereIn('id', $request->locations)->delete();
return response()->json(['message', 'Records Deleted Successfully'], 200);
}
}
yeah, the issue in your LocationController.php file, you missed commas in Location::create . Also, show function has a problem. notice carefully.
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Location;
class LocationController extends Controller
{
public function index(Request $request)
{
$per_page = $request->per_page ? $request->per_page : 5;
$sort_by = $request->sort_by;
$order_by = $request->order_by;
return response()->json(['locations' => Location::orderBy($sort_by, $order_by)->paginate($per_page)],200);
}
public function store(Request $request)
{
$location= Location::create([
'code' =>$request->code,
'name' =>$request->name,
'description' =>$request->description
]);
return response()->json(['location'=>$location],200);
}
public function show($id)
{
$locations = Location::where('code','LIKE', "%$id%")->orWhere('name','LIKE', "%$id%")->orWhere('description', 'LIKE', "%$id%")->paginate();
return response()->json(['locations' => $locations],200);
}
public function update(Request $request, $id)
{
$location = Location::find($id);
$location->code = $request->code;
$location->name = $request->name;
$location->description = $request->description;
$location->save();
return response()->json(['location'=>$location], 200);
}
public function destroy($id)
{
$location = Location::where('id', $id)->delete();
return response()->json(['location'=>$location],200);
}
public function deleteAll(Request $request){
Location::whereIn('id', $request->locations)->delete();
return response()->json(['message', 'Records Deleted Successfully'], 200);
}
}

Select Box is not changing immediately after changing input in ElementUi Vue

I have made a CRUD based admin pannel with laravue. Now my problem is that whenever I am on the update page, I can't change the category immediately. I always have to make change in some other field to view the changed category. Its working fine on add card page when all the fields are empty.
This is the video of my issue
https://thisisntmyid.tumblr.com/post/189075383873/my-issue-with-elementui-and-laravue-and-vue
I've included the code for my list page as well as the add/update page.
Code for the listing page that will lead u to edit page
<div class="app-container">
<h1>My Cards</h1>
<Pagination
:total="totalCards"
layout="total, prev, pager, next"
:limit="10"
:page.sync="currentPage"
#pagination="loadNewPage"
></Pagination>
<el-table v-loading="loadingCardsList" :data="cards" stripe style="width: 100%">
<el-table-column prop="name" sortable label="Product Name"></el-table-column>
<el-table-column prop="description" label="Description" width="200px"></el-table-column>
<el-table-column prop="price" label="Price"></el-table-column>
<el-table-column prop="cardcategory" sortable label="Category"></el-table-column>
<el-table-column label="Operations" width="300px">
<template slot-scope="scope">
<el-button size="mini" type="primary" #click="handleView(scope.$index, scope.row)">View</el-button>
<el-button size="mini" #click="handleEdit(scope.$index, scope.row)">Edit</el-button>
<el-button size="mini" type="danger" #click="handleDelete(scope.$index, scope.row)">Delete</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog :visible.sync="viewCard" width="30%">
<el-card class="box-card">
<h1>{{currentViewedCard.name}}</h1>
<p>{{currentViewedCard.description}}</p>
<p>{{currentViewedCard.price}}</p>
<el-tag>{{currentViewedCard.cardcategory}}</el-tag>
</el-card>
</el-dialog>
</div>
</template>
<script>
import Resource from '#/api/resource';
import Pagination from '#/components/Pagination/index.vue';
const cardcategoryResource = new Resource('cardcategories');
const cardResource = new Resource('cards');
export default {
name: 'Cards',
components: {
Pagination,
},
data() {
return {
cards: [],
categories: [],
currentPage: '',
totalCards: '',
loadingCardsList: true,
currentViewedCard: '',
viewCard: false,
};
},
created() {
this.getCardCategories();
this.getCardList({ page: 1 });
},
methods: {
async getCardList(query) {
this.loadingCardsList = true;
const data = await cardResource.list(query);
this.cards = data.data;
for (const card of this.cards) {
card['cardcategory'] = this.getCategoryName(card.cardCategory_id);
}
console.log(this.cards);
this.totalCards = data.total;
this.loadingCardsList = false;
},
async getCardCategories() {
this.categories = await cardcategoryResource.list({});
console.log(this.categories);
},
loadNewPage(val) {
this.getCardList({ page: val.page });
},
getCategoryName(id) {
return this.categories[id - 1].name;
},
handleView(index, info) {
this.viewCard = true;
this.currentViewedCard = info;
},
handleEdit(index, info) {
this.$router.push('/cards/edit/' + info.id);
},
closeDialog() {
this.viewProduct = false;
this.currentProductInfo = null;
},
handleDelete(index, info) {
cardResource.destroy(info.id).then(response => {
this.$message({
message: 'Card Deleted Successfully',
type: 'success',
duration: 3000,
});
this.getCardList({ page: this.currentPage });
});
},
},
};
</script>
<style lang="scss" scoped>
</style>
Code for the add/update page
<template>
<div class="app-container">
<el-form ref="form" :model="formData" label-width="120px">
<el-form-item label="Name">
<el-input v-model="formData.name"></el-input>
</el-form-item>
<el-form-item label="Description">
<el-input type="textarea" v-model="formData.description"></el-input>
</el-form-item>
<el-form-item label="Price">
<el-input v-model="formData.price"></el-input>
</el-form-item>
<el-form-item label="Category">
<!-- DO something here like binding category id to category name sort of meh... -->
<el-select v-model="formData.cardcategory" placeholder="please select category">
<el-option v-for="item in categories" :key="item" :label="item" :value="item"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" #click="editable ? updateProduct() : createProduct()">Save</el-button>
<el-button #click="editable ? populateFormData($route.params.id) : formDataReset()">Reset</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import Resource from '#/api/resource';
const cardcategoryResource = new Resource('cardcategories');
const cardResource = new Resource('cards');
export default {
data() {
return {
formData: {
name: '',
description: '',
price: '',
cardcategory: '',
},
categories: [],
editable: '',
};
},
created() {
this.getCategories();
if (this.$route.params.id) {
this.editable = true;
this.populateFormData(this.$route.params.id);
} else {
this.editable = false;
}
},
methods: {
async getCategories() {
this.categories = (await cardcategoryResource.list({})).map(
cat => cat.name
);
console.log(this.categories);
},
formDataReset() {
this.formData = {
name: '',
description: '',
price: '',
cardcategory: '',
};
},
populateFormData(id) {
cardResource.get(id).then(response => {
this.formData = Object.assign({}, response);
this.formData.price = this.formData.price.toString();
this.formData.cardcategory = this.categories[
this.formData.cardCategory_id - 1
];
delete this.formData.cardCategory_id;
});
},
filterFormData(formData) {
const cardData = Object.assign({}, formData);
cardData['cardCategory_id'] =
this.categories.indexOf(cardData.cardcategory) + 1;
delete cardData.cardcategory;
return cardData;
},
createProduct() {
const cardData = this.filterFormData(this.formData);
cardResource
.store(cardData)
.then(response => {
this.$message({
message: 'New Card Added',
type: 'success',
duration: 3000,
});
this.formDataReset();
})
.catch(response => {
alert(response);
});
},
updateProduct() {
const cardData = this.filterFormData(this.formData);
cardResource.update(this.$route.params.id, cardData).then(response => {
this.$message({
message: 'Card Updated Successfully',
type: 'success',
duration: 3000,
});
this.populateFormData(this.$route.params.id);
});
},
},
};
</script>
<style>
</style>
Update
here is the git hub repo for my project
https://github.com/ThisIsntMyId/laravue-admin-pannel-demo

The localStorage is not refreshing in Vuex

I write codes with Vuex to login and logout in my Laravel single page application it's working well but when i login to an account the profiles information (name, address, Email, ...)doesn't show in profile but after i reload the page the profile information loads, and when another user try the profile the data of the last person that login shown to him/her
auth.js:
export function registerUser(credentials){
return new Promise((res,rej)=>{
axios.post('./api/auth/register', credentials)
.then(response => {
res(response.data);
})
.catch(err => {
rej('Somthing is wrong!!')
})
})
}
export function login(credentials){
return new Promise((res,rej)=>{
axios.post('./api/auth/login', credentials)
.then(response => {
res(response.data);
})
.catch(err => {
rej('The Email or password is incorrect!')
})
})
}
export function getLoggedinUser(){
const userStr = localStorage.getItem('user');
if(!userStr){
return null
}
return JSON.parse(userStr);
}
store.js:
import {getLoggedinUser} from './partials/auth';
const user = getLoggedinUser();
export default {
state: {
currentUser: user,
isLoggedIn: !!user,
loading: false,
auth_error: null,
reg_error:null,
registeredUser: null,
},
getters: {
isLoading(state){
return state.loading;
},
isLoggedin(state){
return state.isLoggedin;
},
currentUser(state){
return state.currentUser;
},
authError(state){
return state.auth_error;
},
regError(state){
return state.reg_error;
},
registeredUser(state){
return state.registeredUser;
},
},
mutations: {
login(state){
state.loading = true;
state.auth_error = null;
},
loginSuccess(state, payload){
state.auth_error = null;
state.isLoggedin = true;
state.loading = false;
state.currentUser = Object.assign({}, payload.user, {token: payload.access_token});
localStorage.setItem("user", JSON.stringify(state.currentUser));
},
loginFailed(state, payload){
state.loading = false;
state.auth_error = payload.error;
},
logout(state){
localStorage.removeItem("user");
state.isLoggedin = false;
state.currentUser = null;
},
registerSuccess(state, payload){
state.reg_error = null;
state.registeredUser = payload.user;
},
registerFailed(state, payload){
state.reg_error = payload.error;
},
},
actions: {
login(context){
context.commit("login");
},
}
};
general.js:
export function initialize(store, router) {
router.beforeEach((to, from, next) => {
const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
const currentUser = store.state.currentUser;
if(requiresAuth && !currentUser) {
next('/login');
} else if(to.path == '/login' && currentUser) {
next('/');
} else {
next();
}
if(to.path == '/register' && currentUser) {
next('/');
}
});
axios.interceptors.response.use(null, (error) => {
if (error.resposne.status == 401) {
store.commit('logout');
router.push('/login');
}
return Promise.reject(error);
});
if (store.getters.currentUser) {
setAuthorization(store.getters.currentUser.token);
}
}
export function setAuthorization(token) {
axios.defaults.headers.common["Authorization"] = `Bearer ${token}`
}
I think that this issue is relate to my localstorage, how can i fix this?
I'm novice at the Vue and don't have any idea what is the problem.
Login Component:
<template>
<main>
<form #submit.prevent="authenticate">
<div class="grid-x grid-padding-x">
<div class="small-10 small-offset-2 cell" v-if="registeredUser">
<p class="alert success">Welcome {{registeredUser.name}}</p>
</div>
<div class="small-10 small-offset-2 cell" v-if="authError">
<p class="alert error">
{{authError}}
</p>
</div>
<div class="small-2 cell">
<label for="email" class="text-right middle">Email:</label>
</div>
<div class="small-10 cell">
<input type="email" v-model="formLogin.email" placeholder="Email address">
</div>
<div class="small-2 cell">
<label for="password" class="text-right middle">Password:</label>
</div>
<div class="small-10 cell">
<input type="password" v-model="formLogin.password" placeholder="Enter password">
</div>
<div class="small-10 small-offset-2 cell">
<div class="gap"></div>
<input type="submit" value="Login" class="button success expanded">
</div>
</div>
</form>
</main>
</template>
<script>
import {login} from '../../partials/auth';
export default {
data(){
return {
formLogin: {
email: '',
password: ''
},
error: null
}
},
methods:{
authenticate(){
this.$store.dispatch('login');
login(this.$data.formLogin)
.then(res => {
this.$store.commit("loginSuccess", res);
this.$router.push({path: '/profile'});
})
.catch(error => {
this.$store.commit("loginFailed", {error});
})
}
},
computed:{
authError(){
return this.$store.getters.authError
},
registeredUser(){
return this.$store.getters.registeredUser
}
}
}
</script>
Localstorage data is once loaded on page load, so when you use setItem, this won't be visible until the next time.
You should store the data to vuex store, and use that as the source. Only set and get the data from localstorage on page loads.
Otherwise use something like: https://github.com/robinvdvleuten/vuex-persistedstate
I solved the problem.I have this code in my EditProfile component.
methods: {
getAuthUser () {
axios.get(`./api/auth/me`)
.then(response => {
this.user = response.data
})
},
}
this.user = response.data is wrong, I changed to this:
getAuthUser () {
this.user = this.$store.getters.currentUser
},

Use tab key not working on Prime-react editable Data table

I used an editable data Table of prime-react , and it worked mouse click. But Problem is tab key not work.I want to enable editable mode one cell to another cell using tab key. I use Prime react version 1.4.0
A full code are given below:-
index.js
where my editable table code contains
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { FormattedMessage } from 'react-intl';
import { createStructuredSelector } from 'reselect';
import { compose } from 'redux';
import injectSaga from 'utils/injectSaga';
import injectReducer from 'utils/injectReducer';
import reducer from './reducer';
import saga from './saga';
import messages from './messages';
import { Messages } from 'primereact/components/messages/Messages';
import { Growl } from 'primereact/components/growl/Growl';
import { Panel } from 'primereact/components/panel/Panel';
import { Button } from 'primereact/components/button/Button';
import { DataTable } from 'primereact/components/datatable/DataTable';
import { Column } from 'primereact/components/column/Column';
import { InputText } from 'primereact/components/inputtext/InputText';
import { Dropdown } from 'primereact/components/dropdown/Dropdown';
import CustomDataTable from 'components/CustomDataTable';
import { makeSelectSelectedStudent, makeSelectSectionName, makeSelectStudentUpdateBasicInformation, makeSelectSectionList, makeSelectStdBasicInfo, makeSelectEditorStudent, makeSelectSetMessage, makeSelectSetErrMessage, makeSelectLoaderOff, makeSelectLoaderOn } from './selectors';
import { selectStudent, setEditorData, submitUpdate, getMessage, getErrMessage, submitForm, changeSectionName, getLoaderOn, getLoaderOff } from './actions';
import AppPrivateLayout from '../AppPrivateLayout';
export class StudentUpdateBasicInformation extends React.Component {
componentDidUpdate() {
this.props.changeMessage('');
}
rollBody(rowData) {
return <InputText type="text" value={rowData.studentRoll} />;
}
nameBody(rowData) {
return <InputText type="text" value={rowData.studentName} />;
}
fatherNameBody(rowData) {
return <InputText type="text" value={rowData.fatherName} />;
}
motherNameBody(rowData) {
return <InputText type="text" value={rowData.motherName} />;
}
contactBody(rowData) {
return <InputText type="text" value={rowData.guardianMobile} />;
}
genderBody(rowData) {
let gender = [
{ label: 'Male', value: 'Male' },
{ label: 'Female', value: 'Female' },
{ label: 'Others', value: 'Others' }
];
return <Dropdown value={rowData.studentGender} options={gender} style={{ width: '100%' }} placeholder="Select" />
}
religionBody(rowData) {
let religion = [
{ label: 'Islam', value: 'Islam' },
{ label: 'Hindu', value: 'Hindu' },
{ label: 'Buddhist', value: 'Buddhist' },
{ label: 'Christian', value: 'Christian' },
{ label: 'Others', value: 'Others' }
];
return <Dropdown value={rowData.studentReligion} options={religion} style={{ width: '100%' }} placeholder="Select" />
}
bloodBody(rowData) {
let blood = [
{ label: 'A+', value: 'A+' },
{ label: 'A-', value: 'A-' },
{ label: 'B+', value: 'B+' },
{ label: 'B-', value: 'B-' },
{ label: 'O+', value: 'O+' },
{ label: 'O-', value: 'O-' }
];
return <Dropdown value={rowData.bloodGroup} options={blood} style={{ width: '100%' }} placeholder="Select" />
}
render() {
let rollEditor = (row) => {
return <InputText onChange={(evt) => { this.props.onEditorValueChange(row, evt.target.value); }} placeholder="Roll" value={row.rowData.studentRoll} />
}
let nameEditor = (row) => {
return <InputText onChange={(evt) => { this.props.onEditorValueChange(row, evt.target.value); }} placeholder="Student name" value={row.rowData.studentName} />
}
let fatherNameEditor = (row) => {
return <InputText onChange={(evt) => { this.props.onEditorValueChange(row, evt.target.value); }} placeholder="Father name" value={row.rowData.fatherName} />
}
let motherNameEditor = (row) => {
return <InputText onChange={(evt) => { this.props.onEditorValueChange(row, evt.target.value); }} placeholder="Mother name" value={row.rowData.motherName} />
}
let contactEditor = (row) => {
return <InputText onChange={(evt) => { this.props.onEditorValueChange(row, evt.target.value); }} placeholder="Contact Number" value={row.rowData.guardianMobile} />
}
let genderEditor = (row) => {
let gender = [
{ label: 'Male', value: 'Male' },
{ label: 'Female', value: 'Female' },
{ label: 'Others', value: 'Others' }
];
return <Dropdown value={row.rowData.gender} options={gender} onChange={(evt) => this.props.onEditorValueChange(row, evt.value)} style={{ width: '100%' }} placeholder="Select" />
}
let religionEditor = (row) => {
let religion = [
{ label: 'Islam', value: 'Islam' },
{ label: 'Hindu', value: 'Hindu' },
{ label: 'Buddhist', value: 'Buddhist' },
{ label: 'Christian', value: 'Christian' },
{ label: 'Others', value: 'Others' }
];
return <Dropdown value={row.rowData.religion} options={religion} onChange={(evt) => { this.props.onEditorValueChange(row, evt.value); }} style={{ width: '100%' }} placeholder="Select" />
}
let bloodEditor = (row) => {
let blood = [
{ label: 'A+', value: 'A+' },
{ label: 'A-', value: 'A-' },
{ label: 'B+', value: 'B+' },
{ label: 'B-', value: 'B-' },
{ label: 'O+', value: 'O+' },
{ label: 'O-', value: 'O-' }
];
return <Dropdown value={row.rowData.blood} options={blood} onChange={(evt) => { this.props.onEditorValueChange(row, evt.value); }} style={{ width: '100%' }} placeholder="Select" />
}
let msg = "";
if (this.props.setMessage) {
msg = { severity: 'success', detail: this.props.setMessage.message };
this.growl.show(msg);
}
else if (this.props.setErrMessage) {
msg = { severity: 'error', summary: 'Failed', detail: this.props.setErrMessage };
this.growl.show(msg);
}
if(this.props.loaderOn){
if(this.props.loaderOn === 'On') {
$('.loaderDiv').show();
} else if(this.props.loaderOn === 'Off'){
$('.loaderDiv').hide();
}
}
let content = '';
if (this.props.stdBasicInfo && this.props.stdBasicInfo.length) {
$('#UpdateBtnID').show();
let selectedStudentArr = [];
if (this.props.selectedStudent.length) {
Array.prototype.push.apply(selectedStudentArr, this.props.selectedStudent);
}
let columnData = [
<Column selectionMode="multiple" header="Mark" style={{ width: '3em' }} />,
<Column field="studentRoll" header="Roll No." editor={rollEditor} body={this.rollBody} style={{ width: '55px' }} />,
<Column field="studentName" header="Name" editor={nameEditor} body={this.nameBody} style={{ width: '170px' }} />,
<Column field="fatherName" header="Father Name" editor={fatherNameEditor} body={this.fatherNameBody} style={{ width: '145px' }} />,
<Column field="motherName" header="Mother Name" editor={motherNameEditor} body={this.motherNameBody} style={{ width: '145px' }} />,
<Column field="guardianMobile" header="Contact No." editor={contactEditor} style={{ width: '100px' }} body={this.contactBody} />,
<Column field="studentGender" header="Gender" editor={genderEditor} body={this.genderBody} style={{ width: '85px' }} />,
<Column field="studentReligion" header="Religion" editor={religionEditor} body={this.religionBody} style={{ width: '85px' }} />,
<Column field="bloodGroup" header="Blood Group" editor={bloodEditor} style={{ width: '80px' }} body={this.bloodBody} />
];
content = <CustomDataTable
info={this.props.stdBasicInfo}
onSelectionChange={this.props.onSelectionChange}
selectedData={selectedStudentArr}
columnData={columnData}
isSelectionOn={true}
editable={true}
header={'Student List'}
rows={10}
/>
}
//FOR SECTION LIST
let sectionListOptions = [];
if (this.props.sectionList && this.props.sectionList.length) {
sectionListOptions = this.props.sectionList.map((item) => ({
value: item.classConfigId,
label: item.classShiftSection,
}))
}
return (
<div>
<AppPrivateLayout>
<Panel header="Student Information Update">
<form method="post" onSubmit={this.props.onSubmitForm} >
<div className='ui-g form-group'>
<div className='ui-g-2 ui-lg-2 ui-md-2'></div>
<div className='ui-g-2 ui-lg-2 ui-md-2 ui-sm-12 netiLabel'>
<label> Section <span className="required"> * </span></label>
</div>
<div className='ui-g-3 ui-lg-3 ui-md-4 ui-sm-12 ui-fluid'>
<Dropdown value={this.props.sectionname} onChange={this.props.onChangeSectionList} options={sectionListOptions} placeholder="Select Section" autoWidth={false} />
</div>
<div className='ui-g-2 ui-lg-2 ui-md-3 ui-sm-12 ui-fluid'>
<Button icon="ui-icon-search" title="Search" label='Search'></Button>
</div>
<div className='ui-g-2 ui-lg-2 ui-fluid'></div>
</div>
</form>
{content}
<div className='ui-g'>
<Growl ref={(el) => this.growl = el} />
<div className='ui-g-4 ui-lg-4 ui-md-4 ui-sm-12 ui-fluid'>
</div>
<div className='ui-g-6 ui-lg-6 ui-md-5 ui-sm-12 ui-fluid'></div>
<div className='ui-g-2 ui-lg-2 ui-md-3 ui-sm-12 ui-fluid'>
<Button id="UpdateBtnID" style={{ display: 'none' }} onClick={this.props.onUpdate} icon='ui-icon-autorenew' label='Update'></Button>
</div>
</div>
</Panel>
<div class="loaderDiv" style={{display: 'none'}}>
<img className="sticky" src="https://loading.io/spinners/harmony/lg.harmony-taiji-spinner.gif" />
</div>
</AppPrivateLayout>
</div>
);
}
}
StudentUpdateBasicInformation.propTypes = {
stdBasicInfo: PropTypes.any,
onSubmitForm: PropTypes.func,
onEditorValueChange: PropTypes.func,
value: PropTypes.any,
onUpdate: PropTypes.func,
setMessage: PropTypes.any,
setErrMessage: PropTypes.any,
changeMessage: PropTypes.func,
sectionList: PropTypes.any,
onChangeSectionList: PropTypes.func,
sectionname: PropTypes.any,
loaderOn: PropTypes.any,
};
const mapStateToProps = createStructuredSelector({
stdBasicInfo: makeSelectStdBasicInfo(),
selectedStudent: makeSelectSelectedStudent(),
value: makeSelectEditorStudent(),
setMessage: makeSelectSetMessage(),
setErrMessage: makeSelectSetErrMessage(),
sectionList: makeSelectSectionList(),
sectionname: makeSelectSectionName(),
loaderOn: makeSelectLoaderOn(),
});
function mapDispatchToProps(dispatch) {
return {
changeMessage: (evt) => {
dispatch(getMessage());
dispatch(getErrMessage());
dispatch(getLoaderOn(evt));
},
onSubmitForm: (evt) => {
if (evt !== undefined && evt.preventDefault)
evt.preventDefault();
dispatch(submitForm());
},
onSelectionChange: (evt) => dispatch(selectStudent(evt.data)),
onEditorValueChange: (row, value) => {
dispatch(setEditorData(row, value));
},
onUpdate: (evt) => dispatch(submitUpdate()),
onChangeSectionList: (evt) => dispatch(changeSectionName(evt.value)),
};
}
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withReducer = injectReducer({ key: 'studentUpdateBasicInformation', reducer });
const withSaga = injectSaga({ key: 'studentUpdateBasicInformation', saga });
export default compose(
withReducer,
withSaga,
withConnect,
)(StudentUpdateBasicInformation);
constants.js
export const DEFAULT_ACTION = 'app/StudentUpdateBasicInformation/DEFAULT_ACTION';
export const SUBMIT_FORM = 'app/StudentUpdateBasicInformation/SUBMIT_FORM';
export const SET_STD_BASIC_INFO = 'app/StudentUpdateBasicInformation/SET_STD_BASIC_INFO';
export const SELECT_STUDENT = 'app/StudentUpdateBasicInformation/SELECT_STUDENT';
export const SET_EDITOR_DATA = 'app/StudentUpdateBasicInformation/SET_EDITOR_DATA';
export const GET_MESSAGE = 'app/StudentUpdateStudentId/GET_MESSAGE';
export const GET_ERR_MESSAGE = 'app/StudentUpdateStudentId/GET_ERR_MESSAGE';
export const SUBMIT_UPDATE = 'app/StudentUpdateBasicInformation/SUBMIT_UPDATE';
export const SET_SECTION_LIST = 'app/StudentUpdateBasicInformation/SET_SECTION_LIST';
export const CHANGE_SECTIONNAME = 'app/StudentUpdateBasicInformation/CHANGE_SECTIONNAME';
export const GET_LOADER_ON = 'app/StudentUpdateBasicInformation/GET_LOADER_ON';
actions.js
import {
DEFAULT_ACTION, SUBMIT_FORM, SET_STD_BASIC_INFO, SELECT_STUDENT, SET_EDITOR_DATA, SUBMIT_UPDATE, GET_MESSAGE, GET_ERR_MESSAGE, CHANGE_SECTIONNAME, SET_SECTION_LIST, GET_LOADER_OFF, GET_LOADER_ON
} from './constants';
export function defaultAction() {
return {
type: DEFAULT_ACTION,
};
}
export function setStdBasicInfo(item) {
return {
type: SET_STD_BASIC_INFO,
item,
}
}
export function selectStudent(data) {
return {
type: SELECT_STUDENT,
data,
};
}
export function setEditorData(row, value) {
return {
type: SET_EDITOR_DATA,
row,
value,
};
}
export function submitForm() {
return {
type: SUBMIT_FORM,
};
}
export function submitUpdate() {
return {
type: SUBMIT_UPDATE,
};
}
export function getMessage(message) {
return {
type: GET_MESSAGE,
message,
}
}
export function getErrMessage(errmessage) {
return {
type: GET_ERR_MESSAGE,
errmessage,
}
}
export function setSectionList(sectionList) {
return {
type: SET_SECTION_LIST,
sectionList,
};
}
export function changeSectionName(sectionname) {
return {
type: CHANGE_SECTIONNAME,
sectionname,
};
}
export function getLoaderOn(loaderOn){
return{
type: GET_LOADER_ON,
loaderOn,
}
}
reducer.js
import { fromJS } from 'immutable';
import {
DEFAULT_ACTION, SET_STD_BASIC_INFO, SELECT_STUDENT, SET_EDITOR_DATA, GET_MESSAGE, GET_ERR_MESSAGE, SET_SECTION_LIST, CHANGE_SECTIONNAME, GET_LOADER_ON, GET_LOADER_OFF
} from './constants';
const initialState = fromJS({
selectedStudent: [],
value: [],
sectionList: {},
sectionname: '',
});
function studentUpdateBasicInformationReducer(state = initialState, action) {
switch (action.type) {
case DEFAULT_ACTION:
return state;
case SET_STD_BASIC_INFO:
return state.set('stdBasicInfo', action.item);
case SELECT_STUDENT:
return state.set('selectedStudent', action.data);
case SET_EDITOR_DATA:
let updatedInfost = [...action.row.value];
updatedInfost = [...action.row.value];
updatedInfost[action.row.rowIndex][action.row.field] = action.value;
return state.set('stdBasicInfo', updatedInfost);
case GET_MESSAGE:
return state.set('setMessage', action.message);
case GET_ERR_MESSAGE:
return state.set('setErrMessage', action.errmessage);
case SET_SECTION_LIST:
return state.set('sectionList', action.sectionList);
case CHANGE_SECTIONNAME:
return state.set('sectionname', action.sectionname);
case GET_LOADER_ON:
return state.set('loaderOn', action.loaderOn);
// case GET_LOADER_OFF:
// return state.set('loaderOff', action.loaderOff);
default:
return state;
}
}
export default studentUpdateBasicInformationReducer;
selectors.js
import { createSelector } from 'reselect';
const selectStudentUpdateBasicInformationDomain = (state) => state.get('studentUpdateBasicInformation');
const makeSelectStudentUpdateBasicInformation = () => createSelector(
selectStudentUpdateBasicInformationDomain,
(substate) => substate.toJS()
);
const makeSelectStdBasicInfo = () => createSelector(selectStudentUpdateBasicInformationDomain, (abc) => abc.get('stdBasicInfo'));
const makeSelectSelectedStudent = () => createSelector(selectStudentUpdateBasicInformationDomain, (substate) => substate.get('selectedStudent'));
const makeSelectEditorStudent = () => createSelector(selectStudentUpdateBasicInformationDomain, (substate) => substate.get('value'));
const makeSelectSetMessage = () => createSelector(selectStudentUpdateBasicInformationDomain, (abc) => abc.get('setMessage'));
const makeSelectSetErrMessage = () => createSelector(selectStudentUpdateBasicInformationDomain, (abc) => abc.get('setErrMessage'));
const makeSelectSectionName = () => createSelector(selectStudentUpdateBasicInformationDomain, (abc) => abc.get('sectionname'));
const makeSelectSectionList = () => createSelector(selectStudentUpdateBasicInformationDomain,(substate) => substate.get('sectionList'));
const makeSelectLoaderOn = () => createSelector(selectStudentUpdateBasicInformationDomain, (substate) => substate.get('loaderOn'));
export {
selectStudentUpdateBasicInformationDomain,
makeSelectStdBasicInfo,
makeSelectSelectedStudent,
makeSelectEditorStudent,
makeSelectSetMessage,
makeSelectSetErrMessage, makeSelectSectionName, makeSelectSectionList, makeSelectLoaderOn,
//makeSelectLoaderOff
};
saga.js
import { take, call, put, select, takeLatest } from 'redux-saga/effects';
import { BASE_URL, FETCH_BASIC_INFO_LIST, UPDATE_ID, GET_CLASS_CONFIGURATION_URL, STUDENT_CONFIG_LIST } from '../../utils/serviceUrl';
import { setStdBasicInfo, getMessage, getErrMessage, selectStudent, setSectionList, changeSectionName, getLoaderOn } from './actions';
import request from '../../utils/request';
import { SUBMIT_FORM, SUBMIT_UPDATE } from './constants';
import { makeSelectEditorStudent, makeSelectSelectedStudent, makeSelectSectionList, makeSelectSectionName } from './selectors';
import { getTokenData } from '../../utils/authHelper';
//FOR SECTION LIST
export function* fetchSectionList() {
const tokenData = JSON.parse(getTokenData());
const requestUrl = BASE_URL.concat(GET_CLASS_CONFIGURATION_URL);
const options = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': tokenData.token_type+" "+tokenData.access_token,
},
};
try {
const response = yield call(request, requestUrl, options);
if (response.item) {
yield put(setSectionList(response.item));
}
} catch (err) {
console.dir(err);
}
}
//FOR STUDENT BASIC INFO LIST
export function* fetchStudentBasicInfoList() {
const tokenData = JSON.parse(getTokenData());
const classConfigId = yield select(makeSelectSectionName());
let msgg;
if (classConfigId == '') {
let msg = "An error has occured. Please fill up all required fields";
yield put(getErrMessage(msg));
}
else {
msgg = 'On';
yield put(getLoaderOn(msgg));
const requestURL = BASE_URL.concat(STUDENT_CONFIG_LIST).concat('?classConfigId=').concat(classConfigId);
const options = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': tokenData.token_type+" "+tokenData.access_token,
},
};
const info = yield call(request, requestURL,options);
yield put(setStdBasicInfo(info.item));
msgg = 'Off';
yield put(getLoaderOn(msgg));
}
}
//FOR UPDATE STUDENT INFORMATION
export function* updateStdBasicInfo() {
const tokenData = JSON.parse(getTokenData());
const selectedCheckData = yield select(makeSelectSelectedStudent());
let selectedData = [];
if (selectedCheckData.length === undefined || selectedCheckData.length === 0) {
const errresult = "An error has occured. Please fill up all required fields";
yield put(getErrMessage(errresult));
} else {
for (const i in selectedCheckData) {
const DataList = selectedCheckData[i];
selectedData.push(DataList);
}
const requestURL = BASE_URL.concat(UPDATE_ID);
const options = {
method: 'PUT',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': tokenData.token_type+" "+tokenData.access_token,
},
body: JSON.stringify(selectedData),
}
try {
const result = yield call(request, requestURL, options);
yield put(selectStudent([]));
yield fetchStudentBasicInfoList();
yield put(getMessage(result));
} catch (err) {
const errresult = "Something went wrong. Please try again.";
yield put(setStdBasicInfo(info.item));
yield put(getErrMessage(errresult));
}
}
}
export default function* defaultSaga() {
yield fetchSectionList();
yield takeLatest(SUBMIT_FORM, fetchStudentBasicInfoList);
yield takeLatest(SUBMIT_UPDATE, updateStdBasicInfo);
}
DuĊĦan's answer worked for me but for 2 exceptions:
In onEditorKeyDown instead of
var table = this.dt.container.childNodes[1].childNodes[0].childNodes[1];
use
let table = this.dt.container.childNodes[0].childNodes[0].childNodes[1];
In addition, (event.which === 9) should be used instead of (event.keyCode == 9) and all the functions must be bound in the constructor:
this.inputTextEditor = this.inputTextEditor.bind(this)
this.xxxEditor = this.xxxEditor.bind(this)
this.onEditorKeyDown = this.onEditorKeyDown.bind(this)
I have an idea how you can do this:
while you are in editable cell, you need to intercept TAB key and then to simulate click on next cell to the right or, if current cell is the last one, on first cell in next row.
Steps in following example are based on PrimeReact's show case editable page. You can adopt them for your particular case.
FUNCTIONAL EXAMPLE
Step 1:
define onRowClickhandler and add it to DataTable component to be able to catch currently clicked rowIndex (we need to know what is the row index of the cell currently edited)
onRowClick(event) {
this.rowIndex = event.index;
}
...
<DataTable ref={(el) => this.dt = el} editable={true} onRowClick={(e) => this.onRowClick(e)} ...>
Step 2:
Define column index (ordinal number) to each of column editors: 1st column has index 0, 2nd column index 1, etc. For example
vinEditor(props) {
return this.inputTextEditor(props, 'vin', 0);
}
yearEditor(props) {
return this.inputTextEditor(props, 'year', 1);
}
brandEditor(props) {
return this.inputTextEditor(props, 'brand', 2);
}
where inputTextEditor now look like this
inputTextEditor(props, field, columnIndex) {
return <InputText type="text" value={props.rowData.year}
onKeyDown={(e) => this.onEditorKeyDown(e, columnIndex)} onChange={(e) => this.onEditorValueChange(props, e.target.value)} />;
}
Note that I've added onKeyDown handler and passed columnIndex arg to it so that we can recognize the column where some key is typed.
Step 3:
Finally we can define onEditorKeyDown to do the magic (check out code comments for additional explanations)
onEditorKeyDown(event, columnIndex) {
console.log("onKeyDown", event);
console.log("key code", event.keyCode);
console.log("columnIndex", columnIndex);
console.log("rowIndex", this.rowIndex);
//change following 2 constants to to fit your case
const columnCount = 4;
const rowCount = 10;
//check if TAB (key code is 9) is pressed on InputText
if (event.keyCode == 9) {
//prevent default behaviour on TAB press
event.preventDefault();
//this.dt is reference to DataTable element
//get reference to `table` node only
var table = this.dt.container.childNodes[1].childNodes[0].childNodes[1];
//check if we are not in last column
if (columnIndex < columnCount - 1) {
//simulate click on next column
table.childNodes[this.rowIndex].childNodes[columnIndex + 1].click();
} else {
//we are in the last column, check if we are not in last row
if (this.rowIndex < rowCount - 1) {
//we are not in the last row
// select next row
this.rowIndex += 1;
//simulate click on first column in next row
table.childNodes[this.rowIndex].childNodes[0].click();
}
}
}
}

Resources