I have designed a table which will read a object array and a dropdown list for ordering control.
However, when I select other ordering value in dropdown list. The front end table did not update at the same time. It will have a delay, please see the following example.
T0: default select order by "name" -> front end correct(Order by "name")
T1: select order by "age" -> front-end no update (still order by "name")
T2: select order by "name" -> front-end update (order by "age")
T3: select order by "age" -> front-end update (order by "name")
My object array
var data = [
{
key: 1,
name: 'AAA',
age: '10',
},
{
key: 2,
name: 'BBB',
age: '8',
},
{
key: 3,
name: 'name',
age: '12',
},
]
const [listData, setListData] = useState(data);
Drop down control
const handleOrderChange = (value) => {
setOrderValue(value);
};
useEffect(() => {
console.log(orderValue.value); //match what I click
switch (orderValue.value) {
case 'name':
listData.sort((a, b) => (a.name > b.name ? 1 : -1));
break;
case 'age':
listData.sort((a, b) => (a.age> b.age? 1 : -1));
break;
default:
console.log('Default');
}
console.log(listData); //match what I expected
}, [orderValue]);
Front-End
{/* Data */}
{listData.map((item) => (
<DataDetail
key={item.key}
name={item.name}
age={item.age}
></DataDetail>
))}
You should never mutate a state variable as this:
switch (orderValue.value) {
case 'name':
listData.sort((a, b) => (a.name > b.name ? 1 : -1));
break;
case 'age':
listData.sort((a, b) => (a.age> b.age? 1 : -1));
break;
default:
console.log('Default');
}
instead you should use:
useEffect(() => {
switch (orderValue.value) {
case 'name':
const listDataCopy = [...listData]
listDataCopy.sort((a, b) => (a.name > b.name ? 1 : -1));
setListData(listDataCopy)
break;
case 'age':
const listDataCopy = [...listData]
listDataCopy.sort((a, b) => (a.age> b.age? 1 : -1));
setListData(listDataCopy)
break;
default:
console.log('Default');
}
}, [orderValue, listData, setListData]);
Related
I have a requirement where the array of objects needs to be sorted on certain keys. The keys with which it needs to be sorted is dynamic and it is Not fixed.
I came across array-sort in npm library. Using that, am able to sort on multiple keys but it sorts only on ascending order.
const input = [{id:'1',name:'John',city:'Denver',State:'CO'},
{id:'2',name:'Smith',city:'San Fransisco',State:'CA'},
{id:'3',name:'Adam',city:'Concord',State:'CA'},
{id:'1',name:'John',city:'Concord',State:'CA'}]
I want to sort on State (asc), city (asc) and id (desc). My output should look like
[
{id:'3',name:'Adam',city:'Concord',State:'CA'},
{id:'1',name:'John',city:'Concord',State:'CA'},
{id:'2',name:'Smith',city:'San Fransisco',State:'CA'},
{id:'1',name:'John',city:'Denver',State:'CO'}]
Can anyone please let me know how i can implement sorting on descending using array-sort
Thanks
Maybe you want a JavaScript function like this?
function multicolumnSort(data, orders) {
return data.sort((e1, e2) => {
for (var i = 0; i < orders.length; i++)
if (e1[orders[i].column] != e2[orders[i].column])
return orders[i].desc ^ e2[orders[i].column] < e1[orders[i].column]? 1 : -1;
return 0;
});
}
Then, you may call the function with your order keys:
let orders = [
{
column: 'State'
},
{
column: 'city'
},
{
column: 'id',
desc: true
}
];
let result = multicolumnSort(input, orders);
Check my code
function DESC(i, ii) { // DESC
return (i[key] > ii[key]) ? -1 : ((i[key] < ii[key]) ? 1 : 0);
}
function ASC(i, ii) { // ASC
return (i[key] > ii[key]) ? 1 : ((i[key] < ii[key]) ? -1 : 0);
}
function StartSort(data, myArray, order) {
// data - row for sorting, array - array fo sorting, order - order of sorting
key = data;
arr = myArray;
if (order.toUpperCase() == "ASC") {
sortedArray = arr.sort(ASC);
} else {
sortedArray = arr.sort(DESC);
}
return sortedArray;
}
//sorting started
const input = [{
id: '1',
name: 'John',
city: 'Denver',
State: 'CO'
},
{
id: '2',
name: 'Smith',
city: 'San Fransisco',
State: 'CA'
},
{
id: '3',
name: 'Adam',
city: 'Concord',
State: 'CA'
},
{
id: '1',
name: 'John',
city: 'Concord',
State: 'CA'
}
]
let output1 = StartSort('state', input, 'ASC');
output1 = StartSort('city', output1, 'ASC');
output1 = StartSort('id', output1, 'DESC');
console.log(output1);
i have an array, where all data is calculated by records from matches table:
Illuminate\Support\Collection {#1342 ▼
#items: array:4 [▼
"First team" => & array:6 [▼
"points" => 3
"scoredGoals" => 6
"goalsConceded" => 6
"wins" => 0
"loses" => 0
"draws" => 3
]
"Second team" => array:6 [▶]
"third team" => array:6 [▶]
"fourth team" => & array:6 [▶]
]
}
i need add to array image of each team (from teams table, where column image)
how can i do that?
here is my code from controller, where all data is calculated from matches table:
there is my code which i need edit:
$standings = [];
$blank = [
'points' => 0,
'scoredGoals' => 0,
'goalsConceded' => 0,
'wins' => 0,
'loses' => 0,
'draws' => 0,
];
$matches = Match::with('score', 'homeTeam', 'awayTeam')
->whereHas('score', function($query){
$query->whereNotNull('home_team_score')
->whereNotNull('away_team_score');
})
->where('league_id', '=', $league->id)
->get();
foreach ($matches as $match) {
$homeTeamScore = $match->score->home_team_score;
$awayTeamScore = $match->score->away_team_score;
if (! isset($standings[$match->homeTeam->name])) {
$standings[$match->homeTeam->name] = $blank;
}
if (! isset($standings[$match->awayTeam->name])) {
$standings[$match->awayTeam->name] = $blank;
}
$home = &$standings[$match->homeTeam->name];
$away = &$standings[$match->awayTeam->name];
$away['scoredGoals'] += $awayTeamScore;
$home['scoredGoals'] += $homeTeamScore;
$away['goalsConceded'] += $homeTeamScore;
$home['goalsConceded'] += $awayTeamScore;
switch ($homeTeamScore <=> $awayTeamScore) {
case -1:
// home lost
// swap home and away and let it fall through
$tmpHome = &$home;
$home = &$away;
$away = &$tmpHome;
case 1:
// home won
$home['points'] += 3;
$home['wins']++;
$away['loses']++;
break;
default:
// draw
$home['points']++;
$away['points']++;
$home['draws']++;
$away['draws']++;
}
}
$standings = collect($standings)->sort(function ($one, $other) {
if ($one['points'] !== $other['points']) {
return $other['points'] - $one['points']; // similar to desc
}
$oneDelta = $one['scoredGoals'] - $one['goalsConceded'];
$otherDelta = $other['scoredGoals'] - $other['goalsConceded'];
return $otherDelta - $oneDelta; // similar to desc
});
return view('admin.leagues.standings')->with([
'standings' => $standings,
]);
Going with the key of each element in your collection is the name of your team and is stored in the name column of your teams table, you can map over your collection and add in your image.
For example:
$images = [
'First team' => 'first-team.jpg',
'Second team' => 'second-team.jpg',
'Third team' => 'third-team.jpg'
];
$teamsWithImages =
collect([
"First team" => [
"points" => 3,
"scoredGoals" => 6,
"goalsConceded" => 6,
"wins" => 0,
"loses" => 0,
"draws" => 3,
],
"Second team" => [
"points" => 3,
"scoredGoals" => 6,
"goalsConceded" => 6,
"wins" => 0,
"loses" => 0,
"draws" => 3,
],
"Third team" => [
"points" => 3,
"scoredGoals" => 6,
"goalsConceded" => 6,
"wins" => 0,
"loses" => 0,
"draws" => 3,
]
])->map(function ($item, $key) use ($images) {
// You would uncomment this line to retrieve the image
// from your teams table
// You also wouldn't need the use ($images) either
//$item['image'] = Teams::where('name', $key)->first()->image;
$item['image'] = $images[$key];
return $item;
})->all();
dump($teamsWithImages);
Update
Based on the code you've added, you won't need to map you can just add the image in your foreach:
if (! isset($standings[$match->homeTeam->name])) {
$standings[$match->homeTeam->name] = $blank;
$standing[$match->homeTeam->name]['image'] = $match->homeTeam->image;
}
if (! isset($standings[$match->awayTeam->name])) {
$standings[$match->awayTeam->name] = $blank;
$standing[$match->awayTeam->name]['image'] = $match->awayTeam->image;
}
Alternatively you could still use map once you have the standings sorted, but you may as well just add the image in with everything else.
$standingsWithImages = $standings
->map(function ($item, $key) {
$item['image'] = Team::where('name', $key)->first()->image;
return $item;
})->all();
I'm retrieving the data from the radio button checked for database purposes and I wanted to check the string objects index are equal to the api response string object from the db. The user can select the radio button in any order, but finally I wanted to sort the radio button with respect to get api response
Since, I'm new to react, I am trying to start off with...
I have attached the response below
data:
matrix:
option_questions: Array(10)
0: {text: "Hai"}
1: {text: "Hello"}
2: {text: "Hola"}
options: Array(10)
0: {text: "1"}
1: {text: "2"}
2: {text: "3"}
After checking the radio button values, my array goes likes this...
0:
id: "3"
qn: "Hello"
1:
id: "1"
qn: "Hola"
2:
id: "2"
qn: "Hai"
Here, I have to rearrange the array using the qn object index only like below format..
0:
id: "2"
qn: "Hai"
1:
id: "3"
qn: "Hello"
2:
id: "1"
qn: "Hola"
This is my code for on change
changeRadioHandler = (event) => {
const qn = event.target.name;
const id = event.target.value;
const question = {
id: event.target.value,
qn
};
if (this.state.questions.some((question) => question.qn === qn)) {
questions = [
...this.state.questions.filter((question) => question.qn !== qn),
question,
];
} else {
questions = [...this.state.questions, question];
}
const comparator = (a, b) => a.qn.localCompare(b.qn);
console.log(questions.sort(comparator), "comparator");
questions.sort(comparator);
this.setState({ questions });
console.log(questions);
};
Create a comparator function to compare the qn properties of each element and do a localeCompare comparison.
const comparator = (a, b) => a.qn.localeCompare(b.qn);
const data = [
{
id: "3",
qn: "Hello"
},
{
id: "1",
qn: "Hola"
},
{
id: "2",
qn: "Hai"
},
];
const comparator = (a, b) => a.qn.localeCompare(b.qn);
console.log(data.sort(comparator));
This is the case: Every order can contain many types, with different quantities. I want, for each order item, the total quantity for each type.
[{
"order" : 1,
"orderDetails" : [{
"quantity" : 10,
"product" : {
"productType" : "A"
},
"quantity" : 20,
"product" : {
"productType" : "A"
},
"quantity" : 10,
"product" : {
"productType" : "B"
}
}]
}]
this is my code, it does the job but I am trying to make it a bit more elegant, somehow. I am pretty sure there is redundant code there, I am not sure I am using reduce correctly
const orders = data.map(h => {
const newArray = [];
h.orderDetails_ = h.orderDetails.reduce(function(a, b, i) {
if (newArray[b.product.productType] == undefined) {
newArray[b.product.productType] = b.quantity;
return newArray;
} else {
newArray[b.product.productType] += b.quantity;
return newArray;
}
}, 0);
return h;
});
well, for anyone out there, this is the better and correct version
const orders = data.map(h => {
h.orderDetails_ = h.orderDetails.reduce((orderTotals, order) => {
orderTotals[order.product.productType] =
(orderTotals[order.product.productType] || 0) + order.quantity;
return orderTotals;
}, {});
return h;
});
I'm trying to filter my array of objects passing two parameters but it's not working... My array contain an object with the values that I'm passing on parameters but the result is empty
const item = this.lista.find(i => i.number === rule.number && i.name === rule.name);
I also tried to use "filter" but same problem...
const item = this.lista.filter(i => i.number === rule.number).filter(i =>
i.name === rule.name);
Here is my full array:
this.lista= [
{number: 0, name: 'jose'},
{number: 2, name: 'maria'},
{number: 3, name: 'martha'},
{number: 4, name: 'ana'},
{number: 4, name: 'petter'},
];
And this is the rule object:
rule = new Rule();
rule.number = 4;
rule.name = 'ana';
There's a best way to do this?
I'm not sure what the problem is in your code but I've reproduced a simple example of your code and it works just as expected.
const rule = {};
rule.number = 4;
rule.name = 'ana';
const lista = [{
number: 0,
name: 'jose'
},
{
number: 2,
name: 'maria'
},
{
number: 3,
name: 'martha'
},
{
number: 4,
name: 'ana'
},
{
number: 4,
name: 'petter'
},
];
const item = lista.find(i => i.number === rule.number && i.name === rule.name);
console.log(item);