How can I avoid this behavior in react-native? - javascript

I'm currently working on an input with mask in react-native, however I'd like to avoid input of non-numeric characters. I did, however I'd like to avoid the behavior below:
enter image description here
'use strict';
import React, { Component, PropTypes } from 'react';
import { styles, cleanStyle, dirtyStyle } from './styles';
import { colors } from '../../config/styles';
import {
Animated,
Easing,
Platform,
StyleSheet,
Text,
TextInput,
View,
Keyboard,
} from 'react-native';
const textPropTypes = Text.propTypes || View.propTypes;
const textInputPropTypes = TextInput.propTypes || textPropTypes;
const propTypes = {
...textInputPropTypes,
inputStyle: textInputPropTypes.style,
labelStyle: textPropTypes.style,
disabled: PropTypes.bool,
style: View.propTypes.style,
};
const SMInput = React.createClass({
propTypes,
getDefaultProps() {
return {
editable: true,
onlyNumbers: false,
underlineColorAndroid: 'transparent'
};
},
getInitialState() {
Keyboard.addListener('keyboardDidChangeFrame', () => {
console.log('keyboardDidChangeFrame');
});
const state = {
text: (this.props.value) ? this.props.value.toString() : '',
dirty: !!this.props.value,
borderColor: new Animated.Value(0),
labelColor: new Animated.Value(0),
maxLength: this.props.maxLength,
placeHolder: '',
};
const style = state.dirty ? dirtyStyle : cleanStyle;
state.labelStyle = {
fontSize: new Animated.Value(style.fontSize),
top: new Animated.Value(style.top),
position: new Animated.Value(style.position),
}
return state;
},
_animate(dirty) {
const animateTime = 150;
const nextStyle = dirty ? dirtyStyle : cleanStyle;
const labelStyle = this.state.labelStyle;
const anims = Object.keys(nextStyle).map(prop => {
return Animated.timing(
labelStyle[prop],
{
toValue: nextStyle[prop],
duration: animateTime,
},
Easing.ease
)
});
setTimeout(() => {
if (this.props.placeholder && dirty) {
this.setState({
placeHolder: this.props.placeholder
});
}
}, 120);
anims.push(
Animated.timing (
this.state.borderColor, {
toValue: dirty ? 1 : 0,
duration: animateTime,
}
)
);
anims.push(
Animated.timing (
this.state.labelColor, {
toValue: dirty ? 1 : 0,
duration: animateTime,
}
)
);
Animated.parallel(anims).start();
},
_onFocus() {
this._animate(true);
this.setState({ dirty: true });
if (this.props.onFocus) {
this.props.onFocus(arguments);
}
},
_onBlur() {
if (!this.state.text) {
this._animate(false);
this.setState({ dirty: false });
}
if (this.props.onBlur) {
this.props.onBlur(arguments);
}
if (this.props.placeholder) {
this.setState({
placeHolder: ''
});
}
},
onChangeText(text) {
this.setMask(text);
if (this.props.onChangeText) {
this.props.onChangeText(text);
}
},
setMask(text) {
//function mask(inputName, mask) {
var mask = '00/00/0000';
this.setState({
maxLength: mask.length
});
var value = text;
var literalPattern = /[0\*]/;
var numberPattern = /[0-9]/;
var newValue = '';
for (var vId = 0, mId = 0 ; mId < mask.length ; ) {
if (mId >= value.length) {
break;
}
// Number expected but got a different value, store only the valid portion
if (mask[mId] == '0' && value[vId].match(numberPattern) == null) {
break;
}
// Found a literal
while (mask[mId].match(literalPattern) == null) {
if (value[vId] == mask[mId]) {
break;
}
newValue += mask[mId++];
}
newValue += value[vId++];
mId++;
}
this.setState({
text: newValue
})
},
updateText(event) {
const text = event.nativeEvent.text;
this.setState({ text })
if (this.props.onEndEditing) {
this.props.onEndEditing(event);
}
},
_renderLabel() {
const labelColor = this.state.labelColor.interpolate({
inputRange: [ 0, 1 ],
outputRange: [ colors.darkPurple50, colors.purple100 ]
});
return (
<View style={ styles.wrapper }>
<Animated.Text
ref='label'
style={ [this.state.labelStyle, styles.label, this.props.labelStyle, { color: labelColor } ] }
>
{this.props.children}
</Animated.Text>
</View>
)
},
render() {
const borderColor = this.state.borderColor.interpolate({
inputRange: [ 0, 1 ],
outputRange: [ colors.gray80, colors.purple100 ]
});
const props = {
autoCapitalize: this.props.autoCapitalize,
autoCorrect: this.props.autoCorrect,
autoFocus: this.props.autoFocus,
bufferDelay: this.props.bufferDelay,
clearButtonMode: this.props.clearButtonMode,
clearTextOnFocus: this.props.clearTextOnFocus,
controlled: this.props.controlled,
editable: this.props.editable,
enablesReturnKeyAutomatically: this.props.enablesReturnKeyAutomatically,
keyboardType: this.props.keyboardType,
multiline: this.props.multiline,
onBlur: this._onBlur,
onChange: this.props.onChange,
onChangeText: this.onChangeText,
onEndEditing: this.updateText,
onFocus: this._onFocus,
onSubmitEditing: this.props.onSubmitEditing,
password: this.props.password,
returnKeyType: this.props.returnKeyType,
selectTextOnFocus: this.props.selectTextOnFocus,
selectionState: this.props.selectionState,
style: [styles.input],
maxLength: this.state.maxLength,
underlineColorAndroid: this.props.underlineColorAndroid, // android TextInput will show the default bottom border
onKeyPress: this.props.onKeyPress,
spellCheck: this.props.spellCheck,
mask: this.props.mask,
placeholder: this.state.placeHolder,
placeholderTextColor: colors.darkPurple50,
value: this.state.text,
};
const elementStyles = [styles.element];
if (this.props.inputStyle) {
props.style.push(this.props.inputStyle);
}
if (this.props.style) {
elementStyles.push(this.props.style);
}
if (!this.props.editable) {
elementStyles.push(styles.elementNotEditable);
props.style.push(styles.inputNotEditable);
}
return (
<Animated.View style={ [elementStyles, { borderColor: borderColor }] }>
{ this._renderLabel() }
<TextInput
{ ...props }
>
</TextInput>
</Animated.View>
);
},
});
SMInput.propTypes = {
disabled: PropTypes.bool,
style: Text.propTypes.style,
};
export default SMInput;

