How to access to another column's value from a column in v7 (React-Table) - react-table

I see in previous versions that you can access it using :
const columns = [
{
Header: "Name",
accessor: "name",
Cell: (e) => {
return e.original.name;
}
}
];
But in v7 it doesn't work.

In v7 the Cell gets called with a props object. One of the props is the row which has the original property that you are looking for.
{
Header: 'Name',
Cell: (props) => {
return (
<>{props.row.original.lastName}, {props.row.original.firstName}</>
);
}
},
You can destructure the row from the props.
{
Header: 'Name',
accessor: 'firstName',
Cell: ({row, value}) => (
<span onClick={() => alert(row.original.lastName)}>{value}</span>
)
},

Related

How do I align header text in react table?

I am using react-table and enabled filtering on some of the columns. The problem is I want the header text for the columns that don't have filtering to be aligned with the ones that do. How would I go about this?
Also, would it be possible to set the filter text fields to expand the entire width of the column?
import React, { useState } from 'react';
import { useSortBy, useTable, useFilters } from 'react-table';
import { Cells, ColumnHeader, DeleteButton, EditButton, TableContainer } from './view-items.styles';
function DefaultColumnFilter({
column: { filterValue, preFilteredRows, setFilter },
}) {
const count = preFilteredRows.length
return (
<input
value={filterValue || ''}
onChange={e => {
setFilter(e.target.value || undefined) // Set undefined to remove the filter entirely
}}
placeholder={`Search ${count} records...`}
/>
)
}
function SelectColumnFilter({column: { filterValue, setFilter, preFilteredRows, id }, })
{
// Calculate the options for filtering
// using the preFilteredRows
const options = React.useMemo(() =>
{
const options = new Set();
preFilteredRows.forEach(row =>
{
options.add(row.values[id]);
});
return [...options.values()];
}, [id, preFilteredRows]);
// Render a multi-select box
return (
<select
value={filterValue}
onChange={e =>
{
setFilter(e.target.value || undefined);
}}
>
<option value=''>All</option>
{options.map((option, i) => (
<option key={i} value={option}>
{option}
</option>
))}
</select>
);
}
const ViewItems = ({ collections }) =>
{
const [data] = useState(React.useMemo(() =>
{
let init = new Array(0);
for (let i = 0; i < collections.length; i++)
{
Object.entries(collections[i]).map(([key, value]) =>
{
if (Array.isArray(value))
{
for (let j = 0; j < value.length; j++)
{
value[j].description = collections[i].title + ' ' + value[j].name;
value[j].category = collections[i].title;
value[j].price = `$${value[j].price}`;
value[j].onHand = Math.floor((Math.random() * 99) + 1);
init.push(value[j]);
}
}
});
}
return init;
}, []));
const handleEdit = (value) =>
{
console.log(value);
};
const handleDelete = (value) =>
{
console.log(value);
};
const columns = React.useMemo(
() => [
{
Header: 'ID',
accessor: 'id',
},
{
Header: 'Name',
accessor: 'name',
},
{
Header: 'Description',
accessor: 'description',
},
{
Header: 'Price',
accessor: 'price',
disableFilters: true,
disableSortBy: true,
},
{
Header: 'On Hand',
accessor: 'onHand',
disableFilters: true,
disableSortBy: true,
},
{
Header: 'Category',
accessor: 'category',
Filter: SelectColumnFilter,
filter: 'includes',
},
{
Header: 'Edit',
//headerStyle: {textAlign: 'right'},
accessor: '',
disableFilters: true,
disableSortBy: true,
Cell: ({ cell }) => <EditButton onClick={() => handleEdit(cell.row.values)}>Edit</EditButton>,
},
{
Header: 'Delete',
accessor: '',
disableFilters: true,
disableSortBy: true,
Cell: ({ cell }) => <DeleteButton onClick={() => handleDelete(cell.row.values)}>Delete</DeleteButton>,
},
], [],
);
return (
<Table columns={columns} data={data}/>
)
};
function Table({ columns, data })
{
const filterTypes = React.useMemo(
() => ({
// Add a new fuzzyTextFilterFn filter type.
// Or, override the default text filter to use
// "startWith"
text: (rows, id, filterValue) =>
{
return rows.filter(row =>
{
const rowValue = row.values[id]
return rowValue !== undefined
? String(rowValue)
.toLowerCase()
.startsWith(String(filterValue).toLowerCase())
: true
})
},
}),
[]
)
const defaultColumn = React.useMemo(
() => ({
// Let's set up our default Filter UI
Filter: DefaultColumnFilter,
}),
[]
)
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
} = useTable({ columns, data, defaultColumn, filterTypes }, useFilters, useSortBy);
return (
<TableContainer>
<table {...getTableProps()} style={{ border: 'solid 1px blue' }}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<ColumnHeader {...column.getHeaderProps(column.getSortByToggleProps())}>
{column.render('Header')}
<div>{ column.canFilter ? column.render('Filter') : null}</div>
{/*{*/}
{/* <span>*/}
{/* {column.isSorted ? column.isSortedDesc ? ' 🔽' : ' 🔼' : ''}*/}
{/* </span>*/}
{/*}*/}
</ColumnHeader>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map(row =>
{
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell =>
{
return (
<Cells{...cell.getCellProps()}>{cell.render('Cell')}</Cells>
);
})}
</tr>
);
})}
</tbody>
</table>
</TableContainer>
);
}
export default ViewItems;

