Has column show property stopped working in latest react-table v7? - react-table

I have used the show property to show/hide columns in my table earlier and it has worked fine using react-table v7. However, recently I cannot get it to work any longer, since I've made a bunch of changes and my table is quite complex I'm not sure what caused it, possibly also an update of react-table itself (7.0.0-beta.12 to 7.0.0-rc.5).
Anyway, now I can't even get the most basic show example to work:
const columns = React.useMemo(
() => [
{
Header: "Info",
columns: [
{
Header: "Age",
accessor: "age",
show: false
},
{
Header: "Visits",
accessor: "visits"
}
]
}
],
[]);
https://codesandbox.io/s/react-table-hide-column-2g3js
Why is the 'age' column showing?
Edit
Digging into the changelog I now understand that column show/hide has indeed changed:
7.0.0-beta.28 Added the useColumnVisibility plugin as a core plugin along with several new instance and column-level methods to control
column visibility Added the "column-hiding" example
However, I still have not figured out how to apply the useColumnVisibility hook to a column in a similar way to how show used to work. The "column-hiding" example shows how to do it with checkboxes but does not help in my case (afaik).

I had a similar issue as I was using show. Instead of setting show in the column, set the initialState.hiddenColumns, here you can convert your existing show into the initial hidden columns:
useTable<T>(
{
columns,
data,
hiddenColumns: columns.filter(column => !column.show).map(column => column.id)
},
I couldn't use that as my columns are loaded dynamically (so the initial state was set to some columns that didn't exist, and was just set to an empty array) so I used:
React.useEffect(
() => {
setHiddenColumns(
columns.filter(column => !column.show).map(column => column.id)
);
},
[columns]
);
where setHiddenColumns is provided by useTable:
const {
headerGroups,
rows,
prepareRow,
state,
toggleRowSelected,
toggleAllRowsSelected,
setHiddenColumns
} = useTable<T>(
{
columns,
data,
getRowId,
...
This means if I changed the column props it would be reflected in the table.

I also use setHiddenColumns to show/hide columns. However, instead returning Header, I use id. My code:
...
setHiddenColumns,
flatColumns,
headerGroups,
state: { pageIndex, pageSize },
} = useTable({
columns,
data,
initialState: { pageIndex: 0 },
manualPagination: true,
pageCount: controlledPageCount,
},
useSortBy,
usePagination
);
React.useEffect(() => {
const hiddenColumns = flatColumns.filter((column: any) => !column.show).map((column: any)=> column.id);
setHiddenColumns(hiddenColumns); }, []);

Related

React-Table display contents of array as individual elements inside a cell

I am trying to use react-table to visualise some data structured as below:
{
companyName: "Barclays Bank Plc",
tenancies: ["G.01 # Newbuilding"],
status: "Active",
accountNumber: "EX209302",
logo: "companylogo1",
},
{
companyName: "Boeing AerospaceLtd",
tenancies: ["G.01 # Newbuilding", "G.02 # Newbuilding"],
status: "Active",
accountNumber: "EX209302",
logo: "companylogo1",
},
My column definition (which doesn't work) looks something like this:
{
Header: "Tenancies",
accessor: "tenancies",
Cell: (tableProps) => (
<div>{tableProps.cell.value.forEach((item) => item)}</div>
),
},
What I am trying to do is display each array item within it's own HTML tags (such as a div) so I can visually style and seperate them within the table cell.
Can anyone point me in the right direction as to the best way to achieve this?
According to the API document, the Cell receives the table Instance and returns a valid JSX.
{
...
Cell: (tableInstance) => JSX
}
Since the tenancies array are available from tableInstance.row.original.tenancies, so you can change your tenancies column definition as follow:
{
Header: "Tenancies",
Cell: ({ row }) => {
return (
<div>
{row.original.tenancies.map((tenancy, i) => (
<div key={i}>{tenancy}</div>
))}
</div>
);
}
}
Here is the example:

How to pass attributes to child Gutenberg blocks in InnerBlocks template?

I'm trying to build a custom set of column blocks using InnerBlocks and am having trouble passing attributes to block templates. To start, I scaffolded a new plugin using Create-Guten-Block. I then created two blocks, one to serve as a row container, and one for individual columns.
Here is a simplified version of how I'm creating the main container (with two columns hard-coded for testing):
registerBlockType( 'wabe/multi-column-block', {
title: __( 'Multi-Column' ),
icon: 'columns',
category: 'common',
keywords: [
__( 'columns' ),
__( 'grid' ),
],
attributes: {
layout: {
type: 'string',
},
},
edit: () => {
return (
<div>
{ /* inspector controls for choosing a layout will go here */ }
<InnerBlocks
template={ [
[ 'wabe/multi-column-column', { columnwidth: '6' }, [
[ 'core/paragraph', { content: 'Insert column content here.' } ],
],
],
[ 'wabe/multi-column-column', { columnwidth: '6' }, [
[ 'core/paragraph', { content: 'Insert column content here.' } ],
],
],
] }
/>
</div>
);
},
save: () => {
// This is a dynamic block
return (
<InnerBlocks.Content />
);
},
} );
... and how I'm creating the individual column block:
registerBlockType( 'wabe/multi-column-column', {
title: __( 'Multi-Column Column' ),
icon: 'columns',
category: 'common',
keywords: [
__( 'columns' ),
__( 'grid' ),
],
attributes: {
columnwidth: {
type: 'string',
default: '',
},
},
edit: ( props ) => {
return (
<div>
<p>Width: { props.attributes.columnwidth }</p>
<InnerBlocks />
</div>
);
},
save: () => {
return (
<InnerBlocks.Content />
);
},
} );
I'll have a custom select for users to choose a column layout, and using that, will determine how many columns to include, and pass the "columnwidth" attribute to each column block. This will tell each column what CSS class to use.
The problem is no matter what I try, that "columnwidth" attribute just will not be passed to the column block. In fact, I can't get it to pass anything, even "className".
I've looked at the code for core columns/column blocks, and can't see what I'm doing wrong. Everything has gone great up until this giant roadblock. Any tips are appreciated.
The block code example you have provided shows you are setting up the InnerBlocks fine. The issue may be a simple oversight that you have missed importing the required dependancy of <InnerBlocks>.
I was able to build your block code successfully once I added the required imports:
import { registerBlockType } from '#wordpress/blocks';
import { __ } from '#wordpress/i18n';
import { InnerBlocks} from '#wordpress/block-editor';
Here is the result:
The code editor shows that your attributes are being passed and being saved.
If you are still encountering an issue, double check that you are clearing your browser cache before retesting and also check the browser console to see if any errors are present.
As you mentioned you have already reviewed the Gutenberg code for Columns/Column, a tip would be to look at how they do variations for creating the options in your Inspector Control. Hope this gets you back on track with creating your block.

Vue/Vuex watcher dynamic/async component loading

I have a base component within which I have a dynamic component with a v-for that displays based on a computed property.
All I've really tried doing thus far, which was an incorrect methodology, was to wrap the method that loads data in a settimeout. This question is as much a methodology question as it is a coding question.
My base component looks like this:
<template>
<div>
<v-progress-linear
v-model="progressValue"
v-if="loading"
></v-progress-linear>
<component
v-for="table in tables"
:key="table.id"
:is="table.structure"
:table="table"
></component>
</div>
</template>
<script>
import Annual from './DataTables/Annual';
import { mapState, mapGetters } from 'vuex';
export default {
name: "Page",
props: [],
components: {
Annual,
},
data: () => ({
progressValue: 0,
loading: false,
tables: [],
}),
computed: {
...mapGetters({
currentTables: 'getCurrentPageTables',
tableTitles: 'getCurrentPageTableTitles',
}),
...mapState({
pageName: state => state.pageName,
snakeName: state => state.snakeName,
}),
methods: {
updateTables(payload) {
this.loading = true;
payload.forEach(title => {
this.tables.push(this.currentTables.filter(e => title === e.name)[0]);
this.progressValue = this.tables.length / payload.length;
})
},
},
watch: {
snakeName: {
handler() {
this.progressValue = 0;
this.updateTables(this.tableTitles);
this.$nextTick(() => {this.loading = false;})
},
immediate: true,
},
}
}
</script>
Annual.vue is simply a component that displays a Vuetify v-data-table element and its structure is fairly inconsequential to this.
For all intents and purposes we can consider currentTables and tableTitles to both be arrays, the first of objects whose data populate the v-data-tables in Annual.vue, and the second of strings which are just the names of the tables.
When the user navigates to another page the getters return different data, based on the page the user navigates to, but some of the pages have over 20 tables, which makes page loading slow upon navigation to these pages. I am trying to do one of two things:
1. Asynchronously load the components one at a time while still making the page functional for the user to navigate through.
2. Display a loader that disappears after all of the content is rendered. I'm having trouble figuring out how to do the latter because I can't put this functionality into the mounted() hook since all of this happens upon the watched parameter changing (hence the component is not re-mounted each time the route changes).
Any advice on how to tackle this would be appreciated.

What's the correct way to filter and keep the original results with Redux

I'm looking for the "correct" way to filter the original state.
State
{
searchText: '',
items: [
{name: 'Tom'},
{name: 'Larry'},
{name: 'Harry'}
]
}
Reducer
const filterText = action.text.toLowerCase();
const filteredResults = state.items.filter((item) => {
return item.name.toLowerCase().indexOf(filterText.toLowerCase()) > -1
})
const newState = { items: filteredResults , searchText: action.text }
return newState
Container
return this.props.people.items.map((person) => {
return(
<li
key={person.name}
onClick={() => this.props.selectPerson(person)}
>{person.name}</li>
)
})
However if I clear the text input I've obviously removed the items with .filter() I basically need on the keystroke to search all results but not remove from the original state.
I have a solution, and store an additional piece of data on the store and then add the results into the items array.
initialItems: [...],
items: [...]
However as mentioned I'm looking for the correct way to filter my results and I'm not sure if this is it.
Your solution is just one of the solutions to do this. IMO there are no "correct" ways because every implementation will have its pros and cons :)
However, a "cleaner" solution with eventually better performance results that comes to my mind is to use a selector in mapStateToProps which will filter out the items according to the searchText. In practice it would be just moving your code from the reducer to a selector.
const filterItems = state =>
state.items.filter(item =>
item.name.toLowerCase().indexOf(state.searchText.toLowerCase())
);
const mapStateToProps = state => ({
filteredItems: filterItems(state)
});
export default connect(mapStateToProps)(YourComponent);
You could do this even better by using reselect - https://github.com/reactjs/reselect

grid.getColumnmanager().getColumns() is not giving parent column in Ext JS grid

I have grid having grouped columns.
Some of my code is as follows:
Ext.require([
'Ext.grid.*',
'Ext.ux.grid.FiltersFeature',
'Ext.ux.LiveSearchGridPanel'
...
]);
var filters = {
ftype: 'filters',
encode: false,
local: true
};
var grid = new Ext.create('Ext.ux.LiveSearchGridPanel', {
selType: 'cellmodel',
store: store,
columns:[
{
header: "Column1"
dataIndex: 'Column1'
},{
header: "Column2",
columns : [{
header: "innerColumn1",
dataIndex: 'innerColumn1'
},{
header: "innerColumn2"
dataIndex: 'innerColumn2'
}]
},{
header: "Column3",
dataIndex: 'Column3'
}],
features: [filters]
...
Now, if I use grid.columnManager.getColumns() it returns following columns:
Column1
innerColumn1
innerColumn2
Column3
It is not returning Column2 which is a parentColumn/groupColumn of innerColumn1 & innerColumn2. Which method of Ext Js I should use to get Column2 as well in the columnList? I am using Ext Js 4.2. Any help will be appreciated.
grid.getColumnmanager().getColumns() does not provide parent column of grouped columns. Column manager is to deal with only leaf columns.
While iterating columns you can access isSubHeader property only available in child groped columns and after that through ownerCt property you can access parent column.
hope this helps.
One of the solution to get all the columns is to make use of Ext ComponentQuery. I have created this fiddle. Look into the developer console of after running this fiddle.
So simplest query to get all the columns is :
grid.query('gridcolumn:not([hidden])')// Open fiddle for full example
It will simply return all visible columns. You can change query according to your requirements.
For Example, to get only the Grouped Column, you can use this
grid.query('gridcolumn[isGroupHeader=true]')
Click here for more information about ComponentQuery.

Resources