Related

How do you set filename for Webdatarocks default export

As the title suggests i cant for the life of me find a way to give the exported file a name except "Pivot"
The HTML/Vue part only has the Pivot and a select dropdown that filters by date and that works fine, it's only the export that i'm struggling with
<template>
<v-card>
<v-progress-linear
v-if="loading"
class="position-absolute"
style="z-index: 1"
color="red"
height="10"
indeterminate></v-progress-linear>
<v-card-title style="text-align:center"> Reports </v-card-title>
<v-card-text v-if="!loading">
<v-row>
<v-col cols="3" offset="1">
<v-select
v-model="selectedDate"
:items="reportdates"
label="Period:"
item-title="rd_date_label"
item-value="rd_date"
density="compact"
hide-details>
</v-select>
</v-col>
</v-row>
<br />
<v-row>
<Pivot id="pivotid"
ref="pivotref"
height="650px"
:report="report"
:toolbar="toolbar"
:beforetoolbarcreated="beforetoolbarcreated">
</Pivot>
</v-row>
</v-card-text>
</v-card>
</template>
Javascript part with my methods and data structure
<script>
import { mapGetters } from 'vuex'
import 'webdatarocks/webdatarocks.css'
import Pivot from "../../Common/Pivot.vue";
import '../../Common/webdatarocks.css';
export default {
name: 'Reports',
props: {
curDate: String,
},
components: {
Pivot
},
computed: {
...mapGetters (['reportdates', 'worktask']),
},
mounted() {
},
created() {
this.loadingData();
},
data() {
return {
isAdmin: null,
loading: false,
loaded: {
reportdates: false,
worktask: false,
},
selectedDate: null,
datachanged: null,
toolbar: true,
beforetoolbarcreated: this.customizeToolbar,
report: {
dataSource: {
data: [],
},
formats: [{
name: "hours",
maxDecimalPlaces: 2,
maxSymbols: 20,
textAlign: "right"
}],
slice: {
rows: [{
uniqueName: "Employee"
}
// ,{
// uniqueName: "Date"
// },
],
columns: [
{
uniqueName: "Client"
},
{
uniqueName: "[Measures]"
},],
measures: [{
uniqueName: "Hours",
aggregation: "sum",
format: "hours"
}]
},
options: {
grid: {
type: "compact",
title: "",
showFilter: true,
showHeaders: true,
showTotals: true,
showGrandTotals: "on",
showHierarchies: true,
showHierarchyCaptions: true,
showReportFiltersArea: true
},
configuratorActive: false,
configuratorButton: true,
showAggregations: true,
showCalculatedValuesButton: true,
drillThrough: true,
showDrillThroughConfigurator: true,
sorting: "on",
datePattern: "dd/MM/yyyy",
dateTimePattern: "dd/MM/yyyy HH:mm:ss",
saveAllFormats: false,
showDefaultSlice: true,
defaultHierarchySortName: "asc",
},
}
}
},
watch: {
reportdates() {
this.loaded.reportdates = true;
let fdate = this.reportdates.find(r => r.rd_date_label === this.curDate);
this.selectedDate = fdate.rd_date;
this.checkLoading();
},
worktask() {
this.loaded.worktask = true;
this.checkLoading();
//console.log('worktask: ' + this.worktask.length);
this.report.dataSource.data = this.getJSONData();
},
async selectedDate() {
//console.log('selectedDate: ' + this.selectedDate);
let fdate = this.reportdates.find(r => r.rd_date_label === this.curDate);
let tUserEmail = window.Laravel.user.email;
let tUserId = window.Laravel.user.id;
if(window.Laravel.user.role === "USR"){
if (fdate.rd_date == this.selectedDate) {
this.report.dataSource.data = [];
this.$store.dispatch('fetchWorkTaskReportDataUser', { rdate : this.selectedDate, tUserEmail : tUserEmail, });
} else {
let dstr = new Date(this.selectedDate).toISOString().slice(0, 7);
const params = Object.assign({}, this.$route.params);
params.curDate = dstr;
await this.$router.push({ params });
this.$router.go();
}
}else{
if (fdate.rd_date == this.selectedDate) {
this.report.dataSource.data = [];
this.$store.dispatch('fetchWorkTaskReportData', { rdate : this.selectedDate, tUserEmail : tUserEmail, });
} else {
let dstr = new Date(this.selectedDate).toISOString().slice(0, 7);
const params = Object.assign({}, this.$route.params);
params.curDate = dstr;
await this.$router.push({ params });
this.$router.go();
}
}
// if (fdate.rd_date == this.selectedDate) {
// this.report.dataSource.data = [];
// this.$store.dispatch('fetchWorkTaskReportDataUser', { rdate : this.selectedDate, tUserEmail : tUserEmail, });
// } else {
// let dstr = new Date(this.selectedDate).toISOString().slice(0, 7);
// const params = Object.assign({}, this.$route.params);
// params.curDate = dstr;
// await this.$router.push({ params });
// this.$router.go();
// }
}
},
methods: {
loadingData() {
this.loading = true;
// let tUserId = window.Laravel.user.id;
// if(window.Laravel.user.role === "ADM"){
// console.log("Admin");
// this.$store.dispatch('fetchReportDates',{
// tUserId : tUserId,
// });
// }else{
// console.log("User");
// this.$store.dispatch('fetchReportDatesUser',{
// tUserId : tUserId,
// })}
this.$store.dispatch('fetchReportDates',{
// tUserId : tUserId,
})
},
checkLoading() {
this.loading = !(this.loaded.reportdates && this.loaded.worktask);
},
getText(item) {
return item;
},
customizeToolbar(toolbar) {
var tabs = toolbar.getTabs();
toolbar.getTabs = function() {
delete tabs[0];
delete tabs[1];
delete tabs[2];
delete tabs[7];
return tabs;
}
},
getJSONData() {
return this.worktask
for(let r=0; r < this.worktask.length; r++){
returns.push(this.worktask[r]);
}
return returns;
},
},
}
This can be done by customizing the default tabs from the Toolbar and using the exporTo() API call. For example, here's how you can change the name of the exported PDF file:
function customizeToolbar(toolbar) {
// get all tabs
let tabs = toolbar.getTabs();
toolbar.getTabs = function() {
let exportTab = tabs.find(tab => tab.id == "wdr-tab-export");
if (!exportTab) return tabs;
let exportToPdfTab = exportTab.menu.find(tab => tab.id == "wdr-tab-export-pdf");
exportToPdfTab.handler = () => {
this.pivot.exportTo("pdf", {
filename: "custom-name" // set the necessary name
});
}
return tabs;
}
}
Please check the following CodePen: https://codepen.io/webdatarocks/pen/QWxYLRy?editors=1010