How to add new panels to the existing gutenberg document sidebar?

I try to add two new panels to the existing gutenberg document sidebar. One should contain a radio-button menu to set the height of the header image, and the other one a text-field to enter a subtitle for the page.
But because I do not want to use the outdated meta boxes technologie, there aren't hardly any tutorials how to accomplish this. I only found the following piece of code, but I have no idea how to shape it to my needs and where to put it ;) - My knowledge of coding is just not good enough, but I still need to implement this feature in my theme.
const { registerPlugin } = wp.plugins
const { PluginDocumentSettingPanel } = wp.editPost
const PluginDocumentSettingPanelDemo = () => (
<PluginDocumentSettingPanel
name="custom-panel"
title="Custom Panel"
className="custom-panel"
>
Custom Panel Contents
</PluginDocumentSettingPanel>
)
registerPlugin('plugin-document-setting-panel-demo', {
render: PluginDocumentSettingPanelDemo
})
Do you maybe have a guess how to achieve my idea? Thanks for you support, and greetings from Austria! Samuel
First of all, register the meta fields, so you have where to save the values. This goes in your plugin file or functions.php.
register_post_meta('post', 'customname_meta_subtitle', array(
'show_in_rest' => true,
'type' => 'string',
'single' => true
));
register_post_meta('post', 'customname_meta_header_height', array(
'show_in_rest' => true,
'type' => 'string',
'single' => true
));
You can check the documentation. We are telling WordPress to create 2 new post meta fields, with keys customname_meta_subtitle and customname_meta_header_height, which we will use in the Gutenberg part.
For the ES code, you will need the following:
const { registerPlugin } = wp.plugins
const { PluginDocumentSettingPanel } = wp.editPost
const { RadioControl, TextControl } = wp.components
const { withState } = wp.compose
const { withSelect, withDispatch } = wp.data
let SubtitleControl = ({ subtitle, handleSubtitleChange }) => (
<TextControl
label="Set subtitle"
value={subtitle}
onChange={subtitle => handleSubtitleChange(subtitle)}
/>
);
SubtitleControl = withSelect(
(select) => {
return {
subtitle: select('core/editor').getEditedPostAttribute('meta')['customname_meta_subtitle']
}
}
)(SubtitleControl);
SubtitleControl = withDispatch(
(dispatch) => {
return {
handleSubtitleChange: (value) => {
dispatch('core/editor').editPost({ meta: { customname_meta_subtitle: value } })
}
}
}
)(SubtitleControl);
let HeaderImageHeightControl = ({ height, handleHeightChange }) => (
<RadioControl
label="Set image height"
help="Set the height of the header image"
selected={height}
options={[
{ label: '100', value: '1' },
{ label: '200', value: '2' },
]}
onChange={handleHeightChange}
/>
);
HeaderImageHeightControl = withSelect(
(select) => {
return {
height: select('core/editor').getEditedPostAttribute('meta')['customname_meta_header_height']
}
}
)(HeaderImageHeightControl);
HeaderImageHeightControl = withDispatch(
(dispatch) => {
return {
handleHeightChange: value => {
dispatch('core/editor').editPost({ meta: { customname_meta_header_height: value } })
}
}
}
)(HeaderImageHeightControl);
const PluginDocumentSettingPanelDemo = () => (
<PluginDocumentSettingPanel
name="custom-panel"
title="Custom Panel"
className="custom-panel"
>
<SubtitleControl />
<HeaderImageHeightControl />
</PluginDocumentSettingPanel>
)
registerPlugin('plugin-document-setting-panel-demo', {
render: PluginDocumentSettingPanelDemo
})
Most of this code is described in the official WP tutorial, but feel free to ask if anything is unclear.
Finally, to use the new values, you can do something like this:
<h1><?php echo get_post_meta(get_the_ID(), 'customname_meta_subtitle')[0]; ?></h1>
<h1><?php echo get_post_meta(get_the_ID(), 'customname_meta_header_height')[0]; ?></h1>
This is to be used in the post template file, for the front-end visualization of the meta field info.
I hope this helps!

