I am creating a React project with Ant-Design. When the page is opened, I want several checkboxes in the table to be selected.
Hook:
const [selectedPages, setSelectedPages] = useState([]);
RowSelection :
let rowSelectionPages = {
selectedPages,
onChange: onSelectPagesChange,
selections: [Table.SELECTION_ALL, Table.SELECTION_NONE],
getCheckboxProps: (record) => {
return {
disabled: record.screenName === 'Disabled',
name: record.screenName,
defaultChecked: record.key === 1
};
},
};
onSelectPagesChange:
let onSelectPagesChange = (newSelectedPages) => {
setSelectedPages(newSelectedPages);
};
Columns:
let columnsPages = [
{
title: "screen name",
dataIndex: "screenName",
render: (text) => <a>{text}</a>,
},
];
MyData:
let dataPages = [
{
key: "1",
screenName: "Home",
},
{
key: "2",
screenName: "Login",
},
{
key: "3",
screenName: "profile",
},
{
key: "4",
screenName: "Disabled",
},
];
Table:
<Table
rowSelection={{
type: "checkbox",
...rowSelectionPages,
}}
columns={columnsPages}
dataSource={dataPages}
/>
I am using Ant-Design library for the first time.
This is the code I tried.
But I couldn't come to a conclusion.
Add row indexes in the state selection
const [selectedPages, setSelectedPages] = useState([0]); // check first row
demo
I'm having a hard time to structure the list location for items array in order to access name attribute in search.js
Below is the nested JSON structure:
{
menus: [
{
name: "Summer ",
url: "/menus/2",
items: [
{
name: "man o man", //this is what I'm trying to access
url: "/menus/2/items/7"
}
]
]
}
So far I've tried in search.js:
document.addEventListener("turbolinks:load", function() {
$input = $("[data-behavior='autocomplete']")
var options = {
getValue: "name",
url: function(phrase) {
data = "/search.json?q=" + phrase;
return data;
},
categories: [
{
listLocation: "menus",
header: "--<strong>Menus</strong>--",
},
{
listLocation: "items", //this is where I'm having problem with
header: "--<strong>Items</strong>--",
}
],
list: {
onChooseEvent: function() {
var url = $input.getSelectedItemData().url
$input.val("")
Turbolinks.visit(url)
}
}
}
$input.easyAutocomplete(options)
})
I've have a complex data structure with multiple nested arrays in place.
Below is the current structure
var contentData = {
data: {
content: [
{
type: "column",
sections: [
{
sub: [
{
type: "heading-1",
text: "Heading Text"
}
]
}
]
},
{
type: "acc-item",
sections: [
{
sub: [
{
type: "heading-1",
text: "Heading Text"
},
{
type: "ordered-item",
text: "Item 1"
},
{
type: "unordered-item",
text: "Item 2"
}
]
}
]
},
{
type: "acc-item",
sections: [
{
sub: [
{
type: "heading-1",
text: "Heading Text 2"
}
]
}
]
}
]
}
}
So What I wanted is,
I wanted to group all the ordered-item & unordered-item into a new object like {type: 'list', items:[all list items]}.
I need to extract all items which are inside sub and push it to new object embedded and it should placed in the root level like below,
{type:"acc-item",embedded:[{type:"heading-1",text:"Heading Text 2"}]};
So What I've done so far,
I can able to group acc-item, but not the ordered-item & unordered-item.
So my final expected result should like this,
[{
"type": "column",
"embedded": [
{
"type": "heading-1",
"text": "Heading Text"
}
]
},
{
"type": "acc-group",
"items": [
{
"type": "acc-item",
"embedded": [
{
"type": "heading-1",
"text": "Heading Text"
},
{
"type": "list",
"items": [
{
"type": "ordered-item",
"text": "Item 1"
},
{
"type": "unordered-item",
"text": "Item 2"
}
]
}
]
},
{
"type": "acc-item",
"embedded": [
{
"type": "heading-1",
"text": "Heading Text 2"
}
]
}
]
}]
Below is my code,
var group,contentData={data:{content:[{type:"column",sections:[{sub:[{type:"heading-1",text:"Heading Text"}]}]},{type:"acc-item",sections:[{sub:[{type:"heading-1",text:"Heading Text"},{type:"ordered-item",text:"Item 1"},{type:"unordered-item",text:"Item 2"}]}]},{type:"acc-item",sections:[{sub:[{type:"heading-1",text:"Heading Text 2"}]}]}]}},types=[["list",["ordered-item","unordered-item"]],["accordion",["acc-item"]]];
var result = contentData.data.content.reduce((r, o) => {
var type = (types.find(({ 1: values }) => values.indexOf(o.type) > -1)|| {})[0];
if (!type) {
r.push(o);
group = undefined;
return r;
}
if (!group || group.type !== type) {
group = { type, items: [] };
r.push(group);
}
group.items.push(o);
return r;
}, []);
document.body.innerHTML = '<pre>' + JSON.stringify(result, null, ' ') + '</pre>';
You could store the last items array as well as the last embedded array and use them until a column type is found.
var contentData = { data: { content: [{ type: "column", sections: [{ sub: [{ type: "heading-1", text: "Heading Text" }] }] }, { type: "acc-item", sections: [{ sub: [{ type: "heading-1", text: "Heading Text" }, { type: "ordered-item", text: "Item 1" }, { type: "unordered-item", text: "Item 2" }] }] }, { type: "acc-item", sections: [{ sub: [{ type: "heading-1", text: "Heading Text 2" }] }] }] } },
list = ["ordered-item", "unordered-item"],
lastItems, lastEmbedded,
result = contentData.data.content.reduce((r, { type, sections }) => {
if (type === 'column') {
r.push({ type, embedded: sections.reduce((q, { sub }) => q.concat(sub), []) });
lastItems = undefined;
lastEmbedded = undefined;
return r;
}
if (!lastItems) r.push({ type: "acc-group", items: lastItems = [] });
lastItems.push(...sections.map(({ sub }) => ({
type,
embedded: sub.reduce((q, o) => {
if (list.includes(o.type)) {
if (!lastEmbedded) q.push({ type: 'list', items: lastEmbedded = [] });
lastEmbedded.push(o);
} else {
q.push(o);
lastEmbedded = undefined;
}
return q;
}, [])
})));
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
The Array.prototype and Object.prototype methods are perfect for this kind of thing.
And you're right that this is some complicated kind of logic.
I would suggest that you definitely need some unit tests for this, and try break in to separate pieces.
Here's how I'm thinking I'd do it.
1. Group By the type to create your groups..
I'm actually creating a more generic solution that you've asked for here. That is, I'm not just grouping the 'acc-item', but everything.
I did a quick search for 'array group by javascript' and it gives us this answer which suggests using Array.reduce, so let's do that.
const groupedData = contentData.data.content.reduce((acc, cur) => {
//Check if this indexed array already exists, if not create it.
const currentArray = (acc[`${cur.type}-group`] && acc[`${cur.type}-group`].items) || [];
return {
...acc,
[`${cur.type}-group`]: {
type: `${cur.type}-group`,
items: [...currentArray, cur]
}
}
}, {});
2. Now for each of those items, we need to look at their subs, and group just the list items.
To do this, we basically want to find all the `item -> sections -> sub -> types and filter them into two arrays. A quick google on how to create two arrays using a filter gives me this answer.
First though, we need to flatten that sections-> subs thing, so lets just do that.
function flattenSectionsAndSubs(item) {
return {
type: item.type,
subs: item.sections.reduce((acc, cur) => ([...acc, ...cur.sub]), [])
};
}
And I'll just copy paste that partition function in:
function partition(array, isValid) {
return array.reduce(([pass, fail], elem) => {
return isValid(elem) ? [[...pass, elem], fail] : [pass, [...fail, elem]];
}, [[], []]);
}
const listTypes = ['ordered-item', 'unordered-item'];
function createEmbeddedFromItem(item) {
const [lists, nonLists] = partition(item.subs, (v) => listTypes.includes(v.type);
return {
type: item.type,
embedded: [
...nonLists,
{
type: "list",
items: lists
}
]
}
}
Putting this all together and we get.
const contentData = {
data: {
content: [{
type: "column",
sections: [{
sub: [{
type: "heading-1",
text: "Heading Text"
}]
}]
},
{
type: "acc-item",
sections: [{
sub: [{
type: "heading-1",
text: "Heading Text"
},
{
type: "ordered-item",
text: "Item 1"
},
{
type: "unordered-item",
text: "Item 2"
}
]
}]
},
{
type: "acc-item",
sections: [{
sub: [{
type: "heading-1",
text: "Heading Text 2"
}]
}]
}
]
}
}
function partition(array, isValid) {
return array.reduce(([pass, fail], elem) => {
return isValid(elem) ? [
[...pass, elem], fail
] : [pass, [...fail, elem]];
}, [
[],
[]
]);
}
function flattenSectionsAndSubs(item) {
return {
type: item.type,
subs: item.sections.reduce((acc, cur) => ([...acc, ...cur.sub]), [])
};
}
const listTypes = ['ordered-item', 'unordered-item'];
function createEmbeddedFromItem(item) {
const [lists, nonLists] = partition(item.subs, (v) => listTypes.includes(v.type));
return {
type: item.type,
embedded: [
...nonLists,
{
type: "list",
items: lists
}
]
}
}
const groupedData = contentData.data.content.reduce((acc, cur) => {
//Check if this indexed array already exists, if not create it.
const currentArray = (acc[`${cur.type}-group`] && acc[`${cur.type}-group`].items) || [];
const flattenedItem = flattenSectionsAndSubs(cur);
const embeddedItem = createEmbeddedFromItem(flattenedItem);
return {
...acc,
[`${cur.type}-group`]: {
type: `${cur.type}-group`,
items: [...currentArray, embeddedItem]
}
}
}, {});
console.log(groupedData);
Now this doesn't exactly match what you've asked for - but it should probably work.
You can add your own bits into only add a list item, if the array isn't empty, and to stop the column from being in its own group.
The thing is - tbh it seems like a little bit of a red flag that you would create an array of items that don't having matching structures, which is why I've done it this way.
Just started with ReactJS and I'm looking for the most efficient code to display the array below in a table structure as described in the 'render' section. I have been using .map to iterate through the users/buttons objects, but with no success yet.
In my code sample below, I want to take the userData array and display the content in separate rows (html table format)ie.
Joe,Smith,[Click 1A],[Click2B] //'Click XX' are buttons
Mary,Murphy,[Click 2A],[Click2B]
How can I achieve this?
Thanks
var MyButton = require('./mybutton.js');
var userData =[{
userButtons: [
[{user: [{ id: 1, lastName: 'Smith', firstName: 'Joe',
buttons: [
{button:[{ id:0, value: "Click 1A" enabled:1}]},
{button:[{ id:1, value: "Click 1B" enabled:1}]}
]
}]}],
[{user: [{ id: 1, lastName: 'Murphy', firstName: 'Mary',
buttons: [
{button:[{ id:0, value: "Click 2A" enabled:1}]},
{button:[{ id:1, value: "Click 2B" enabled:1}]}
]
}]
}]
]}];
var DisplayData = React.createClass({
render: function() {
// render userButtons in a table with data using <MyButton> ie.
// <table>
// <tr><td>Joe</td><td>Smith</td><td>[Click 1A]</td><td>[Click 2A]</td</tr>
// <tr><td>Mary</td><td>Murphy</td><td>[Click 2B]</td><td>[Click 2B]</td></tr>
// </table>
}
}
});
React.render(
<DisplayData tArr = {userData} />
, document.getElementById('content')
);
// mybutton.js
var React = require('react');
module.exports = React.createClass({
render: function() {
return (
<button>{this.props.value}</button>
)
}
});
I would suggest you simplify your userData if possible.. you have quite a bit of extra nested arrays that don't seem to be needed.
Something like this:
var userButtons = [
{
id: 1,
lastName: 'Smith',
firstName: 'Joe',
buttons: [
{
id: 0,
value: "Click 1A",
enabled: 1
}, {
id: 1,
value: "Click 1B",
enabled: 1
}
]
},
{
id: 2,
lastName: 'Murphy',
firstName: 'Mary',
buttons: [
{
id: 0,
value: "Click 2A",
enabled: 1
}, {
id: 1,
value: "Click 2B",
enabled: 1
}
]
}
];
Then it's easy to loop through and return the right elements:
return (
<table>
{
userButtons.map(function(ub) {
var buttons = ub.buttons.map(function(button) {
return (
<td>{button.value}</td>
)
});
return (
<tr>
<td>{ub.firstName}</td>
<td>{ub.lastName}</td>
{buttons}
</tr>
)
})
}
</table>
)
Something like the following might work:
handleClick: function(id, value) {
// do something
},
render: function() {
var rows = userData.userButtons.map(
function(u) {
var buttons = u.buttons.map(
function(b) {
return <Button onClick={function() { this.handleClick(b.id, b.value)}.bind(this);}
enabled={b.enabled===1}>
{b.value}
</Button>;
});
return <tr>
<td>{u.firstName}</td>
<td>{u.lastName}</td>
{buttons}
</tr>;
});
return <table>{rows}</table>;
}
Where I assume you can get Button from something like react-bootstrap.
I want to shuffle the fields in popup when ever i add or edit the record
In this below fiddle example Grid view Columns are in sequence like First Name,LastName,Cities But when ever i do add or Edit in popup first i want sequence of fields to be like Cities, LastName, FistName.
Jsfiddle Link
<div id="grid"></div>
var firstNames = ["Nancy", "Andrew", "Janet", "Margaret", "Steven", "Michael", "Robert", "Laura", "Anne", "Nige"];
var lastNames = ["Davolio", "Fuller", "Leverling", "Peacock", "Buchanan", "Suyama", "King", "Callahan", "Dodsworth",
"White"];
var cities = ["Seattle", "Tacoma", "Kirkland", "Redmond", "London", "Philadelphia", "New York",
"Seattle", "London", "Boston"];
function createRandomData(count) {
var data = [],
now = new Date();
for (var i = 0; i < count; i++) {
var firstName = firstNames[Math.floor(Math.random() * firstNames.length)];
var lastName = lastNames[Math.floor(Math.random() * lastNames.length)];
var city = [];
for (var j = 0; j < Math.floor(Math.random() * 3 + 1); j++) {
city.push(cities[Math.floor(Math.random() * cities.length)]);
}
data.push({
Id: i + 1,
FirstName: firstName,
LastName: lastName,
Cities: city
});
}
return data;
}
function citiesEditor(container, options) {
$("<select multiple='multiple' " +
"data-bind='value : Cities'/>").appendTo(container).kendoMultiSelect({
dataSource: cities
});
}
var ds = new kendo.data.DataSource({
transport: {
read: function (op) {
op.success(createRandomData(300));
},
update: function (op) {
alert("update: " + JSON.stringify(op, null, 2));
op.success(op.data);
}
},
pageSize: 10,
schema: {
model: {
id: "Id",
fields: {
Id: {
type: 'number'
},
FirstName: {
type: 'string'
},
LastName: {
type: 'string'
}
}
}
}
});
var grid = $("#grid").kendoGrid({
dataSource: ds,
editable: "popup",
pageable: {
refresh: true,
pageSizes: true
},
columns: [{
command: "edit",
width: 100
}, {
field: "FirstName",
width: 100,
title: "First Name"
}, {
field: "LastName",
width: 100,
title: "Last Name"
}, {
field: "Cities",
width: 300,
editor: citiesEditor,
template: "#= Cities.join(', ') #"
}]
}).data("kendoGrid");
How to shuffle fields on Add and Edit Popup.