How to get the updated value of a particular cell in Data Grid of Material UI

When I updated the cell in the data grid, I was only able to retrieve the ID and field through the prop selectedCellParams here but I could not get its modified value.
I want to get the selected value inside the handleSaveOrEdit() function in order to accomplish the PUT request to update the API. How to use the getValue as given in the MUI Docs.
The entire code is below;
import * as React from 'react';
import PropTypes from 'prop-types';
import { Typography, Grid } from "#mui/material";
import Box from '#mui/material/Box';
import Button from '#mui/material/Button';
import { DataGrid, GridCellModes } from '#mui/x-data-grid';
import { styled } from '#mui/material/styles';
import { useState, useEffect } from "react";
import Avatar from "#mui/material/Avatar";
import axios from 'axios';
const DrawerHeader = styled('div')(({ theme }) => ({
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
padding: theme.spacing(0, 1),
...theme.mixins.toolbar,
}));
function EditToolbar(props) {
const { selectedCellParams, cellMode, cellModesModel, setCellModesModel } = props;
const handleSaveOrEdit = () => {
if (!selectedCellParams) {
return;
}
const { id, field } = selectedCellParams;
if (cellMode === 'edit') {
setCellModesModel({
...cellModesModel,
[id]: { ...cellModesModel[id], [field]: { mode: GridCellModes.View } },
});
const getValue = (params) => console.log(params.value);
console.log('value:::', getValue);
} else {
setCellModesModel({
...cellModesModel,
[id]: { ...cellModesModel[id], [field]: { mode: GridCellModes.Edit } },
});
}
};
const handleCancel = () => {
if (!selectedCellParams) {
return;
}
const { id, field } = selectedCellParams;
setCellModesModel({
...cellModesModel,
[id]: {
...cellModesModel[id],
[field]: { mode: GridCellModes.View, ignoreModifications: true },
},
});
};
const handleMouseDown = (event) => {
// Keep the focus in the cell
event.preventDefault();
};
return (
<Box
sx={{
borderBottom: 1,
borderColor: 'divider',
p: 1,
}}
>
<Button
onClick={handleSaveOrEdit}
onMouseDown={handleMouseDown}
disabled={!selectedCellParams}
color="primary"
variant="outlined"
>
{cellMode === 'edit' ? 'Save' : 'Edit'}
</Button>
<Button
onClick={handleCancel}
onMouseDown={handleMouseDown}
disabled={cellMode === 'view'}
color="primary"
variant="outlined"
sx={{ ml: 1 }}
>
Cancel
</Button>
</Box>
);
}
EditToolbar.propTypes = {
cellMode: PropTypes.oneOf(['edit', 'view']).isRequired,
cellModesModel: PropTypes.object.isRequired,
selectedCellParams: PropTypes.shape({
field: PropTypes.string.isRequired,
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
}),
setCellModesModel: PropTypes.func.isRequired,
};
export default function Donees() {
const [selectedCellParams, setSelectedCellParams] = React.useState(null);
const [cellModesModel, setCellModesModel] = React.useState({});
const [tableData, setTableData] = useState([])
const [fname, setFname] = useState("");
const [lname, setLname] = useState("");
const [address, setAddress] = useState("");
const [dob, setDob] = useState("");
const [gender, setGender] = useState("");
const [email, setEmail] = useState("");
const [phone, setPhone] = useState("");
const [grade, setGrade] = useState("");
const [photo, setPhoto] = useState("");
useEffect(() => {
fetch("http://localhost:4000/donees")
.then((data) => data.json())
.then((data) => setTableData(data))
}, [])
useEffect(() => {
axios.get("http://localhost:4000/donees")
.then((response) => {
setFname(response.data.fname);
setLname(response.data.lname);
setAddress(response.data.address);
setDob(response.data.dob);
setGender(response.data.gender);
setEmail(response.data.email);
setPhone(response.data.phone);
setGrade(response.data.grade);
setPhoto(response.data.photo);
})
}, [])
// console.log(tableData);
const handleCellFocus = React.useCallback((event) => {
const row = event.currentTarget.parentElement;
const id = row.dataset.id;
const field = event.currentTarget.dataset.field;
setSelectedCellParams({ id, field });
}, []);
const cellMode = React.useMemo(() => {
if (!selectedCellParams) {
return 'view';
}
const { id, field } = selectedCellParams;
return cellModesModel[id]?.[field]?.mode || 'view';
}, [cellModesModel, selectedCellParams]);
const handleCellKeyDown = React.useCallback(
(params, event) => {
if (cellMode === 'edit') {
// Prevents calling event.preventDefault() if Tab is pressed on a cell in edit mode
event.defaultMuiPrevented = true;
}
},
[cellMode],
);
return (
<Box component="main">
<DrawerHeader />
<Typography sx={{ textAlign: "center", pt: 5 }} variant="h5">Donees Table</Typography>
<Grid container spacing={3} sx={{ pl: 15, pr: 15, pt: 5 }}>
<div style={{ height: 400, width: '100%' }}>
<DataGrid
rows={tableData}
columns={columns}
getRowId={(row) => row._id}
onCellKeyDown={handleCellKeyDown}
cellModesModel={cellModesModel}
components={{
Toolbar: EditToolbar,
}}
componentsProps={{
toolbar: {
cellMode,
selectedCellParams,
setSelectedCellParams,
cellModesModel,
setCellModesModel,
},
cell: {
onFocus: handleCellFocus,
},
}}
experimentalFeatures={{ newEditingApi: true }}
/>
</div>
</Grid>
</Box>
);
}
const columns = [
{ field: 'fname', headerName: 'First Name', width: 140, editable: true },
{ field: 'lname', headerName: 'Last Name', width: 140, editable: true },
{ field: 'address', headerName: 'Address', width: 200, editable: true },
{ field: 'dob', headerName: 'Date of Birth', width: 140, editable: true },
{ field: 'gender', headerName: 'Gender', width: 100, editable: true },
{ field: 'email', headerName: 'Email ID', width: 140, editable: true },
{ field: 'phone', headerName: 'Mobile Number', type: 'number', width: 140, editable: true },
{ field: 'grade', headerName: 'Grade', width: 180, editable: true },
{
field: 'photo', headerName: 'Photo', width: 180, editable: true, renderCell: (params) => {
// console.log(params);
return (
<>
<Avatar src={params.value} />
</>
);
}
},
];
add following to dataGrid
<DataGrid
processRowUpdate={processRowUpdate}
/>
add
const processRowUpdate = (newRow: any) => {
const updatedRow = { ...newRow, isNew: false };
console.log(updatedRow);
//handle send data to api
return updatedRow;
};

