I am using react-table.js to take data from a form, but I want to be able to delete the data out of the table. The button is working so I know that is attached properly, but I can't seem to get it to delete.
Here is the code
handleDelete = item => {
var newArr = [];
const newState = this.props.documentation;
for (var key in newState) {
if (newState.hasOwnProperty(key)) {
let data = newState[key];
data.id = key;
newArr.push(newState[key]);
}
const sliceArr = newArr.slice();
if (sliceArr.indexOf(item) > -1) {
sliceArr.slice(sliceArr.indexOf(item), 1);
}
console.log('New Array', sliceArr);
this.setState({ data: sliceArr });
}
};
Along with the button I am attaching it to
Cell: row => (
<div>
<button onClick={() => this.handleDelete(row.id)}>Delete</button>
</div>
You're looking for splice rather than slice:
const spliceArr = newArr.slice();
if (spliceArr.indexOf(item) > -1) {
spliceArr.splice(spliceArr.indexOf(item), 1);
}
console.log('New Array', spliceArr);
this.setState({ data: spliceArr });
Example:
const newArr = [1, 2, 3, 4]
// [1, 2, 3, 4] example
const spliceArr = newArr.slice()
// [1, 2, 3, 4] ok
spliceArr.slice(spliceArr.indexOf(3), 1)
spliceArr
// [1, 2, 3, 4] oops
spliceArr.splice(spliceArr.indexOf(3), 1)
spliceArr
// [1, 2, 4] better
If that doesn't get you all the way there, you may want to update your question with the rendering (presumably JSX) of the table itself, as #MichaelBenin suggested.
Related
It's a simple Vue.js test application and the code looks as following:
<template>
<div>
<button #click="onPrevious">Previous</button>
<button #click="onNext">Next</button>
<br><br>
<div v-for="(a, index) in chunkedArr()" :key="index">
<div v-for="(i, index) in a" :key="index">{{ i }}</div>
-
</div>
</div>
</template>
<script>
export default {
data() {
return {
input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
newInput: [],
currentIndex: 0
}
},
mounted() {
const temp = []
for (let i = 0; i < this.input.length; i += 3) {
let chunk = this.input.slice(i, i + 3)
if (chunk.length === 1) {
chunk = chunk.concat(this.input.slice(0, 2))
}
if (chunk.length === 2) {
chunk = chunk.concat(this.input.slice(0, 1))
}
temp.push(chunk)
}
this.newInput = temp.flat()
},
methods: {
chunkedArr() {
if (this.newInput.length === 0) {
return
}
const output = []
for (let i = this.currentIndex; i < this.newInput.length; i += 3) {
let chunk = this.newInput.slice(i, i + 3)
output.push(chunk)
}
console.log(output)
return output
},
onNext () {
this.chunkedArr()
},
onPrevious () {
// TODO
}
},
}
</script>
We could simulate carousel with Next and Previous buttons. Suppose we have some array of elements that should be displayed in carousel.
But, in this carousel we should display 3 elements at once. It means 3 elements should be visible only on each click Next/Previous. For example, if we have an array of elements: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, the initial state is to display: 1, 2, 3. On first click on Next, carousel should display 4, 5, 6 and so on. There are 3 cases at the end of array. The array can have 1, 2 or 3 elements at the end. If it has 3 elements, everything is easy. But if it has 1 or 2 elements, we need to add 2 or 1 elements respectively. In case of having 1 element at the end we need to add first 2 elements of array in order to display 3 elements. In case of having 2 elements at the end (our test case) we need to add first element only in order to display 3 elements. The rotating should go further based on previously described scenario.
Please, take a look at the screenshot attached:
In real case I need that data structure for BootstrapVue's Carousel.
UPDATE:
There are 4 subarrays in output array. Please, take a look at the screenshot below:
UPDATE:
const example = [1, 2, 3, 4, 5];
const subArrayIterator = subArrayGenerator(example);
console.log('init: ' + subArrayIterator.next().value); // init
const prevBtn = document.getElementById('prev');
const nextBtn = document.getElementById('next');
prevBtn.onclick = () => {
console.log(subArrayIterator.next(false).value);
}
nextBtn.onclick = () => {
console.log(subArrayIterator.next().value);
}
function* subArrayGenerator(inputArray, subArrayLength=3) {
let prev = false;
for (let i = 0; i < inputArray.length;) {
if (prev) {
let diff = subArrayLength*2;
if (diff > inputArray.length) {
diff = diff % inputArray.length;
}
diff = i - diff;
i = diff < 0 ? inputArray.length + diff : diff;
}
const subArray = [];
for (let j = 0; j < subArrayLength; j++) {
subArray.push(inputArray[i]);
i = i < inputArray.length - 1 ? i + 1 : 0;
}
prev = (yield subArray) === false;
}
}
<button type="button" id="prev">prev</button>
<button type="button" id="next">next</button>
Another approach:
Rotate the array by appending a splice of input from 0 to currentIndex:
input.push(...input.splice(0, currentIndex))
Pad the array to a max length of 12 by appending a slice of input from 0 to the pad length:
while (12 - input.length > 0) {
input.push(...input.slice(0, 12 - input.length))
}
Split the array into slices of 3 by Array(size).fill().map():
const output = Array(Math.ceil(input.length / 3)).fill().map((_, i) => input.slice(i * 3, i * 3 + 3))
demo
I'm having an object like this
{
"GroupA": {
"Parent1": [1, 2, 3],
"Parent2": [1, 2, 3],
"Parent12": [1, 2, 3]
},
"GroupB": {
"Parent13": [1, 2, 3],
"Parent5": [1, 2, 3]
},
"GroupC": {
"Parent7": [1, 2, 3]
}
}
Now i want to filter this object by searching the name of the Parent
For example when I search parent1 the result should be
{
"GroupA": {
"Parent1": [1, 2, 3],
"Parent12": [1, 2, 3]
},
"GroupB": {
"Parent13": [1, 2, 3],
}
}
Here is my solution but it's not working correctly if a Group has many similar Parent name it only return the first one. And when I try to set state it filter like all wrong value
let newData = []
let catalogArr = Object.entries(catalogList)
const handleSearchElement = (e) => {
const value = e.target.value
catalogArr.forEach(catalog => {
let filteredKeys = Object.keys(catalog[1]).filter(name => name.toLowerCase().includes(value.toLowerCase()))
let valuesOfKey
if(filteredKeys[0]) {
valuesOfKey = {
[filteredKeys[0]]: Object.values(catalog[1][filteredKeys[0]])
}
newData.push([catalog[0], {...valuesOfKey}])
}
})
console.log(Object.fromEntries(newData));
setCatalogList(Object.fromEntries(newData))
// console.log(catalogList);
}
You can use Array#reduce to accomplish this pretty easily, however, all of the packing and unpacking of objects using Object.entries and Object.fromEntries to essentially treat them as arrays suggests you may be using the wrong data structure.
If you need to do this repeatedly, look into doing a one-off transformation that arranges the data for O(1) access, for example, by grouping on inner keys rather than outer keys (hard to say since I don't know the data or use case). Or, if you're mostly iterating, consider using arrays.
const data = {
"GroupA": {
"Parent1": [1, 2, 3],
"Parent2": [1, 2, 3],
"Parent12": [1, 2, 3]
},
"GroupB": {
"Parent13": [1, 2, 3],
"Parent5": [1, 2, 3]
},
"GroupC": {
"Parent7": [1, 2, 3]
}
};
const targetKey = "parent1";
const res = Object.entries(data).reduce((a, [k, v]) => {
const filtered = Object.entries(v).filter(([k, ]) =>
k.toLowerCase().includes(targetKey.toLowerCase())
);
if (filtered.length) {
a[k] = Object.fromEntries(filtered);
}
return a;
}, {});
console.log(res);
I want to separate a React-Redux API such that I can display two or more columns from the mapped data in the array. I have tried a variety of answers to no avail.
I have tried using the Math.floor method to no avail, and it pops up an error. How can I separate an array, in this case this.props.abouts, into two equal parts?
{
this.props.abouts.map(about =>(
<div key = {about.id}>
<h5>{about.title}</h5>
<p>{about.text}</p>
</div>
))
}
I would like to display the data from the array given above, i.e. this.props.abouts in two different columns.
You could use zip to create columned array from a flat array:
const array = [1, 2, 3, 4, 5, 6, 7, 8];
const zip = (a, ...args) =>
a.map((a, i) => [a].concat(args.map(b => b[i])));
const twoColumned = zip(array, array.slice(1)) //create [[1,2],[2,3],...]
.filter((_, i) => i % 2 === 0); //only even items of array
const threeColumned = zip(
array,
array.slice(1),
array.slice(2)
) //create [[1,2,3],[2,3,4],...]
.filter((_, i) => i % 3 === 0); //only even items of array
console.log('two colums', twoColumned);
console.log('three colums', threeColumned);
You can then generalize the columned logic in a function:
const array = [1, 2, 3, 4, 5, 6, 7, 8];
const zip = (a, ...args) =>
a.map((a, i) => [a].concat(args.map(b => b[i])));
const columned = columns => array =>
zip(
...[...new Array(columns)].map((_, i) => array.slice(i))
).filter((_, i) => i % columns === 0);
const twoColumned = columned(2);
const threeColumned = columned(3);
console.log('two colums', twoColumned(array));
console.log('three colums', threeColumned(array));
Before displaying your data you can divide your array into two parts and store those values in different variables.
Like the below example.
const list = [1, 2, 3, 4, 5, 6];
const middleIndex = Math.ceil(list.length / 2);
const firstHalf = list.splice(0, middleIndex);
const secondHalf = list.splice(-middleIndex);
console.log(firstHalf); // [1, 2, 3]
console.log(secondHalf); // [4, 5, 6]
console.log(list); // []
Suppose I have an array arr with several elements. I want to create an array of groups of elements of arr (array of arrays), in which each group is composed of the next element that matched some condition fn and every next element in sequence until the next match.
So I want to kinda slice the array in groups starting by matching elements.
I made the following code to do it, but it's too imperative to me:
var sliceGroupingBy = (arr, fn) => {
var newArray = [];
arr.forEach(el => {
if (fn(el)) {
newArray.push([el]);
} else {
newArray.slice(-1)[0].push(el);
}
});
return newArray;
};
Example:
var in = [1, 2, 4, 6, 3, 4, 6, 5, 7, 8, 8, 1];
var out = sortaGroupBy(in, x => x % 2 === 1);
// [ [ 1, 2, 4, 6 ], [ 3, 4, 6 ], [ 5 ], [ 7, 8, 8 ], [ 1 ] ]
I wonder what's the more functional way to do it, using the regular functional operations only (no if or aux. array).
You can always make it more functional by using reduce instead of some imperative looping:
function sliceGroupingBy(arr, fn) {
return arr.reduce((newArray, el) => {
if (fn(el))
newArray.push([el]);
else
newArray[newArray.length-1].push(el);
return newArray;
}, []);
}
If you also want to avoid the push and, for whatever reasons, statements at all, you can concat:
const sliceGroupingBy = (arr, fn) =>
arr.reduce((newArray, el) =>
fn(el)
? newArray.concat([[el]]);
: newArray.slice(0, -1).concat(newArray.slice(-1).map(lastArray =>
lastArray.concat([el])
)
, []);
("altering" the last element of the array could be done in a myriad of ways)
Grossly inefficient but:
let predicate = x => x % 2 === 1;
let partition = (pred, arr) => {
let res1 = arr.filter(pred);
let res2 = arr.filter(x => !pred(x));
return [res1, res2];
};
partition(predicate, [1,2,3,...]);
I'd never do it that way in JavaScript though (assume from the code that's the language in question). See my comments on your question.
EDIT
Per the comment that I was wrong about what you're doing,
let xs = array.reduce((acc, x, i, arr) => {
let lastIndex = acc.reduce((y, z) => { y + z.length }, 0);
return predicate(x) || i === arr.length - 1 ?
acc.concat([arr.slice(lastIndex, i)]) :
acc;
}, []);
Uses no statements, only expressions, no mutation, only copying. I still wouldn't do this without using immutable.js or mori. Its rather expensive.
EDIT 2
More efficient version of the last approach based on comment from Bergi:
let {result} = array.reduce((obj, x, i, arr) => {
let {lastIndex, result} = obj;
let passes = predicate(x) || i === arr.length - 1;
return {
lastIndex: passes ? i : lastIndex,
result: passes ? result.concat([arr.slice(lastIndex, i)]) : result
};
}, { lastIndex: 0, result: [] });
I have a Flux Store and a state array that needs updating when a new comment is created so that a list of comments updates in the view. I just want to confirm that I am updating it correctly using push:
this.state.comments.push(commentArray);
It works fine but I have read about immutability but as this is a store and not a view I take it this is ok?
onDispatcherAction: function (payload) {
var action = payload.action;
if (ActionTypes.CREATE_CONFIGURATION_SETTINGS_RESPONSE === action.type) {
this.handleResponseErrors(action.data);
var commentArray = {
_id: action.data._id,
user: {
id: action.data.user.id
},
id:action.data.id,
commentname: action.data.commentname,
timeCreated: action.data.timeCreated
}
this.state.commentname = action.data.commentname;
this.state.comments.push(commentArray);
this.emitChange();
}
}
You probably should take a look to the Immutability Helpers.
From React Documentation
Simple push
var initialArray = [1, 2, 3];
var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]
initialArray is still [1, 2, 3].