I have a form in reactjs which has a normal variable called "name" and two arrays, one called "data1" and the other "data2", but when saving from reactjs it is only saving the variable "name" in base of data.
I need that they also save the arrangements in the database but I have not achieved it.
the mysql database only has one table called revenue2 and 4 fields: revenue_id, name, data1, data2
https://codesandbox.io/s/ecstatic-browser-nvcee?file=/src/App.js
import React, {useState} from 'react';
import axios from 'axios';
import {
Grid,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Paper
} from "#material-ui/core";
import AddCircleOutlineIcon from "#material-ui/icons/AddCircleOutline";
import { withStyles, makeStyles } from "#material-ui/core/styles";
import DeleteIcon from "#material-ui/icons/Delete";
const StyledTableRow = withStyles((theme) => ({
root: {
"&:nth-of-type(odd)": {
backgroundColor: theme.palette.action.hover
}
}
}))(TableRow);
const options = [
{ value: 1, label: 1 },
{ value: 2, label: 2 },
{ value: 3, label: 3 }
];
function Pruebas() {
const baseUrlAd = 'https://www.inventarios.gemcont.com/apiGemcont/compras/ingresos/';
const [data, setData]=useState([]);
const [frameworkSeleccionado, setFrameworkSeleccionado]=useState({
id_ingreso:'',
nombre:'',
dato1:'',
dato2:''
});
const handleChange=e=>{
const {name, value}=e.target;
setFrameworkSeleccionado((prevState)=>({
...prevState,
[name]: value
}))
console.log(frameworkSeleccionado);
}
const peticionPost = async() =>{
var f = new FormData();
f.append("nombre", frameworkSeleccionado.nombre);
f.append("dato1", frameworkSeleccionado.dato1);
f.append("dato2", frameworkSeleccionado.dato2);
f.append("METHOD", "POST_prueba");
await axios.post(baseUrlAd,f)
.then(response=>{
setData(data.concat(response.data));
}).catch(error=>{
console.log(error);
})
}
const [roomInputs, setRoomInputs] = useState([
{ dato1: "", dato2: "" }
]);
const handleRoomChange = (value, index, name) => {
const list = [...roomInputs ];
list[index][name] = value;
setRoomInputs(list);
};
const handleRemoveClickRoom = (index) => {
const list = [...roomInputs];
list.splice(index, 1);
setRoomInputs(list);
};
const handleAddClickRoom = () => {
setRoomInputs([...roomInputs, { dato1: "", dato2: "" }]);
};
return (
<div className="content-wrapper">
<div className="content-header">
<div className="container-fluid">
<div className="col-sm-12">
<div class="card">
<div class="card-header">
<h3 class="card-title">Datos</h3>
</div>
<div class="card-body">
<div class="row">
<div class="col-sm-4">
<div class="input-group">
<input type="text" name="nombre"
placeholder='nombre' className="form-control" onChange={handleChange}/>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<br />
<Grid item sm={12}>
<TableContainer component={Paper} variant="outlined">
<Table aria-label="customized table">
<TableHead>
<TableRow>
<TableCell>#</TableCell>
<TableCell align="left">dato1</TableCell>
<TableCell align="left">dato2</TableCell>
</TableRow>
</TableHead>
<TableBody>
{roomInputs.map((x, i) => (
<StyledTableRow key={i}>
<TableCell component="th" scope="row">
{i + 1}
</TableCell>
<TableCell align="left">
<input
type="text"
className="form-control"
name="dato1"
value={options.value}
//onChange={option => handleRoomChange(option, i, "dato1")}
onChange={event => handleRoomChange(event.target.value, i, "dato1")}
/>
</TableCell>
<TableCell align="left">
<input
type="number"
name="dato2"
className="form-control"
value={options.value}
//onChange={option => handleRoomChange(option, i, "dato2")}
onChange={event => handleRoomChange(event.target.value, i, "dato2")}
/>
</TableCell>
<TableCell align="left">
{roomInputs.length !== 1 && (
<DeleteIcon
onClick={() => handleRemoveClickRoom(i)}
style={{
marginRight: "10px",
marginTop: "4px",
cursor: "pointer"
}}
/>
)}
{roomInputs.length - 1 === i && (
<AddCircleOutlineIcon
onClick={handleAddClickRoom}
style={{ marginTop: "4px", cursor: "pointer" }}
/>
)}
</TableCell>
</StyledTableRow>
))}
</TableBody>
</Table>
</TableContainer>
</Grid>
</div>
</div>
<br />
<button className="btn btn-primary" onClick={()=>peticionPost()}> Registrar</button>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
export default Pruebas
php
<?php
include '../../bd/global.php';
header('Access-Control-Allow-Origin: *');
if($_POST['METHOD']=='POST_prueba'){
unset($_POST['METHOD']);
$nombre=$_POST['nombre'];
$dato1=$_POST['dato1'];
$dato2=$_POST['dato2'];
$query="insert into ingresos2(nombre,dato1,dato2) values ('$nombre','$dato1','$dato2')";
$queryAutoIncrement="select MAX(id_ingreso) as id_ingreso from ingresos2";
$resultado=metodoPost($query, $queryAutoIncrement);
echo json_encode($resultado);
header("HTTP/1.1 200 OK");
exit();
}
header("HTTP/1.1 400 Bad Request");
?>
Refactor handleChangeRoom as below
const handleRoomChange = (value, index, name) => {
setFrameworkSeleccionado((prevState) => ({
...prevState,
[name]: value
}));
};
Demo - https://codesandbox.io/s/happy-sara-or05xx?file=/src/App.js:2167-2326
Related
I have a form in reactjs that saves a variable "name" and two dynamic arrays, one is called "data1" and "data2", each array can contain several values since I can add more dynamic values from reactjs to there, but not I have been able to pass those values of the array that are saved in mysql from the php since it only saves the name and the first two data of the array of data1 and data2:
https://codesandbox.io/s/ecstatic-browser-nvcee?file=/src/App.js:0-8794
I need to be able to save the complete arrays "data1" and data2 in the database.
reactjs
import React, {useState} from 'react';
import axios from 'axios';
import {
Grid,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Paper
} from "#material-ui/core";
import AddCircleOutlineIcon from "#material-ui/icons/AddCircleOutline";
import { withStyles, makeStyles } from "#material-ui/core/styles";
import DeleteIcon from "#material-ui/icons/Delete";
const StyledTableRow = withStyles((theme) => ({
root: {
"&:nth-of-type(odd)": {
backgroundColor: theme.palette.action.hover
}
}
}))(TableRow);
/*const useStyles = makeStyles((theme) => ({
paper: {
display: "flex",
flexDirection: "column",
padding: "30px 40px",
marginTop: "50px",
marginLeft: "20px",
marginRight: "20px"
},
heading: {
paddingLeft: "10px"
},
label: {
lineHeight: "2",
fontSize: "14px"
},
input: {
height: "10px"
},
table: {
minWidth: 700
}
}));*/
const options = [
{ value: 1, label: 1 },
{ value: 2, label: 2 },
{ value: 3, label: 3 }
];
function Pruebas() {
const baseUrlAd = 'https://www.inventarios.gemcont.com/apiGemcont/compras/ingresos/index2.php';
const [data, setData]=useState([]);
const [frameworkSeleccionado, setFrameworkSeleccionado]=useState({
id_ingreso:'',
nombre:'',
dato1:'',
dato2:''
});
const handleChange=e=>{
const {name, value}=e.target;
setFrameworkSeleccionado((prevState)=>({
...prevState,
[name]: value
}))
console.log(frameworkSeleccionado);
}
/*const peticionPost = async() =>{
var f = new FormData();
f.append("nombre", frameworkSeleccionado.nombre);
f.append("dato1", frameworkSeleccionado.dato1);
f.append("dato2", frameworkSeleccionado.dato2);
f.append("METHOD", "POST_prueba");
await axios.post(baseUrlAd,f)
.then(response=>{
setData(data.concat(response.data));
}).catch(error=>{
console.log(error);
})
}*/
const peticionPost = async () => {
var f = new FormData();
f.append("nombre", frameworkSeleccionado.nombre);
/* Los datos están en la matriz bidimensional "roomInputs" */
/* f.append("dato1", roomInputs[0].dato1);
f.append("dato2", roomInputs[0].dato2);*/
f.append("data", JSON.stringify(roomInputs));
f.append("METHOD", "POST_prueba");
await axios
.post(baseUrlAd, f)
.then((response) => {
setData(data.concat(response.data));
})
.catch((error) => {
console.log(error);
});
};
//const classes = useStyles();
const [roomInputs, setRoomInputs] = useState([
{ dato1: "", dato2: "" }
]);
/*const handleRoomChange = (option, index, name) => {
const value = option.value;
console.log(value);
const list = [...roomInputs];
list[index][name] = value;
setRoomInputs(list);
};*/
/*const handleRoomChange = (value, index, name) => {
const list = [...roomInputs ];
list[index][name] = value;
setRoomInputs(list);
};*/
/*const handleRoomChange = (value, index, name) => {
setFrameworkSeleccionado((prevState) => ({
...prevState,
[name]: value
}));
};*/
const handleRoomChange = (value, index, name) => {
const list = [...roomInputs ];
list[index][name] = value;
setRoomInputs(list);
};
const handleRemoveClickRoom = (index) => {
const list = [...roomInputs];
list.splice(index, 1);
setRoomInputs(list);
};
const handleAddClickRoom = () => {
setRoomInputs([...roomInputs, { dato1: "", dato2: "" }]);
};
return (
<div className="content-wrapper">
<div className="content-header">
<div className="container-fluid">
<div className="col-sm-12">
<div class="card">
<div class="card-header">
<h3 class="card-title">Datos</h3>
</div>
<div class="card-body">
<div class="row">
<div class="col-sm-4">
<div class="input-group">
<input type="text" name="nombre"
placeholder='nombre' className="form-control" onChange={handleChange}/>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<br />
<Grid item sm={12}>
<TableContainer component={Paper} variant="outlined">
<Table aria-label="customized table">
<TableHead>
<TableRow>
<TableCell>#</TableCell>
<TableCell align="left">dato1</TableCell>
<TableCell align="left">dato2</TableCell>
</TableRow>
</TableHead>
<TableBody>
{roomInputs.map((x, i) => (
<StyledTableRow key={i}>
<TableCell component="th" scope="row">
{i + 1}
</TableCell>
<TableCell align="left">
<input
type="text"
className="form-control"
name="dato1"
value={options.value}
//onChange={option => handleRoomChange(option, i, "dato1")}
onChange={event => handleRoomChange(event.target.value, i, "dato1")}
/>
</TableCell>
<TableCell align="left">
<input
type="number"
name="dato2"
className="form-control"
value={options.value}
//onChange={option => handleRoomChange(option, i, "dato2")}
onChange={event => handleRoomChange(event.target.value, i, "dato2")}
/>
</TableCell>
<TableCell align="left">
{roomInputs.length !== 1 && (
<DeleteIcon
onClick={() => handleRemoveClickRoom(i)}
style={{
marginRight: "10px",
marginTop: "4px",
cursor: "pointer"
}}
/>
)}
{roomInputs.length - 1 === i && (
<AddCircleOutlineIcon
onClick={handleAddClickRoom}
style={{ marginTop: "4px", cursor: "pointer" }}
/>
)}
</TableCell>
</StyledTableRow>
))}
</TableBody>
</Table>
</TableContainer>
</Grid>
</div>
</div>
<br />
<button className="btn btn-primary" onClick={()=>peticionPost()}> Registrar</button>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
export default Pruebas
php - failed attempts
<?php
include '../../bd/global.php';
header('Access-Control-Allow-Origin: *');
//tried 1
if($_POST['METHOD']=='POST_prueba'){
unset($_POST['METHOD']);
$nombre=$_POST['nombre'];
$dato1=$_POST['dato1'];
$dato2=$_POST['dato2'];
$query="insert into ingresos2(nombre,dato1,dato2) values ('$nombre','$dato1','$dato2')";
$queryAutoIncrement="select MAX(id_ingreso) as id_ingreso from ingresos2";
$resultado=metodoPost($query, $queryAutoIncrement);
echo json_encode($resultado);
header("HTTP/1.1 200 OK");
exit();
}
//tried 2
if($_POST['METHOD']=='POST_prueba'){
unset($_POST['METHOD']);
$nombre=$_POST['nombre'];
$data=json_decode($_POST['data']);
foreach ($data as $row) {
$dato1=$row['dato1'];
$dato2=$row['dato2'];
//aqui debes hacer cada inserción en base de datos
}
$query="insert into ingresos2(nombre,dato1,dato2) values ('$nombre','$dato1','$dato2')";
$queryAutoIncrement="select MAX(id_ingreso) as id_ingreso from ingresos2";
$resultado=metodoPost($query, $queryAutoIncrement);
echo json_encode($resultado);
header("HTTP/1.1 200 OK");
exit();
}
//tried 3
if($_POST['METHOD']=='POST_prueba'){
unset($_POST['METHOD']);
$nombre=$_POST['nombre'];
$query="insert into ingresos(nombre) values ('$nombre')";
$queryAutoIncrement="select MAX(id_ingreso) as id_ingreso from ingresos";
$resultado=metodoPost($query, $queryAutoIncrement);
echo json_encode($resultado);
$num_elementos=0;
$sw=true;
while ($num_elementos < count($id_detalle))
{
$sql_detalle = "INSERT INTO detalle_ingresos(id_ingreso, dato1, dato2) VALUES ('$idingresonew', '$idarticulo[$num_elementos]','$dato1[$num_elementos]','$dato2[$num_elementos]')";
ejecutarConsulta($sql_detalle) or $sw = false;
$num_elementos=$num_elementos + 1;
}
return $sw;
header("HTTP/1.1 200 OK");
exit();
}
header("HTTP/1.1 400 Bad Request");
?>
mysql
try to do 'json_encode' before putting the array into the base
example :
$array = [1,2,3,4,5];
$array = json_encode($array);
if the data does not fit into the database, change the field from 'varchar' to 'json' , then everything will work
your php sript won't work, it has a lot of errors
This line of your code:
$query="insert into ingresos2(nombre,dato1,dato2) values ('$nombre','$dato1','$dato2')";
should look like this:
$query="INSERT iNTO ingresos2 (nombre,dato1,dato2) values ($nombre,$dato1,$dato2)";
and in all other inserts the same way (if it's easy to explain)
ideally you should bind your parameters before Insert here is an example :
$this->db->openPdo();
$update = "INSERT INTO imported_error_logs (product_id,errors)
VALUES(:productId,:error)";
$sql = $this->db->pdo->prepare($update);
$sql->execute([
':error' => $error,
':productId' => $productId,
]);
Can anyone help me? I have created a table with checkbox. but I keep losing the table header name because it was being replaced by the checkbox. The first column with checkbox should be Notify Me and the other is Email Me. How can I put those header names together with the checkbox? here is the code that I have created:
<template>
<Modal #close="doClose">
<template v-slot:container>
<section class="card settings-vue-modal-container">
<header class="card-header">
<h2>Settings</h2>
<!-- <span class="custom-close fa fa-times" #click="doClose"></span> -->
</header>
<div class="card-body">
<div class='table-design'>
<SimpleDatatable
:init_data="tableData"
:init_columns="columns"
:init_is_loading="isTableLoading"
:isColumnCustomizable="false"
:isBoredered="true"
:isTableHeaderSticky="true"
:removeBorderWrapper="true"
:showTotalResult="false"
tableContentClass="users-table-content"
#changePage="changePage"
#getTableData="setTableData"
#getSelectedData="getSelectedData"
>
</SimpleDatatable>
</div>
</div>
<footer class="card-footer">
<div class="btn-group ml-auto float-right">
<button type="button" class="btn btn-secondary btn-close" #click="doClose">Close</button>
</div>
</footer>
</section>
</template>
</Modal>
</template>
<script>
import Modal from "../Reusable/Modal"
import SimpleDatatable from '../Others/SimpleDatatable';
export default {
components: {
Modal,
SimpleDatatable
},
data() {
return {
settingsData: [],
isTableLoading: false,
params: {
page: this.currentPage,
page_limit: 10,
search: '',
role: ''
},
columns: [
{
label: 'Task Schedule',
field: 'name',
align: 'center',
default: true
},
{
label: 'Notify Me',
type: 'checkbox',
align: 'center',
width: 200
},
{
label: 'Email Me',
type: 'checkbox',
align: 'center',
width: 200
}
],
tableData: {},
currentPage: 1,
selectedData: [],
requiredData: {},
errors: {},
name: '',
};
},
created() {
this.getTableData()
},
watch: {
currentPage(newValue, oldValue) {
this.params.page = newValue
this.getTableData()
}
},
methods: {
doClose() {
this.errors = {};
this.name = '';
this.$emit('close');
},
changePage(event) {
this.currentPage = event
},
setTableData(data) {
this.tableData = data
},
getSelectedData(data) {
this.selectedData = data.map(x => x.id)
},
getTableData() {
this.isTableLoading = true
let url = '/tasks/api/getAll'
axios
.post(url, this.params)
.then(response => {
this.setTableData(response.data)
this.isTableLoading = false
})
.catch(errors => {
this.isTableLoading = false
console.log(errors)
})
},
}
}
</script>
Thank you. Below is also the SimpleDatatable being used:
<template>
<div class="row">
<SeeMore
:content="this.seeMoreContent"
v-show="seeMoreModalVisibility"
#close="seeMoreModalVisibility=false"
/>
<div class="col-lg-12">
<CustomizeColumnModal
v-show="showColumnModal"
#close="showColumnModal = false"
:columns="init_columns"
#getCols="getColumn"
/>
</div>
<div class="col-lg-12">
<div
class="panel panel-default"
style="margin-bottom: 0"
:class="{ 'no-border': removeBorderWrapper }"
>
<div
class="panel-body"
style="margin-bottom: 0"
:class="{ 'no-border': removeBorderWrapper }"
>
<loading :active.sync="isLoading" :is-full-page="fullPage" style="z-index: 3;"></loading>
<div class="pull-left">
<slot name="functional_upper_left"></slot>
<b
class="ml-3"
v-if="data.total && showTotalResult && totalResultPosition === 'upperLeft' "
>Total Result: {{data.total | addComma }}</b>
</div>
<button
class="btn btn-lg btn-primary pull-right"
v-if="isColumnCustomizable"
#click="showColumnModal = true"
style="margin-bottom: 15px;"
>
<span class="fa fa-list" style=" margin-right: 5px;"></span> Columns
</button>
<slot name="functional_buttons"></slot>
<div class="table table-responsive" style="overflow: auto; max-height: 550px;">
<table
class="table table-hover table-striped"
:class="{ 'table-bordered': isBoredered }"
style="margin-bottom: 0"
>
<thead>
<tr>
<th
v-for="(col, index) in columns"
:class="{'amzentrix-th-sticky' : isTableHeaderSticky, 'with-select-dropdown': col.type === 'checkbox' && isSelectOptions }"
:key="index"
:style="{ minWidth: (col.width) ? `${col.width}px`: '100px', textAlign: (col.align) ? `${col.align}` : 'left' }"
>
<template v-if="col.type === 'checkbox'">
<div class="dropdown">
<input type="checkbox" #click="doSelectAll" v-model="isSelectAll" />
<a
class="dropdown-toggle"
id="dropdownSelectOptions"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
v-if="isSelectOptions"
/>
<div class="dropdown-menu" aria-labelledby="dropdownSelectOptions">
<span class="dropdown-item" #click="doSelectAllOnly">Select All</span>
<span class="dropdown-item" #click="doSelectTop(10)">Select Top 10</span>
<span class="dropdown-item" #click="doSelectTop(20)">Select Top 20</span>
</div>
</div>
</template>
<template v-else-if="col.sortable">
<div class="sortable_col" #click="sortCol(index)">
<span>{{ col.label }}</span>
<span class="sortable_icons">
<i class="fa fa-sort-up" :class="{ active: col.currentSort === 'ASC'}" />
<i
class="fa fa-sort-down"
:class="{ active: col.currentSort === 'DESC'}"
/>
</span>
</div>
</template>
<template v-else>{{ col.label }}</template>
</th>
</tr>
</thead>
<tbody v-if="data.total !== 0">
<template v-for="(row, index) in data.data">
<tr :key="index">
<td
v-for="(col, index) in columns"
:class="tableContentClass"
:style="{
textAlign: (col.align) ? `${col.align}` : 'left',
'vertical-align': (col.valign) ? col.valign : 'middle'
}"
:key="index"
>
<template v-if="col.type == 'checkbox' ">
<div class="vue-checkbox">
<input
type="checkbox"
:checked="row.selected"
#click="doSelect(row, $event)"
/>
</div>
</template>
<template v-else-if="col.type === 'action'">
<slot :name="`action-${row.id}`">
<slot name="action" :data="row" />
</slot>
</template>
<template v-else-if="col.type == 'date'">{{ timeHumanize(row[col.field]) }}</template>
<template
v-else-if="col.type == 'complete_date'"
>{{ completeDateFormat(row[col.field]) }}</template>
<template v-else-if="col.type == 'raw'">
<div v-html="row[col.field]"></div>
</template>
<template v-else-if="col.type == 'rounded_numbers'">
<div>{{ row[col.field] ? Number(row[col.field]).toFixed(4) : row[col.field] }}</div>
</template>
<template
v-else-if="col.type == 'status'"
>{{ row[col.field] ? 'Active': 'Inactive' }}</template>
<template v-else-if="col.type == 'more'">
<div v-if="row[col.field]">
<p v-html="seeMoreTexts(row[col.field].replace(/<\/?[^>]+(>|$)/g, ''))"></p>
<small
class="see-more"
#click="seeMore(row[col.field])"
v-if="row[col.field].length> 20"
>See More</small>
</div>
<p v-else>-</p>
<!-- {{ row[col.field] ? '<h1>awit</h1>' : '-' }} -->
</template>
<template v-else-if="col.type == 'field_value'">
<slot name="field_value" :data="row"></slot>
</template>
<template v-else>{{ row[col.field] ? row[col.field] : '-' }}</template>
</td>
</tr>
</template>
</tbody>
<tbody v-else>
<tr>
<td align="center" colspan="1000">
<slot name="no-result">
<span style="margin-right: 5px">No Data Found.</span>
</slot>
</td>
</tr>
</tbody>
</table>
</div>
<!-- PAGINATION -->
<nav v-if="data.total && data.total !== 0 && !data.single">
<ul class="pagination" :class="`float-${paginationPosition}`">
<li
class="page-item pagination-total-result px-3"
v-if="data.total && showTotalResult && totalResultPosition === 'bottomPaginationLeftSide'"
>
Total Result:
<b class="ml-2">{{data.total | addComma }}</b>
</li>
<slot name="pagination-left" />
<li class="page-item pr-3 page-limit-select" v-if="isCustomResultPerPage">
<label for="results-per-page">Results per page:</label>
<input
class="form-control"
id="results-per-page"
type="number"
min="1"
#change="handleChangeItemsPerPage"
v-model="page_limit"
/>
</li>
<li
class="page-item"
:class=" data.current_page <= 1 ? 'disabled' : '' "
#click=" changePage((data.current_page - 1))"
>
<a
class="page-link"
:href=" (data.current_page > 1) ? `#page-${data.current_page - 1}` : `#page-1`"
aria-label="Previous"
>
<span aria-hidden="true">«</span>
<span class="sr-only">Previous</span>
</a>
</li>
<li
class="page-item"
v-for="(n, index) in pagination(data.current_page, data.last_page)"
:class="(n === data.current_page) ? 'active' : ''"
:key="index"
#click="changePage(n)"
>
<a class="page-link" :href="(typeof n == 'number') ? `#page-${n}` : '#' ">{{ n }}</a>
</li>
<li
class="page-item"
:class=" data.current_page >= data.last_page ? 'disabled' : '' "
#click=" changePage((data.current_page + 1))"
>
<a
class="page-link"
:href=" (data.current_page < data.last_page) ? `#page-${data.current_page + 1}` : `#page-${data.last_page}`"
aria-label="Next"
>
<span aria-hidden="true">»</span>
<span class="sr-only">Next</span>
</a>
</li>
<slot name="pagination-right" />
</ul>
</nav>
</div>
</div>
</div>
</div>
</template>
<style scoped src='bootstrap/dist/css/bootstrap.min.css'></style>
<script>
import moment from "moment";
import CustomizeColumnModal from "./Datatable/CustomizeColumn";
import SeeMore from "./SimpleDatatableModal";
export default {
components: {
CustomizeColumnModal,
SeeMore
},
props: {
init_data: {
type: Object,
required: true
},
init_columns: {
type: Array,
required: true
},
init_is_loading: {
type: Boolean,
default: false
},
init_page_limit: {
type: Number,
default: 0
},
isSelectOptions: {
type: Boolean,
default: false
},
isColumnCustomizable: {
type: Boolean,
default: false
},
isBoredered: {
type: Boolean,
default: false
},
isTableHeaderSticky: {
type: Boolean,
default: false
},
isCustomResultPerPage: {
type: Boolean,
default: false
},
removeBorderWrapper: {
type: Boolean,
default: false
},
showTotalResult: {
type: Boolean,
default: false
},
totalResultPosition: {
type: String,
default: "upperLeft"
},
tableContentClass: {
type: String,
default: ""
},
paginationPosition: {
type: String,
default: "left"
}
},
data() {
return {
data: { total: 0 },
columns: this.init_columns,
isLoading: this.init_is_loading,
fullPage: false,
isSelectAll: false,
showColumnModal: false,
seeMoreContent: "",
seeMoreModalVisibility: false,
page_limit: this.init_page_limit
};
},
watch: {
init_data(newData, oldData) {
this.data = newData;
this.isSelectAll = false;
if (this.isSelectOptions) {
this.getSelectedData();
}
},
init_is_loading(newData, oldData) {
this.isLoading = newData;
if (this.isSelectOptions) {
this.checkSelectHeaderModel(); //Will reset isSelectAll State. Important if you're using checkbox and with dynamic data.
}
},
init_columns(newCols) {
this.columns = newCols;
},
init_page_limit(newData) {
this.page_limit = newData;
}
},
filters: {
addComma(value) {
return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
},
methods: {
resetSortColFields() {
const withSortColFields = this.columns.filter(col => col.currentSort);
const resetColFields = withSortColFields.map(col => {
col.currentSort = null;
return col;
});
},
//returns an object with sortType (eg. ASC or DESC ) and field (eg. DATE, ID)
sortCol(index) {
const { currentSort } = this.columns[index];
let sort = null;
this.resetSortColFields();
switch (currentSort) {
case "ASC":
sort = null;
break;
case "DESC":
sort = "ASC";
break;
default:
sort = "DESC";
}
this.columns[index].currentSort = sort;
this.$emit("sort", {
sortType: sort,
field: sort ? this.columns[index].field : null
});
},
doSelectAll(event) {
//single property for single set of data, means no paginated data.
//usually you want to use this if you're not using primarily the api of laravel's pagination.
//you just need to pass an initial object data with data and single properties
if (!this.data.total && !this.data.single) {
event.preventDefault();
return;
}
this.isSelectAll = !this.isSelectAll;
this.data.data.forEach(element => {
element.selected = this.isSelectAll;
});
if (!this.isSelectAll) this.$emit("getDeselectedData", this.data.data);
this.$emit("getTableData", this.data);
this.getSelectedData();
},
doSelectAllOnly() {
if (!this.isSelectAll) this.doSelectAll();
},
doSelectTop(num) {
this.data.data.forEach((element, index) => {
if (num > index) element.selected = true;
});
this.getSelectedData();
},
checkSelectHeaderModel() {
// to check if all data from the data is selected, if true, checkbox from header must be checked.
if (!this.data.data) return;
const newDataLength = this.data.data.length;
const newSelectedDataLength = this.data.data.filter(data => data.selected)
.length;
this.isSelectAll =
newDataLength && newDataLength === newSelectedDataLength ? true : false;
},
doSelect(row, event) {
let checked = Boolean(row.selected);
row.selected = !checked;
if (!row.selected) {
this.$emit("getDeselectedItem", row);
}
this.getSelectedData();
},
getSelectedData() {
const selected = this.data.data.filter(el => el.selected);
this.checkSelectHeaderModel();
this.$emit("getSelectedData", selected);
},
getColumn(event) {
if (this.isColumnCustomizable) {
this.columns = event;
this.$emit("getSelectedColumns", event);
}
},
timeHumanize(date) {
return moment(date).isValid() ? moment(date).fromNow() : date;
},
completeDateFormat(date) {
return moment(date).isValid()
? moment(date).format("MMM Do YYYY h:mm:ss a")
: date;
},
changePage(pageNumber) {
this.handleChangeItemsPerPage();
if (
pageNumber > 0 &&
pageNumber <= this.data.last_page &&
typeof pageNumber == "number" &&
this.data.current_page != pageNumber
)
this.$emit("changePage", pageNumber);
},
pagination(c, m) {
let current = c,
last = m,
delta = 3,
left = current - delta,
right = current + delta + 1,
range = [],
rangeWithDots = [],
l;
for (let i = 1; i <= last; i++) {
if (i == 1 || i == last || (i >= left && i < right)) {
range.push(i);
}
}
for (let i of range) {
if (l) {
if (i - l === 2) {
rangeWithDots.push(l + 1);
} else if (i - l !== 1) {
rangeWithDots.push("...");
}
}
rangeWithDots.push(i);
l = i;
}
return rangeWithDots;
},
seeMoreTexts(text) {
return text.length > 20 ? text.substring(0, 40) + "..." : text;
},
seeMore(data) {
this.seeMoreContent = data;
this.seeMoreModalVisibility = true;
},
handleChangeItemsPerPage(event) {
let value;
let changePage = false;
if (typeof event == "object") {
value = parseInt(event.target.value);
changePage = true;
} else {
value = parseInt(this.page_limit);
}
if (value <= 0 || typeof value != "number" || !value) {
value = 10;
this.page_limit = 10;
}
this.$emit("handleChangeItemsPerPage", parseInt(value), changePage);
}
},
mounted() {
//single property for single set of data, means no paginated data.
//usually you want to use this if you're not using primarily the api of laravel's pagination.
//you just need to pass an initial object data with data and single properties
this.data =
this.init_data.total || this.init_data.single
? this.init_data
: { total: 0 };
}
};
</script>
I am using vue.js and laravel 5.8.
In my commenting system like youtube,
I want to show user's profile image.
If user doesn't have a profile image, I want to show avatar.
I have many users, so I want to show multiple profile images based on id.
Now I got this error.
"TypeError: Cannot use 'in' operator to search for '' in
1571585278.jpg"
According to this console errors, I am fetching profile image (1571585278.jpg).
But I cannot show it, because 'in' operator is not available.
Also, I cannot show user's avatar. Though I used if method.
<div else class="user" >
<avatar :username="comment.user.name" :size="45"></avatar>
</div>
I am storing images in public/uploads.
How to fix Error in render: "TypeError: Cannot use 'in' operator to
search for '' in ?
user.php
protected $with = ['profile'];
comment.vue
<template>
<div>
<div class="reply-comment" >
<div class="user-comment">
<div class="user" v-if="comment.user.profile.image && comment.user.profile.image.length > 0">
<span :v-for="(item, index) in comment.user.profile.image">
<img :src="'/uploads/' + item.comment.user.profile.image">
</span>
</div>
<div else class="user" >
<avatar :username="comment.user.name" :size="45"></avatar>
</div>
<div class="user-name">
<span class="comment-name"><a :href=" '/user/' + 'profile' +'/'+ comment.user.id + '/' ">{{ comment.user.name }}</a></span>
<p>{{ comment.body }}</p>
</div>
</div>
</div>
<div class="reply">
<button #click="addingReply = !addingReply" class="reply-button" :class="{ 'red' : !addingReply, 'black' : addingReply }">
{{ addingReply ? 'Cancel' : 'Add Reply'}}
</button>
</div>
<div class="user-reply-area" v-if="addingReply">
<div class="reply-comment">
<div v-if="!auth">
<button #click="addReply" class="comment-button">Reply</button>
<input v-model='body' type="text">
</div>
</div>
</div>
<replies ref='replies' :comment="comment"></replies>
</div>
</template>
<script>
import Avatar from 'vue-avatar'
import Replies from './replies.vue'
export default {
components: {
Avatar,
Replies
},
data() {
return {
body: '',
addingReply: false,
auth: '',
item: '',
index: ''
}
},
props: {
comment: {
required: true,
default: () => ({})
},
post: {
required: true,
default: () => ({})
}
},
methods: {
addReply() {
if(! this.body) return
axios.post(`/comments/${this.post.id}`, {
comment_id: this.comment.id,
body: this.body
}).then(({data})=> {
this.body = ''
this.addingReply = false
this.$refs.replies.addReply(data)
})
.catch(function (error) {
console.log(error.response);
});
}
}
}
</script>
I'm in the beginning of learning laravel and vue-js, so this is rather difficult to me. I want to make a component in vue-js with a table, with sorting and pagination.
When I started the project I only used Laravel and jquery, so now I'm turning to vue js and it's getting complicated. What I have is this:
In my index.blade.php
#extends('layouts.dashboard')
#section('content')
<div class="container">
<div class="row">
<div class="col">
<table class="table">
<thead>
<tr>
<th> #sortablelink('first_name','First name') </th>
<th> #sortablelink('last_name', 'Last name') </th>
<th> #sortablelink('email', 'E-mail address') </th>
<th> #sortablelink('created_at', 'Creation date') </th>
<th></th>
</tr>
</thead>
<tbody is="submissions"></tbody>
</table>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col">
{{ $submissions->appends(\Request::except('page'))->render() }}
<div class="total-submissions">
Total submissions:
{{ $submissions->firstItem() }}-{{ $submissions->lastItem() }} of {{ \App\Submission::count() }}
</div>
</div>
</div>
</div>
#stop
In my component Submissions.vue:
<template>
<tbody>
<tr v-for="submission in submissions" :key="submission.id">
<td> {{submission.first_name}}</td>
<td> {{submission.last_name}} </td>
<td> {{submission.email}} </td>
<td> {{submission.created_at}} </td>
<td>
<a class="btn btn-default btn-primary" id="btn-view"
:href="'/dashboard/submissions/' + submission.id">View</a>
<a class="btn btn-default btn-primary"
id="btn-delete"
:href="'/dashboard/submissions'"
#click.prevent="deleteSubmission(submission)">Delete</a>
<label class="switch">
<input class="slider-read" name="is_read"
v-model="submission.is_checked"
#change="updateCheckbox(submission)"
type="checkbox">
<span class="slider round"></span>
</label>
</td>
</tr>
</tbody>
</template>
<script>
import qs from 'qs';
import axios from 'axios';
export default {
data: function () {
return {
submissions: [],
}
},
beforeCreate() {
},
created() {
},
mounted() {
this.fetch();
},
methods: {
fetch: function () {
let loader = this.$loading.show();
var queryString = window.location.search;
if (queryString.charAt(0) === '?')
queryString = queryString.slice(1);
var args = window._.defaults(qs.parse(queryString), {
page: 1,
sort: 'id',
order: 'asc'
});
window.axios.get('/api/submissions?' + qs.stringify(args)).then((response) => {
loader.hide();
this.submissions = response.data.data
});
},
deleteSubmission(submission) {
this.$dialog.confirm("Are you sure you want to delete this record?", {
loader: true
})
.then((dialog) => {
axios.delete('api/submissions/' + submission.id)
.then((res) => {
this.fetch()
})
.catch((err) => console.error(err));
setTimeout(() => {
console.log('Delete action completed');
swal({
title: "Update Completed!",
text: "",
icon: "success",
});
dialog.close();
}, 1000);
})
.catch(() => {
console.log('Delete aborted');
});
},
updateCheckbox(submission)
{
this.$dialog.confirm("Are you sure?", {
loader: true
})
.then((dialog) => {
axios.put('/api/submissions/' + submission.id, submission,
)
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.log(error);
});
setTimeout(() => {
console.log('Action completed');
dialog.close();
swal({
title: "Update Completed!",
text: "",
icon: "success",
});
}, 0);
})
.catch(() => {
submission.is_checked === false ? submission.is_checked = true : submission.is_checked = false;
console.log('Aborted');
});
},
}
}
</script>
Now what I want to accomplish: Put everything in the component, but since I have php in the table to sort everything how can I do this in vue? I'm trying with bootstrap vue tables, but I'm not sure if I can display data like this. Thanks in advance.
I have a datatable that works great. However, on the last column I have a button which should do another query and then build a second datatable, based on these results.
As you can see on the following example, when I click on the button 'searchMom' in the first row, it should run a query based on john newman´s mother('mary newman') and put the results on the panel called "Mom".
But it´s not working.
Please see the image and the code below:
View: viewFamily.blade.php
<div class="row">
<div class="col-md-12" id="rowFamily01">
<div class="panel">
<div class="panel-heading">
<div class="box-tools pull-right">
<button type="button" class="btn btn-xs panel_expand"><i class="material-icons md-18">expand_less</i></button>
</div>
<div class="panel-title">Find a person</div>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-9">
<div class="form-group">
<label class="control-label" for="inputPersonSearch" >Search: </label>
<input id="inputPersonSearch" class="form-control" type="text" name="inputPersonSearch" form="formPerson">
</div>
</div>
<div class="col-md-3">
<div class="form-group">
<label class="control-label" for="btnPersonSearch" style="color: white;">Search:</label>
<button id="btnPersonSearch" class="form-control btn btn-success" type="submit" title="Search" form="formPerson">Search</button>
</div>
</div>
</div>
<div class="row" style="width:100%; margin-left: 0%;">
<div class="col-md-12 datatable" id="datatable-main">
</div>
</div>
</div>
</div>
</div>
</div>
routes: diego_routes.php
Route::group(['prefix' => 'diego', 'namespace' => 'Diego'], function () {
Route::get("/", "DiegoController#index")->name("index");
Route::get("viewFamily", "DiegoController#viewFamily")->name("viewFamily");
Route::post("searchPerson", "DiegoController#searchPerson")->name("searchPerson");
Route::get("searchMom/{mom}", "DiegoController#searchMom")->name("searchMom");
});
controller: DiegoController.php
public function searchMom($mom){
$input = $mom;
//dd($input);
//begining select query
$query = TD_CP_CIDADAO::where('CID_INT_ID_CIDADAO', '>=', "0");
if(!empty($input["filtro"])){
foreach($input["filtro"] as $k=>$v){
if(!empty($k) and !empty($v)){
//$searchValues = preg_split('/,/', $v, -1, PREG_SPLIT_NO_EMPTY);
$searchValues = array_map('trim', $v);
//dd($searchValues);
$query->where(function ($q) use ($searchValues) {
foreach ($searchValues as $value) {
$q->orWhere('CID_STR_DS_NOME', 'like', "%{$value}%");
}
});
}
}
}
//order data
if(!empty($input["order"]) and count($input["order"]) > 0)
{
foreach($input["order"] as $v){
$position = $v["column"];
$column = $input["columns"][$position]["data"];
$dir = !empty($v["dir"])? $v["dir"] : "asc";
$query->orderBy($column, $dir);
}
}
//other params...
$query->skip($input["start"])->take($input["length"]);
$json_data["data"] = $query->get()->toArray();
$json_data["recordsTotal"] = $query->count();
$json_data["recordsFiltered"] = $json_data["recordsTotal"];
$json_data["draw"] = $input["draw"];
return response()->json($json_data);
}
javascript: diego.js
$(document).on("click", ".btnMom", function(e){
e.preventDefault();
$("#newPanels").empty();
$("#newPanels").append(panelMom);
$("#datatable-mom").append(tableMom);
$("#datatable-mom").css("font-size", "12px");
if($.fn.dataTable.isDataTable('table#tbMom')){
$("table#tbMom").DataTable().destroy();
}
$.fn.dataTable.ext.errMode = 'throw';
var filtros = $(this).serializeArray().reduce(function(a, x) { a[x.name] = x.value; return a; }, {});
var options = {
serverSide: true,
processing: true,
retrieve: true,
ajax: {
dataSrc: 'data',
url : $(this).data("url"),
type: 'get',
async: false,
data: {filtro:filtros}
},
columns : columnsMom,
lengthMenu : [ 5, 10, 25 ]
};
$("table#tbMom").DataTable(options);
});
var columnsMom = [
{ data: 'CID_INT_ID_CIDADAO', visible:false},
{ data: 'CID_STR_DS_NOME'},
{ data: 'CID_DAT_DT_NASCIMENTO',
render: function(data, type, row){
return converterData(data);
}, className: "text-center"},
{ data: 'CID_STR_NM_MAE'},
{ data: 'CID_STR_NM_PAI'},
{ data: 'CID_INT_NR_RG', className: "text-center"},
{ data: 'CID_INT_NR_CPF', className: "text-center"},
{ data: 'acao',
render: function(data, type, row, meta){
var b0 = '\n\
\n\
';
return b0;
},orderable: false, className: "text-center"
}];
var panelMom =
`
<div class="panel" id="panelMom">
<div class="panel-heading">
<div class="box-tools pull-right">
<button type="button" class="btn btn-xs panel_expand"><i class="material-icons md-18">expand_less</i></button>
<button type="button" class="btn btn-xs panel_remove"><i class="material-icons md-18">close</i></button>
</div>
<div class="panel-title">Mom</div>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-12 datatable conteudod" id="datatable-mom">
</div>
</div>
</div>
</div>
`;
var tableMom =
`
<table id="tbMom" class="table table-hover compact" cellspacing="0" width="100%" >
<thead>
<tr>
<th class="hidden">ID</th>
<th>NAME</th>
<th>DOB</th>
<th>MOM</th>
<th>DAD</th>
<th class="text-center">DOC #</th>
<th class="text-center">FIELD #</th>
<th class="text-center">ACTION</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
</tfoot>
</table>
`;
The error message:
The line 219 (controller) shown in error message:
Results on "dd($input)" inside the controller:
I appreciate any help to solve this problem!
Thank you!
You're setting the value of $input to the value of $mom, which is the last value in your URL, so mom equals Mary Newman but the rest of your code expects $input to be an array of parameters like order, columns and start.
You should assign the value of $input as the request parameters, e.g:
public function searchMom($mom)
{
$input = request()->input();
}
Alternatively instead of $input being an array you could use the Request object directly, e.g:
public function searchMom(Request $request, $mom)
{
$request->order;
$request->columns;
$request->start;
}