Read and save WP post meta field data from Gutenberg block

I used the code from this article as an example.
It is possible to read the data, but not to save it.
Code:
const { Component, Fragment } = wp.element;
const {
RichText,
InspectorControls,
PanelColorSettings,
AlignmentToolbar,
BlockControls,
} = wp.editor;
const { Button, PanelBody, SelectControl, TextControl } = wp.components;
const { __ } = wp.i18n;
const { registerBlockType } = wp.blocks;
const { withSelect, withDispatch } = wp.data;
class Inspector extends Component {
constructor(props) {
super(...arguments);
}
render() {
const backgroundColors = [
{ color: "#525252", name: "Черный" },
{ color: "#872d2d", name: "Акцентный красный" },
{ color: "#e49312", name: "Акцентный желтый" },
{ color: "#bab3a6", name: "Акцентный кремовый" },
];
const fontSizeOptions = [
{ value: "14px", label: __("14px") },
{ value: "16px", label: __("16px") },
{ value: "18px", label: __("18px") },
{ value: "22px", label: __("22px") },
{ value: "28px", label: __("28px") },
];
const paddingTopOptions = [
{ value: "0px", label: __("0px") },
{ value: "10px", label: __("10px") },
{ value: "25px", label: __("25px") },
{ value: "50px", label: __("50px") },
];
const paddingBottomOptions = [
{ value: "0px", label: __("0px") },
{ value: "10px", label: __("10px") },
{ value: "25px", label: __("25px") },
{ value: "50px", label: __("50px") },
];
const {
setAttributes,
attributes: { text_color, font_size, padding_top, padding_bottom },
} = this.props;
let PluginMetaFields = (props) => {
return (
<>
<TextControl
value={props.text_metafield}
label={__("Text Meta", "textdomain")}
onChange={(value) => props.onMetaFieldChange(value)}
/>
</>
);
};
PluginMetaFields = withSelect((select) => {
return {
text_metafield: select("core/editor").getEditedPostAttribute("meta")[
"_myprefix_text_metafield"
],
};
})(PluginMetaFields);
PluginMetaFields = withDispatch((dispatch) => {
return {
onMetaFieldChange: (value) => {
dispatch("core/editor").editPost({
meta: { _myprefix_text_metafield: value },
});
},
};
})(PluginMetaFields);
return (
<InspectorControls key="inspector">
<PanelBody title={__("Настройки абзаца")}>
<PanelColorSettings
title={__("Цвет шрифта")}
initialOpen={true}
colorSettings={[
{
value: text_color,
colors: backgroundColors,
onChange: (value) => setAttributes({ text_color: value }),
label: __("Цвет шрифта"),
},
]}
/>
<SelectControl
label={__("Размер шрифта")}
options={fontSizeOptions}
value={font_size}
onChange={(value) => this.props.setAttributes({ font_size: value })}
/>
<SelectControl
label={__("Отступ сверху")}
options={paddingTopOptions}
value={padding_top}
onChange={(value) =>
this.props.setAttributes({ padding_top: value })
}
/>
<SelectControl
label={__("Отступ снизу")}
options={paddingBottomOptions}
value={padding_bottom}
onChange={(value) =>
this.props.setAttributes({ padding_bottom: value })
}
/>
<PluginMetaFields />
</PanelBody>
</InspectorControls>
);
}
}
class HeadlineBlock extends Component {
render() {
const {
attributes: {
headline,
text_color,
font_size,
padding_top,
padding_bottom,
alignment,
},
setAttributes,
} = this.props;
const onChangeAlignment = (newAlignment) => {
this.props.setAttributes({
alignment: newAlignment === undefined ? "none" : newAlignment,
});
};
return [
<Inspector {...{ setAttributes, ...this.props }} />,
<div>
{
<BlockControls>
<AlignmentToolbar value={alignment} onChange={onChangeAlignment} />
</BlockControls>
}
<RichText
tagName="p"
placeholder={__("Текст...")}
keepPlaceholderOnFocus
value={headline}
formattingControls={["bold", "italic", "strikethrough", "link"]}
className={"font-" + font_size + " post-desc__p-text"}
style={{
color: text_color,
textAlign: alignment,
}}
onChange={(value) => setAttributes({ headline: value })}
/>
</div>,
];
}
}
registerBlockType("amm-custom-block/test-block", {
title: __("Тест блок"),
icon: "shield",
category: "AMM",
attributes: {
headline: {
type: "string",
},
alignment: {
type: "string",
default: "none",
},
text_color: {
type: "string",
default: "#525252",
},
font_size: {
type: "string",
default: "14px",
},
padding_top: {
type: "string",
default: "50px",
},
padding_bottom: {
type: "string",
default: "0px",
},
},
edit: HeadlineBlock,
save: function (props) {
const {
attributes: {
headline,
text_color,
font_size,
padding_top,
padding_bottom,
alignment,
},
} = props;
return (
<Fragment>
{headline && !!headline.length && (
<RichText.Content
tagName="p"
className={"font-" + font_size + " post-desc__p-text"}
style={{
color: text_color,
paddingTop: padding_top,
paddingBottom: padding_bottom,
textAlign: alignment,
}}
value={headline}
/>
)}
</Fragment>
);
},
});
So far just added a text field to the block and am trying to read and save the data.
With reading everything is OK, but saving the data does not work and there are no errors.
Any idea why this is happening?
sorry english is not a native language
The meta field _myprefix_text_metafield is a protected field as it starts with a "_" (underscore). This is why you can read the value in withSelect() but not save over it withDispatch() without passing auth_callback.
To save to a protected field, the auth_callback is required, eg:
<?php
register_post_meta( 'post', '_myprefix_text_metafield', array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'auth_callback' => function() {
return current_user_can( 'edit_posts' );
})
);
?>
There is an example in the tutorial you are following:
https://css-tricks.com/managing-wordpress-metadata-in-gutenberg-using-a-sidebar-plugin/#post-291605
Alternatively, if your meta field is not required to be protected/private: re-register your meta field as myprefix_text_metafield (no underscore in the name and no auth_callback) and your current code will work, eg:
<?php
register_post_meta( 'post', 'myprefix_text_metafield', array(
'show_in_rest' => true,
'single' => true,
'type' => 'string'
);
?>

How can I re-render MUI data table upon any user action in react

I have one Lock-Unlock button and a delete button, So the problem is when I render data from axios using useEffect hook its working, but if I lock or unlock a user the table is not changing automatically. That means axios is not getting called.
In that case if I put the useState hook in the useEffect, API is getting called multiple times, that is not as expected. In that case can anyone suggest me how can I re render data table as soon as user clicks on lock-unlock button.
FYI, lock unlock functionality is working 100% correctly. What is needed I have to go to other page and again come back to my datatable page in order to see the change.
code snippet:
const useStyles = makeStyles(theme => ({
button: {
margin: theme.spacing(1)
},
input: {
display: "none"
}
}));
/*
Customization of mui
*/
const getMuiTheme = () => createMuiTheme({
overrides: {
MUIDataTableBodyCell: {
root: {
backgroundColor: "#FFFFFE"
}
}
}
});
/* eslint-disable */
const UserDetailsDatatable = () => {
// console.log('POS: ' + localStorageService.getItem("auth_user"));
if(localStorageService.getItem("auth_user") == null){
history.push({
pathname: "/session/signin"
});
}
const [responsive, setResponsive] = useState("vertical");
const [dataRenderHook, setDataRenderHook] = useState([]);
const [tableBodyHeight, setTableBodyHeight] = useState("650px");
const [tableBodyMaxHeight, setTableBodyMaxHeight] = useState("");
const classes = useStyles();
// Redirect to edit
const newMountpage = (rowData) => {
var pickedUpRowData = rowData.rowData;
let path = `/Admin/users/editUser`;
history.push({
pathname: path,
state: {detail: pickedUpRowData}
});
};
/* Deletion */
const deleteRow = (rowDatam) => {
deleteUser(rowDatam);
};
/* User Locker/Unlocker */
const LockerUnlocker = (Iopticore_ID, state) => {
console.log('State: '+ state);
lockerUnlocker(Iopticore_ID, Boolean(state));
}
const ChangeHandler = (event) => {
console.log(event);
};
const columns = [
{
name: "userID",
label: "Iopticore_ID",
options: {
filter: true,
sort: true,
}
},
{
name: "userName",
label: "Corporate ID",
options: {
filter: true,
sort: true,
}
},
{
name: "name",
label: "User Name",
options: {
filter: true,
sort: true,
}
},
{
name: "email",
label: "Email",
options: {
filter: true,
sort: true,
}
},
{
name: "role",
label: "Role",
options: {
filter: true,
sort: true,
}
},
{
name: "external",
label: "IsExternal",
options: {
filter: true,
sort: true,
filterOptions: {
names: ["Yes", "No"],
logic(v, filterVal) {
const show =
(filterVal.indexOf("Yes") >= 0 && ( v === true || v === 'true') ) ||
(filterVal.indexOf("No") >= 0 && ( v === false || v === 'false') );
return !show;
}
},
customBodyRender: (val) => {
return val === true ? "Yes" : "No";
}
}
},
{
name: "locked",
label: "Access",
options: {
filter: true,
sort: true,
empty: true,
filter: true,
sort: true,
filterOptions: {
names: ["Yes", "No"],
logic(v, filterVal) {
const show =
(filterVal.indexOf("Yes") >= 0 && ( v === true || v === 'true') ) ||
(filterVal.indexOf("No") >= 0 && ( v === false || v === 'false') );
return !show;
}
},
customBodyRender: (val, tableMeta) => {
//console.log('v: ' + val + ' ' + JSON.stringify(tableMeta)) ;
return val === true ? (
<Fab
size="small"
variant="extended"
aria-label="Delete"
className={classes.button}
color="default"
onClick={() => LockerUnlocker(tableMeta.rowData[0], tableMeta.rowData[6])}
>
<img src="https://img.icons8.com/plasticine/25/000000/unlock.png"/>
<b>UnLock </b>
</Fab>
) : (
<Fab
size="small"
variant="extended"
aria-label="Delete"
className={classes.button}
color="default"
onClick={() => LockerUnlocker(tableMeta.rowData[0])}
>
<img src="https://img.icons8.com/dusk/25/000000/unlock.png"/>
<b> Lock </b>
</Fab>
);
}
}
},
{
name: "Edit",
options: {
filter: true,
sort: false,
empty: true,
customBodyRender: (value, tableMeta, updateValue) => {
return (
<Fab
size="small"
color="primary"
aria-label="Edit"
className={classes.button}
onClick={() => newMountpage(tableMeta)}
>
<Icon>edit_icon</Icon>
</Fab>
);
}
}
},
{
name: "Delete",
options: {
filter: true,
textAlign: 'center',
sort: false,
empty: true,
customBodyRender: (value, tableMeta, updateValue) => {
return (
<Fab size="small"
color="secondary"
aria-label="Edit"
className={classes.button}
onClick={() => deleteRow(tableMeta.rowData[0])}
>
<Icon>delete_icon</Icon>
</Fab>
);
}
}
}];
const options = {
selectableRows: 'none',
filter: true,
textAlign: 'center',
filterType: "dropdown",
rowsPerPage: 5,
pagination: true,
responsive,
enableNestedDataAccess: '.',
tableBodyHeight,
tableBodyMaxHeight
};
var recentReceivedToken = localStorage.getItem('jwtAuthtokenManager');
var res= [];
useEffect(() => {
(async () => {
res = await axios.get('<URL>', {
headers: {"Authorization" : `Bearer ${recentReceivedToken}`}
},
// console.log('Hola : ' + JSON.stringify(res))
)
.catch((error)=> {
if(error.response.status != 200){
swal({
title: "Opps! Access Denied",
imageUrl: 'https://notionpress.com/new-rewamp/images/404-error.gif',
text: "You Might Not Have Access To This Page.",
icon: "error",
});
}
})
//console.log('Res : ' + JSON.stringify(res));
setDataRenderHook(res.data);
})();
}, []);
//console.log('Data Promise : ' + renderDatatable());
if(dataRenderHook.length === 0){
//console.log('Length: 0');
return(
<React.Fragment>
<div style={{padding:40}}>
<MuiThemeProvider theme={getMuiTheme()}>
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center"
}}
>
<LinearBuffer />
</div>
</MuiThemeProvider>
</div>
</React.Fragment>
)
}else{
//console.log('Length: 1');
return (
<React.Fragment>
<div style={{padding:40}}>
<MuiThemeProvider theme={getMuiTheme()}>
<MUIDataTable
title={"IoptiCore User List"}
data={dataRenderHook}
columns={columns}
options={options}
/>
</MuiThemeProvider>
</div>
</React.Fragment>
);
}
}
export default UserDetailsDatatable;
import React, { useState, useEffect } from "react";
import MUIDataTable from "mui-datatables";
import { makeStyles,createMuiTheme, MuiThemeProvider } from "#material-ui/core/styles";
import { Icon, Fab } from "#material-ui/core";
import history from "history.js";
import axios from "axios";
import swal from 'sweetalert';
import LinearBuffer from './EditUserHelper/progresscircle';
import lockerUnlocker from './Lock_Unlock/lockerUnlocker';
import deleteUser from './DeleteUser/DeleteUser'
import localStorageService from "../../../services/localStorageService";
import apiDataReturner from "./userAxios";
const useStyles = makeStyles(theme => ({
button: {
margin: theme.spacing(1)
},
input: {
display: "none"
}
}));
/*
Customization of mui
*/
const getMuiTheme = () => createMuiTheme({
overrides: {
MUIDataTableBodyCell: {
root: {
backgroundColor: "#FFFFFE"
}
}
}
});
/* eslint-disable */
const UserDetailsDatatable = () => {
// console.log('POS: ' + localStorageService.getItem("auth_user"));
if(localStorageService.getItem("auth_user") == null){
history.push({
pathname: "/session/signin"
});
}
const [responsive, setResponsive] = useState("vertical");
const [dataRenderHook, setDataRenderHook] = useState([]);
const [tableBodyHeight, setTableBodyHeight] = useState("650px");
const [tableBodyMaxHeight, setTableBodyMaxHeight] = useState("");
const [tracker, setTracker] = useState();
const classes = useStyles();
// Redirect to edit
const newMountpage = (rowData) => {
var pickedUpRowData = rowData.rowData;
let path = `/Admin/users/editUser`;
history.push({
pathname: path,
state: {detail: pickedUpRowData}
});
};
/* Deletion */
const deleteRow = (rowDatam) => {
deleteUser(rowDatam);
var x = apiDataReturner();
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
setTracker(x);
}, 3000);
});
promise.then(values => {
setDataRenderHook(values);
});
};
/* User Locker/Unlocker */
const LockerUnlocker = (Iopticore_ID, state) => {
lockerUnlocker(Iopticore_ID, Boolean(state));
var x = apiDataReturner();
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
setTracker(x);
}, 3000);
});
promise.then(values => {
setDataRenderHook(values);
});
}
const ChangeHandler = (event) => {
console.log(event);
};
const columns = [
{
name: "userID",
label: "Iopticore_ID",
options: {
filter: true,
sort: true,
responsive: 'scrollFullHeightFullWidth',
display: false
}
},
{
name: "userName",
label: "Corporate ID",
options: {
filter: true,
responsive: 'scrollFullHeightFullWidth',
sort: true,
}
},
{
name: "name",
label: "User Name",
options: {
filter: true,
responsive: 'scrollFullHeightFullWidth',
sort: true,
}
},
{
name: "email",
label: "Email",
options: {
filter: true,
responsive: 'scrollFullHeightFullWidth',
sort: true,
}
},
{
name: "role",
label: "Role",
options: {
filter: true,
responsive: 'scrollFullHeightFullWidth',
sort: true,
}
},
{
name: "external",
label: "IsExternal",
options: {
filter: true,
sort: true,
responsive: 'scrollFullHeightFullWidth',
filterOptions: {
names: ["Yes", "No"],
logic(v, filterVal) {
const show =
(filterVal.indexOf("Yes") >= 0 && ( v === true || v === 'true') ) ||
(filterVal.indexOf("No") >= 0 && ( v === false || v === 'false') );
return !show;
}
},
customBodyRender: (val) => {
return val === true ? "Yes" : "No";
}
}
},
{
name: "locked",
label: "Access",
options: {
filter: true,
sort: true,
empty: true,
filter: true,
sort: true,
responsive: 'scrollFullHeightFullWidth',
filterOptions: {
names: ["Yes", "No"],
logic(v, filterVal) {
const show =
(filterVal.indexOf("Yes") >= 0 && ( v === true || v === 'true') ) ||
(filterVal.indexOf("No") >= 0 && ( v === false || v === 'false') );
return !show;
}
},
customBodyRender: (val, tableMeta) => {
//console.log('v: ' + val + ' ' + JSON.stringify(tableMeta)) ;
return val === true ? (
<Fab
size="small"
variant="extended"
aria-label="Delete"
className={classes.button}
color="default"
onClick={() => LockerUnlocker(tableMeta.rowData[0], tableMeta.rowData[6])}
>
<img src="https://img.icons8.com/plasticine/25/000000/unlock.png"/>
<b>UnLock </b>
</Fab>
) : (
<Fab
size="small"
variant="extended"
aria-label="Delete"
className={classes.button}
color="default"
onClick={() => LockerUnlocker(tableMeta.rowData[0])}
>
<img src="https://img.icons8.com/dusk/25/000000/unlock.png"/>
<b> Lock </b>
</Fab>
);
}
}
},
{
name: "Edit",
options: {
filter: true,
sort: false,
empty: true,
responsive: 'scrollFullHeightFullWidth',
customBodyRender: (value, tableMeta, updateValue) => {
return (
<Fab
size="small"
color="primary"
aria-label="Edit"
className={classes.button}
onClick={() => newMountpage(tableMeta)}
>
<Icon>edit_icon</Icon>
</Fab>
);
}
}
},
{
name: "Delete",
options: {
filter: true,
textAlign: 'center',
sort: false,
empty: true,
responsive: 'scrollMaxWidth',
customBodyRender: (value, tableMeta, updateValue) => {
return (
<Fab size="small"
color="secondary"
aria-label="Edit"
className={classes.button}
onClick={() => deleteRow(tableMeta.rowData[0])}
>
<Icon>delete_icon</Icon>
</Fab>
);
}
}
}];
const options = {
selectableRows: 'none',
filter: true,
textAlign: 'center',
filterType: "dropdown",
fixedHeaderOptions:true,
rowsPerPage: 5,
pagination: true,
responsive: 'stacked',
enableNestedDataAccess: '.',
tableBodyHeight,
tableBodyMaxHeight
};
//var recentReceivedToken = localStorage.getItem('jwtAuthtokenManager');
var res= [];
useEffect(() => {
var x = apiDataReturner();
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(x);
}, 2000);
});
promise.then(values => {
setDataRenderHook(values);
});
}, [tracker]);
if(dataRenderHook.length === 0){
return(
<React.Fragment>
<div style={{padding:0}}>
<MuiThemeProvider theme={getMuiTheme()}>
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center"
}}
>
<LinearBuffer />
</div>
</MuiThemeProvider>
</div>
</React.Fragment>
)
}else{
return (
<div>
<React.Fragment>
<div style={{padding:0}}>
<MuiThemeProvider theme={getMuiTheme()}>
<MUIDataTable
title={"IoptiCore User List"}
data={dataRenderHook}
columns={columns}
options={options}
/>
</MuiThemeProvider>
</div>
</React.Fragment>
</div>
);
}
}
export default UserDetailsDatatable;
Sharing the code, it might help someone.