How to create multiple meta fields in gutenberg block

I need to create a wordpress Gutenberg block that will allow me to insert some data as name and surname, company name, the best sentence from the references.
So far I managed to create a Gutenberg block that is saving one text field.
dc-references-block.php
// register custom meta tag field
function dcr_register_post_meta() {
register_post_meta( 'page', 'dc_references_block_field', array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
) );
}
add_action( 'init', 'dcr_register_post_meta' );
function dcr_enqueue() {
wp_enqueue_script(
'dc-references-block-script',
plugins_url( 'dc-references-block.js', __FILE__ ),
array( 'wp-blocks', 'wp-element', 'wp-components' )
);
}
add_action( 'enqueue_block_editor_assets', 'dcr_enqueue' );
dc-references-block.js
( function( wp ) {
var el = wp.element.createElement;
var registerBlockType = wp.blocks.registerBlockType;
var TextControl = wp.components.TextControl;
registerBlockType( 'dc-references-block/dc-references-block', {
title: 'Title',
icon: 'edit',
category: 'common',
attributes: {
blockValue: {
type: 'string',
source: 'meta',
meta: 'dc_references_block_field'
}
},
edit: function( props ) {
var className = props.className;
var setAttributes = props.setAttributes;
function updateBlockValue( blockValue ) {
setAttributes({ blockValue });
}
return el(
'div',
{ className: className },
el( TextControl, {
label: 'write here name of company',
value: props.attributes.blockValue,
onChange: updateBlockValue
}
)
);
},
save: function() {
return null;
}
} );
} )( window.wp );
Whenever I try to add a second text field or textarea to the block I get an error "site does not support this block".
Could anyone explain to me how to, in this situation, add correctly more then one text field and textarea to a block?
It would be better if you included the code that did not work. In any case, I changed your code by adding another text input and a textarea (with relevant entries in attributes and meta).
Here is the modified code. Also, I have changed some of the code to be more readable.
Javascript
( function( wp ) {
const el = wp.element.createElement;
const registerBlockType = wp.blocks.registerBlockType;
const TextControl = wp.components.TextControl;
const TextareaControl = wp.components.TextareaControl;
registerBlockType( 'dc-references-block/dc-references-block', {
title: 'Title',
icon: 'edit',
category: 'common',
attributes: {
blockValue: {
type: 'string',
source: 'meta',
meta: 'dc_references_block_field'
},
// Add two new attributes
name: {
type: 'string',
source: 'meta',
meta: 'dc_references_block_field_name'
},
desc: {
type: 'string',
source: 'meta',
meta: 'dc_references_block_field_desc'
}
},
edit: function( props ) {
const className = props.className;
const setAttributes = props.setAttributes;
// Original element with onChange event as an anonymous function
const text = el( TextControl, {
label: 'write here name of company',
value: props.attributes.blockValue,
key: 'companyName',
onChange: function( value ) {
setAttributes( { name: value } );
}
} );
//Add two new elements
const secondText = el( TextControl, {
label: 'Write your name',
value: props.attributes.name,
key: 'username',
onChange: function( value ) {
setAttributes( { name: value } );
}
} );
const textArea = el( TextareaControl, {
label: 'Write a description',
value: props.attributes.desc,
key: 'desc',
onChange: function( value ) {
setAttributes( { desc: value } );
}
} );
return el(
'div',
{ className: className },
// Children of the main div as an array
[ text, secondText, textArea ]
);
},
save: function() {
return null;
}
} );
}( window.wp ) );
PHP
register_post_meta( 'page', 'dc_references_block_field', array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
) );
// register two new meta corresponding to attributes in JS
register_post_meta( 'page', 'dc_references_block_field_name', array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
) );
register_post_meta( 'page', 'dc_references_block_field_desc', array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
) );