When a prop is changing const is backing to its initial values

I have this component which is a filter for a table..
handleSearch function is responsible to update const filters... its work perfectly when dataIndex props is the same, but when it changes, filters value is backing to it's initial value, an empty array.
I can't manage to resolve it, I've already console log everything.
import React, { useState, } from "react";
import { SearchOutlined } from "#ant-design/icons";
import { Select, Button, Space } from "antd";
const TableFilter = (props) => {
const {
filterType,
filterMode,
filterOptions,
FilterSelectOnFocus,
dataIndex,
setSelectedKeys,
selectedKeys,
confirm,
clearFilters,
} = props;
const [filters, setFilters] = useState([]);
const SelectFilter = (
<Select
style={{ width: 188, marginBottom: 8, display: "block" }}
type={filterType}
mode={filterMode}
name={dataIndex}
value={selectedKeys}
optionFilterProp="children"
placeholder={`Search ${dataIndex}`}
onFocus={FilterSelectOnFocus}
showSearch
onChange={(value) => setSelectedKeys(value ? value : [])}
getPopupContainer={(trigger) => trigger}
notFoundContent
>
{filterOptions?.map((type, key) => (
<Select.Option value={type.value} key={key}>
{type.label}
</Select.Option>
))}
</Select>
);
const defaultFilterTypes = [
{
type: "select",
element: SelectFilter,
},
];
const handleFilterType = () => {
const type = defaultFilterTypes.find((types) => types.type === filterType);
return type.element;
};
const handleSearch = () => {
console.log(filters) //is empty when dataIndex value change, when it's is the same it get the update value of the 75 line
confirm();
const newFilterValues = [...filters]
const index = newFilterValues.findIndex(newValue => newValue.searchedColumn === dataIndex)
if(index === -1){
newFilterValues.push({ searchText: selectedKeys, searchedColumn: dataIndex})
}
else{
newFilterValues[index] = {searchText: selectedKeys, searchedColumn: dataIndex}
}
setFilters(newFilterValues)
}
const handleReset = () => {
console.log('reset');
clearFilters();
setFilters({ searchText: "" });
setSelectedKeys([]);
};
return (
<div style={{ padding: 8 }}>
{handleFilterType()}
<Space>
<Button
type="primary"
onClick={() => handleSearch()}
icon={<SearchOutlined />}
size="small"
style={{ width: 90 }}
>
Search
</Button>
<Button
onClick={() => handleReset()}
size="small"
style={{ width: 90 }}
>
Reset
</Button>
</Space>
</div>
);
};
export default TableFilter;
Table Component
import React, { useEffect, useState } from "react";
import { Table } from "antd";
import { getTransactions } from "../../../../api/Transactions";
import { formatCnpjCpf, formatCurrency } from "../../../../utils/masks";
import TableFilter from "../../../../shared-components/ant-design/containers/TableFilters";
import { getPartnersAsOptions } from "../../../../api/Partners";
const Insider = (props) => {
const [data, setData] = useState([]);
const [paginationValues, setPaginationValues] = useState({
current: 1,
pageSize: 50,
total: 0,
position: ["topRight"],
});
const [partners, setPartners] = useState([{value: null, label: 'carregando...'}])
const context = "insider";
function getColumnSearchProps(
dataIndex,
filterType,
filterMode,
filterOptions,
FilterSelectOnFocus
) {
return {
filterDropdown: ({
setSelectedKeys,
selectedKeys,
confirm,
clearFilters,
}) => {
return (
<TableFilter
dataIndex={dataIndex}
filterType={filterType}
filterMode={filterMode}
filterOptions={filterOptions}
FilterSelectOnFocus={FilterSelectOnFocus}
setSelectedKeys={setSelectedKeys}
selectedKeys={selectedKeys}
confirm={confirm}
clearFilters={clearFilters}
/>
);
},
};
}
async function getPartners(){
if(partners.length > 2){
return
}
const response = await getPartnersAsOptions(paginationValues)
setPartners(response.data)
}
const columns = [
{
dataIndex: ["transactionType", "desc"],
title: "Tipo de Transação",
sorter: true,
key: "orderTransactionType",
...getColumnSearchProps("orderTransactionType"),
},
{
dataIndex: "transactionDate",
title: "Data Transação",
key: "orderTransactionDate",
sorter: true,
...getColumnSearchProps("orderTransactionDate"),
},
{
title: "Nome origem",
dataIndex: ["source", "name"],
sorter: true,
key: "orderSourceCustomerName",
},
{
render: (render) => formatCnpjCpf(render.source.document.value),
title: "Documento origem",
key: "sourceCustomer",
...getColumnSearchProps("sourceCustomer", "select", "tags")
},
{
title: "Nome destino",
dataIndex: ["target", "name"],
sorter: true,
key: "orderTargetCustomerName",
},
{
render: (render) => formatCnpjCpf(render.target.document.value),
title: "Documento destino",
},
{
render: (render) => formatCurrency(render.value),
title: "Valor da transação",
key: "orderValue",
sorter: true,
align: "right",
},
{
render: (render) => formatCurrency(render.chargedTariff),
title: "Tarifa",
key: "orderChargedTariff",
sorter: true,
align: "right",
},
{
render: (render) => formatCurrency(render.cost),
title: "Custo",
key: "orderCost",
sorter: true,
align: "right",
},
{
render: (render) => formatCurrency(render.revenue),
title: "Receita",
key: "orderRevenue",
sorter: true,
align: "right",
},
{
title: "Parceiro",
name: "Parceiro",
dataIndex: ["partner", "name"],
key: "orderPartnerName",
sorter: true,
align: "center",
...getColumnSearchProps(
"orderPartnerName",
"select",
"multiple",
partners,
getPartners)
},
{
title: "id da transação",
name: "id da transação",
dataIndex: "id",
},
];
useEffect(function transactions() {
async function fetchTransactions() {
const response = await getTransactions(context, paginationValues);
if (response) {
const { data, pagination } = response;
setData(data);
setPaginationValues(pagination);
}
}
fetchTransactions();
// eslint-disable-next-line
}, []);
return <Table dataSource={data} columns={columns} />;
};
export default Insider;
You could move this piece of code
const [filters, setFilters] = useState([]);
In a higher level

Categories