Gutenberg dynamic SelectControl values object

I want to dynamically pass the options object to Gutenberg SelectControl:
el( SelectControl, {
label: __( 'Animation' ),
value: props.attributes.animation,
onChange: ( value ) => { props.setAttributes( { animation: value } ); },
options: [
{ value: 'date', label: __( 'One column' ) },
{ value: 'title', label: __( 'Two columns' ) },
],
}
),
I have a PHP function that returns an object of available animations?
function animation( ) {
$animations = array(
'' => 'none',
'fade' => 'fade',
'fade-up' => 'fade-up',
'fade-down' => 'fade-down',
'zoom-out-up' => 'zoom-out-up',
'zoom-out-down' => 'zoom-out-down',
'zoom-out-left' => 'zoom-out-left',
'zoom-out-right' => 'zoom-out-right'
);
return apply_filters( '_animations', $animations );
}
I have used wp_localize_script to get the array as object in JS:
$variables['animations'] = _functions::_animation();
wp_localize_script( $this->plugin_name, 'meetongo', $variables );
and you can access that object like this:
console.log( meetongo.animations );

Added options in Highcharts download/context buttons get repeated

I am adding a few options to my download/export/context buttons in Highcharts. However, the process is a bit complex, as this works as an API. A call is being received by one file, another file is being called where all the options for the graph is being produced, it comes back to the first file, where the graph is generated. Here, the additional options are introduced into the context buttons:
function drawGraph(selectedID, selectedCountries, selectedYears, per_capita, graphBorder, graphSource, graphDefinition, graphStyle, graphXAxis, renderToGraph, renderToDescription)
{
jQuery(document).ready(function() {
var options = {};
url = "xxx.com";
jQuery.getJSON(url, {selectedCountries: selectedCountries , selectedID: selectedID, selectedYears: selectedYears, per_capita: per_capita, graphBorder: graphBorder, graphSource: graphSource, graphDefinition: graphDefinition, graphStyle: graphStyle, graphXAxis: graphXAxis, renderToGraph: renderToGraph, type: "jsonp"})
.done(function(data)
{
//console.log(data);
options.chart = data["chart"];
options.tooltip = data["tooltip"];
options.series = data["series"];
options.title = data["title"];
options.subtitle = data["subtitle"];
options.yAxis = data["yAxis"];
options.xAxis = data["xAxis"];
options.legend = data["legend"];
options.exporting = data["exporting"];
options.plotOptions = data["plotOptions"];
options.credits = data["credits"];
if ((graphDefinition == "true") || (graphDefinition == "on"))
{
jQuery('#'+renderToDescription).html(data["description"]);
}
var chart = new Highcharts.Chart(options);
})
var buttons = Highcharts.getOptions().exporting.buttons.contextButton.menuItems;
// add "separator line"
buttons.push({
separator: true,
});
// add "Link to metadata"
buttons.push({
text: 'Metadata',
onclick: function () {
window.open('http://xxx/metadata.php?selectedID=' + selectedID + '&selectedDatasettype=1', "_blank");
}
});
}
// add "separator line"
buttons.push({
separator: true,
});
// add "Link to more data functions"
buttons.push({
text: 'Link to more data functions',
onclick: function () {
window.open('http://xxx/options.php?selectedID=' + selectedID + '&selectedDatasettype=1', "_blank");
}
});
});
}
And from the other end, I have the file which generates the JSON code:
$data_ = array( "chart" => array("renderTo" => $container, "type" => $graphStyle, "zoomType" => "xy", "marginTop" => $marginTop, "marginRight" => 20, "marginBottom" => 60, "marginLeft" => 80),
"title" => array("useHTML" => true, "text" => "<div style='text-align: center'>".str_replace("CO2", "CO<sub>2</sub>", $selectedDataset -> name)."</div>", "align" => "center", "style" => array("fontFamily" => "Helvetica", "fontSize" => "20px")),
"subtitle" => array("text" => "Original data source: <a href='" . $provider_url . "' style='font-family: Helvetica; color: #428bcc; text-decoration: none' target='_blank'>" . $selectedDataset -> data_provider . "</a>", "useHTML" => true),
"xAxis" => array("tickWidth" => 0, "showFirstLabel" => true, "showLastLabel" => true, "tickInterval" => $step),
"yAxis" => array("min" => $min, "title" => array("useHTML" => true, "text" => str_replace("CO2", "CO<sub>2</sub>", $yTitle), "fontWeight" => "bold", "align" => "high", "textAlign" => "left", "rotation" => 0, "y" => $yAxisY)),
"legend" => array("enabled" => $flagValues, "layout" => "vertical", "align" => "center", "verticalAlign" => "middle", "backgroundColor" => "#efefef", "borderWidth" => 0, "floating" => false, "x" => -185, "y" => 100, "title" => array("text" => ":: Legend ::"), "floating" => true, "draggable" => true, "zIndex" => 20),
"plotOptions" => array("series" => array("connectNulls" => true, "shadow" => false, "lineWidth" => 2, "marker" => array("enabled" => false))),
"tooltip" => array("shared" => true, "crosshairs" => true),
"credits" => array("text" => $copyright, "href" => "http://ede.grid.unep.ch", "position" => array("x" => 10, "y" => -20, "align" => "left"), "style" => array("fontSize" => "9px", "lineHeight" => "9px")),
"exporting" => array("buttons" => array("contextButton" => array("symbol" => "url(http://geodata.grid.unep.ch/images/button_download_4.png)", "x" => -10, "y" => 10))),
"series" => $data,
"protected" => $selectedDataset -> protected_,
"description" => $selectedDataset -> abstract,
"noData" => $flagValues);
header("content-type: application/json");
echo $_GET['callback']. '('. json_encode($data_) . ')';
Now, strangely enough, it seems that if a user from the same site chooses one graph after another, the additional context items are being added up. So, the first call, the separator line and the link to metadata are being added; for the second call, I see the separator line and the link to metadata two times... Very strange. No clue.
One thought: Can the contextButtons first be emptied for each call? And then the additional options added? Something like
Highcharts.getOptions().exporting.buttons.contextButton.menuItems.empty()
Thanks for any hints.
I finally found an approach which seems to work well. This is, loop through the array of menuItems of the contextButton. Check if the item already exists, replace its function. Otherwise, use the standard push-option.
Hopes this helps someone else in a similar situation.
var buttons = [];
buttons = Highcharts.getOptions().exporting.buttons.contextButton.menuItems;
flag_metadata = false;
flag_link_functions = false;
for (var x in Highcharts.getOptions().exporting.buttons.contextButton.menuItems)
{
if (buttons[x].id == "Metadata")
{
buttons[x].onclick = function () {
window.open('http://ede.grid.unep.ch/mod_metadata/metadata.php?selectedID=' + selectedID + '&selectedDatasettype=1', "_blank");}
flag_metadata = true;
}
if (buttons[x].id == "Link")
{
buttons[x].onclick = function () {
window.open('http://ede.grid.unep.ch/options.php?selectedID=' + selectedID + '&selectedDatasettype=1', "_blank");}
flag_metadata = true;
}
}
if (flag_metadata == false)
{
// add "separator line"
Highcharts.getOptions().exporting.buttons.contextButton.menuItems.push({
separator: true,
id: 'sep1',
});
// add "Link to metadata"
Highcharts.getOptions().exporting.buttons.contextButton.menuItems.push({
id: 'Metadata',
text: 'Metadata',
onclick: function () {
window.open('http://ede.grid.unep.ch/mod_metadata/metadata.php?selectedID=' + selectedID + '&selectedDatasettype=1', "_blank");
}
});
// add "separator line"
Highcharts.getOptions().exporting.buttons.contextButton.menuItems.push({
separator: true,
id: 'sep2',
});
// add "Link to more data functions"
Highcharts.getOptions().exporting.buttons.contextButton.menuItems.push({
id: 'Link',
text: 'Link to more data functions',
onclick: function () {
window.open('http://ede.grid.unep.ch/options.php?selectedID=' + selectedID + '&selectedDatasettype=1', "_blank");
}
});
}

Resources