Calling Find Function Twice gives undefined as output - javascript

Following code works fine the first time, It finds the correct item and changes its checked value, but if I call the same function with the same id again it returns undefined. any idea why?
This code is using in a React Native Application where the checkbox is updated using this method
CheckBox :
<CheckBox value={item.checked} key={item.id} onValueChange={setSelection} onChange={()=> {
handleChange(item.id);
}}
style={styles.checkbox}
tintColors={{ true: "#ffc324", false: "#ffc324" }}
/>
const handleChange = (id) => {
const ids = id;
let changedCheckbox = categories.find((category) => {
return category.subcategory.find((item) => {
if (item.id === ids) {
return (item.checked = !item.checked);
}
});
});
console.log(changedCheckbox);
};
This is the JSON I use
[
{
"id": 1,
"name": "MOTs",
"filename": "1610270182.png",
"bg_filename": null,
"content": "You can try this set a state like this and check if your component mounted or not. This way you are sure that if your component is unmounted you are not trying to fetch something.",
"featured": 1,
"created_at": "2021-01-10T09:16:22.000000Z",
"updated_at": "2021-01-10T09:40:37.000000Z",
"subcategory": [
{
"id": 1,
"name": "MOT1",
"category_id": 1,
"image_name": null,
"created_at": null,
"updated_at": null,
"checked": false
},
{
"id": 2,
"name": "MOT2",
"category_id": 1,
"image_name": null,
"created_at": null,
"updated_at": null,
"checked": false
},
{
"id": 3,
"name": "MOT3",
"category_id": 1,
"image_name": "1611678308.png",
"created_at": "2021-01-26T16:25:11.000000Z",
"updated_at": "2021-01-26T16:31:24.000000Z",
"checked": false
}
]
}
]

const handleChange = (id) => {
const category = categories.find(category => {
const item = category.subcategory.find(item => item.id === id);
if (item) item.checked = ! item.checked;
return !!item;
});
console.log(category)
};
Toggle checked then return boolean not checked.

change this statement
return (item.checked = !item.checked);
what you are doing when it is false it will return true, the next time its value is true so it will return false
do this instead
if (item.id===ids){
item.checked = !item.checked;
return true;
}

Related

Laravel Sorted Collection Gets Undone When Passed to Javascript [duplicate]

Here is my code :
public function list()
{
$users = User::with('group')->get()->toArray();
return response()->json([
'clients' => array_filter($users, function ($r) {
return $r['group']['name'] === 'client';
}),
'employes' => array(array_filter($users, function ($r) {
return $r['group']['name'] !== 'client';
})),
]);
}
Here is the response :
{
"clients": {
"2": {
"id": 3,
"name": "Client 1",
"email": "client#a.fr",
"email_verified_at": null,
"created_at": null,
"updated_at": null,
"group_id": 4,
"group": {
"id": 4,
"name": "client"
}
},
"3": {
"id": 4,
"name": "Client 2",
"email": "client2#a.fr",
"email_verified_at": null,
"created_at": null,
"updated_at": null,
"group_id": 4,
"group": {
"id": 4,
"name": "client"
}
},
"4": {
"id": 5,
"name": "Client 3",
"email": "client3#a.fr",
"email_verified_at": null,
"created_at": null,
"updated_at": null,
"group_id": 4,
"group": {
"id": 4,
"name": "client"
}
}
},
"employes": [
[
{
"id": 1,
"name": "Alexis",
"email": "alexis#a.fr",
"email_verified_at": null,
"created_at": null,
"updated_at": null,
"group_id": 1,
"group": {
"id": 1,
"name": "admin"
}
},
{
"id": 2,
"name": "guest",
"email": "guest#a.fr",
"email_verified_at": null,
"created_at": null,
"updated_at": null,
"group_id": 2,
"group": {
"id": 2,
"name": "guest"
}
}
]
]
}
I tried to change the conditions of the array_filter. Sometimes I have an array, sometimes I have an object. I don't understand how this is determined
Stackoverflow tells me "It looks like your post is mostly code; please add some more details." So ... what details to add?
Thank you
Internally array_filter() filters matching entries from the array, and returns them with their indices intact. This is very important, as it is the core reason you're getting an object and not an array in JavaScript.
In PHP, this is fine; arrays can start at 0, or another index, such as 2, and function as an array without issue. This is due to the existence of indexed (0-based) and associative (numeric/non-numeric key based) arrays.
In JavaScript, arrays cannot be "associative", i.e. they must start at 0. object classes on the other hand function similarly to associative arrays, but the key difference is that they aren't explicitly arrays.
Now that you know the why, the next question is "how do I fix this?" The simple method is to wrap array_filter() with a function that simply returns the values of the new array. This inherently will "re-index" the array with 0-based values, which when converted to JSON will result in correct arrays being returned:
$users = User::with('group')->get()->toArray();
$clients = array_filter($users, function($r){
return $r['group']['name'] === 'client';
});
$groups = array_filter($users, function ($r) {
return $r['group']['name'] !== 'client';
});
return response()->json([
'clients' => array_values($clients),
'groups' => array_values($groups)
]);
As a sidenote, Collection classes have similar logic, and I prefer to use Laravel's Collection class whenever possible:
$users = User::with('group')->get();
$clients = $users->filter(function($r){
$r->group->name === 'client';
});
$groups = $users->filter(function($r){
$r->group->name !== 'client';
});
return response()->json([
'clients' => $clients->values(),
'groups' => $groups->values()
]);
But again, that's my preference; either approach should work, so use what you're used to.
References:
PHP Array Methods:
https://www.php.net/manual/en/function.array-filter.php
https://www.php.net/manual/en/function.array-values.php
Laravel Collection Methods:
https://laravel.com/docs/5.8/collections#method-filter
https://laravel.com/docs/5.8/collections#method-values
This works for me. I hope this will help anyone.
return response(['STATUS'=>'true','message'=>'Your Message','response'=>
array_values('clients' => array_filter($users, function ($r) {
return $r['group']['name'] === 'client';
})),
'employes' => array_values(array_filter($users, function ($r) {
return $r['group']['name'] !== 'client';
}))
)]);
If in response array you will get a result like an index key and you want the response in object array [{ ... }] then use array_values() will resolve your problem.
"clients": {
"2": {
"id": 3,
"name": "Client 1",
"email": "client#a.fr",
"email_verified_at": null,
"created_at": null,
"updated_at": null,
"group_id": 4,
"group": {
"id": 4,
"name": "client"
}
},
simply add ->values() it will reorder array keys
users = User::with('group')->values();

State in React Native Class Component won't update when I update object in array

I'm using React Navigation to send the array additional in the DisplayItem screen, I use componentDidMount to set the state with the array and I use SectionList to display the array, the goal is to use the function pressOptional to update the value selected in the array, It works at the moment, but the problem is that it doesn't update the state in real-time, the changes in SectionList happen only when I re-render the screen.
Array: additional
Array [
Object {
"data": Array [
Object {
"id": 0,
"price": 1,
"selected": true,
"title": "Ranch",
"type": "Sides",
},
Object {
"id": 1,
"price": 1,
"selected": false,
"title": "Blue Cheese",
"type": "Sides",
},
],
"id": 0,
"required": false,
"title": "Sides",
},
Object {
"data": Array [
Object {
"id": 0,
"price": 0,
"selected": false,
"title": "Hot Sauce",
"type": "Sauces",
},
Object {
"id": 1,
"price": 0,
"selected": false,
"title": "Medium Sauce",
"type": "Sauces",
},
],
"id": 1,
"required": true,
"title": "Sauces",
},
]
Screen
class DisplayItem extends Component {
constructor(props) {
super(props);
this.state = {
additional: [],
}
}
componentDidMount() {
const { item } = this.props.route.params;
const additional = item.additional;
if (additional !== undefined) {
this.setState({additional:[...additional]})
}
}
pressOptional = (e) => {
const additional = this.state.additional;
additional.map((item) => {
if (item.title == e.type) {
item.data.map((item) => {
if (item.id == e.id) {
item.selected = !e.selected
}
})
}
})
}
render() {
const { additional } = this.state;
return (
<View>
<SectionList
sections={additional}
keyExtractor={(item, index) => item + index}
renderSectionHeader={({ section: { type, required } }) => (
<View>
<Text>{type}</Text>
</View>
)}
renderItem={({ item, section: { required } }) => {
return (
<TouchableOpacity key={item.id} onPress={() => this.pressOptional(item)}>
<Ionicons
name={item.selected == false ? 'square-outline' : 'square'}
/>
<Text>{item.title}</Text>
<Text>${item.price}</Text>
</TouchableOpacity>
)
}
}
/>
</View>
)
}};
export default DisplayItem;
Try to use useState instead State classes:
https://reactnative.dev/docs/state

Can't setState in react handleClick

I am unable to setState in handleClick function for this App.
App is working very simple, it has a data that has an entry point in forest from there it just goes thru props till it gets to Tree component where divides to Children and Datum there it has a Collapsible that takes care of the expanding logic.
Now,
I just want to mutate state I have done many copies of that state with JSON.parse(JSON.Stringify())) used Lodash for deep copy, everything works expect that copied and mutated state just doesn't want to set into setState so I can't get it to circular working.
I just want to have a unidirectional data flow, but the 'setState' just doesn't work.
The function that mutates the state mutateState takes as arguments a forest a node.id a patch or get as a string value. I have tested it million times and it works, this function mutates the state via recursion. One thing maybe it has a problem that it doesn't return anything, even if it doesn't return it still doesn't want to set that 'setState'.
I have also used debugger million times and didn't find any clue. Please I need some help.
thank you.
import "./App.css";
import { useState, useEffect, useContext, createContext } from "react";
import React from "react";
import data from "./data.json";
import _ from "lodash";
function App() {
const [state, setState] = useState(data.data);
function mutateState(forest, nodeId, getOrPatch) {
let result;
forest.forEach(function (tree) {
if (tree.id === nodeId && getOrPatch === "patch") {
tree.toggle === true ? (tree.toggle = false) : (tree.toggle = true);
} else if (tree.id === nodeId && getOrPatch === "get") {
return (result = tree.toggle);
}
helper(tree);
});
function helper(tree) {
if (tree.children !== null) {
tree.children.forEach(function (tree) {
if (tree.id === nodeId && getOrPatch === "patch") {
tree.toggle === true ? (tree.toggle = false) : (tree.toggle = true);
} else if (tree.id === nodeId && getOrPatch === "get") {
return (result = tree.toggle);
}
helper(tree);
});
}
}
return result;
}
function Forest({ root }) {
return root.map((tree) => <Tree root={tree} key={tree.id} />);
}
function Tree({ root }) {
if (root.children !== null) {
return <Children key={root.id} node={root} />;
} else {
return <Datum key={root.id} node={root} />;
}
}
function Collapsible(props) {
return (
<ul>
<button onClick={props.handleClick} className="btn">
<li>{props.datum}</li>
</button>
{props.isExpanded ? props.children : ""}
</ul>
);
}
function Children({ node }) {
const [isExpanded, setIsExpanded] = useState(false);
let stateCopy = _.cloneDeep(state)
function handleClick() {
mutateState(stateCopy, node.id,'patch')
setState(stateCopy)
isExpanded ? setIsExpanded(false) : setIsExpanded(true);
}
return (
<Collapsible
datum={node.datum}
handleClick={handleClick}
isExpanded={isExpanded}
>
{node.children.map((tree) => (
<Tree key={tree.id} root={tree} />
))}
</Collapsible>
);
}
function Datum({ node }) {
return <li>{node.datum}</li>;
}
return (
<div className="App">
<header className="App-header">
<Forest root={state} />
</header>
</div>
);
}
export default App;
data JSON
{
"data": [
{
"datum": "String",
"id": 1,
"toggle": false,
"children": [
{
"datum": "String",
"id": 2,
"toggle": false,
"children": [
{
"datum": "String",
"id": 3,
"toggle": false,
"children": []
}
]
},
{
"datum": "String",
"id": 4,
"toggle": false,
"children": []
}
]
},
{
"datum": "String",
"id": 5,
"toggle": false,
"children": [{
"datum": "String",
"id": 6,
"children": []
}]
},
{
"datum": "String",
"id": 7,
"toggle": false,
"children": [
{
"datum": "String",
"id": 8,
"toggle": false,
"children": [
{
"datum": "String",
"id": 9,
"toggle": false,
"children": [
{
"datum": "String",
"id": 10,
"toggle": false,
"children": [
{
"datum": "String",
"id": 11,
"toggle": false,
"children": []
}
]
}
]
},
{
"datum": "String",
"id": 12,
"toggle": false,
"children": [
{
"datum": "String",
"id": 13,
"toggle": false,
"children": []
}
]
}
]
},
{
"datum": "String",
"id": 14,
"toggle": false,
"children": []
}
]
}
]
}

Partial selection on Inner Join

I need select ony on field to services, look:
async find(): Promise<AccountEntity[]> {
const result = await this.repository
.createQueryBuilder("account")
.select(['account', 'accountServices', 'service.description'])
.leftJoinAndSelect("account.accountAndServices", "accountServices")
.leftJoinAndSelect("accountServices.service", "service")
.getMany();
return result === undefined ? null : result;
}
How to ? please.
I don't want null attributes to appear and I also want to choose which attributes to show
I need :
{
"message": "",
"success": true,
"data": [
{
"id": 1,
"name": "STONES TECNOLOGIA LTDA",
"accountAndServices": [
{
"service": {
"name": "Construção de uma casa",
},
"date_initial": "2021-08-01T07:39:18.000Z",
"date_final": "2021-08-01T07:39:20.000Z",
"value": "10.00",
"created_by": 1,
"is_active": true,
"id": 1,
"pay_day": 10,
"nfse": 0,
"created_at": "2021-08-01T07:39:27.000Z",
},
{
"service": {
"name": "Desenvolvimento de sistemas",
},
"date_initial": "2021-08-01T07:40:01.000Z",
"date_final": "2021-08-01T07:40:02.000Z",
"value": "20.00",
"created_by": 1,
"is_active": true,
"id": 2,
"pay_day": 20,
"nfse": 0,
"created_at": "2021-08-01T07:40:11.000Z",
}
]
}
],
"errors": null
}
I Need selection only field on entity join.
Select with innerJoin you must use addSelect(...).
The find function must not manipulate any data and should return an array of AccountEntity (empty if not found):
function find(): Promise<AccountEntity[]> {
return this.repository
.createQueryBuilder("a")
.innerJoin("account.accountAndServices", "as")
.innerJoin("accountServices.service", "s")
.select(['a.id', 'a.name', 'a.status'])
.addSelect(['as.date_initial', 'as.date_final', 'as.service_id', 'as.value', 'as.nfse', 'as.value', 'as.created_by', 'is_active', 'pay_day', 'created_at'])
.addSelect(['s.name'])
.getMany();
}
Note that to obtain the result from the function you must use await.
Moreover, surround it with try and catch for a better error handling.
Example:
try {
const accounts: AccountEntity[] = await find();
} catch(error) {
console.error(`Error: ${error}`);
}
To transform the array of AccountEntity to another object:
function transform(accounts?: AccountEntity[]) {
return {
message: "",
success: accounts !== undefined,
data: accounts,
errors: null
};
}

Laravel - why json response return sometimes an array sometimes an object

Here is my code :
public function list()
{
$users = User::with('group')->get()->toArray();
return response()->json([
'clients' => array_filter($users, function ($r) {
return $r['group']['name'] === 'client';
}),
'employes' => array(array_filter($users, function ($r) {
return $r['group']['name'] !== 'client';
})),
]);
}
Here is the response :
{
"clients": {
"2": {
"id": 3,
"name": "Client 1",
"email": "client#a.fr",
"email_verified_at": null,
"created_at": null,
"updated_at": null,
"group_id": 4,
"group": {
"id": 4,
"name": "client"
}
},
"3": {
"id": 4,
"name": "Client 2",
"email": "client2#a.fr",
"email_verified_at": null,
"created_at": null,
"updated_at": null,
"group_id": 4,
"group": {
"id": 4,
"name": "client"
}
},
"4": {
"id": 5,
"name": "Client 3",
"email": "client3#a.fr",
"email_verified_at": null,
"created_at": null,
"updated_at": null,
"group_id": 4,
"group": {
"id": 4,
"name": "client"
}
}
},
"employes": [
[
{
"id": 1,
"name": "Alexis",
"email": "alexis#a.fr",
"email_verified_at": null,
"created_at": null,
"updated_at": null,
"group_id": 1,
"group": {
"id": 1,
"name": "admin"
}
},
{
"id": 2,
"name": "guest",
"email": "guest#a.fr",
"email_verified_at": null,
"created_at": null,
"updated_at": null,
"group_id": 2,
"group": {
"id": 2,
"name": "guest"
}
}
]
]
}
I tried to change the conditions of the array_filter. Sometimes I have an array, sometimes I have an object. I don't understand how this is determined
Stackoverflow tells me "It looks like your post is mostly code; please add some more details." So ... what details to add?
Thank you
Internally array_filter() filters matching entries from the array, and returns them with their indices intact. This is very important, as it is the core reason you're getting an object and not an array in JavaScript.
In PHP, this is fine; arrays can start at 0, or another index, such as 2, and function as an array without issue. This is due to the existence of indexed (0-based) and associative (numeric/non-numeric key based) arrays.
In JavaScript, arrays cannot be "associative", i.e. they must start at 0. object classes on the other hand function similarly to associative arrays, but the key difference is that they aren't explicitly arrays.
Now that you know the why, the next question is "how do I fix this?" The simple method is to wrap array_filter() with a function that simply returns the values of the new array. This inherently will "re-index" the array with 0-based values, which when converted to JSON will result in correct arrays being returned:
$users = User::with('group')->get()->toArray();
$clients = array_filter($users, function($r){
return $r['group']['name'] === 'client';
});
$groups = array_filter($users, function ($r) {
return $r['group']['name'] !== 'client';
});
return response()->json([
'clients' => array_values($clients),
'groups' => array_values($groups)
]);
As a sidenote, Collection classes have similar logic, and I prefer to use Laravel's Collection class whenever possible:
$users = User::with('group')->get();
$clients = $users->filter(function($r){
$r->group->name === 'client';
});
$groups = $users->filter(function($r){
$r->group->name !== 'client';
});
return response()->json([
'clients' => $clients->values(),
'groups' => $groups->values()
]);
But again, that's my preference; either approach should work, so use what you're used to.
References:
PHP Array Methods:
https://www.php.net/manual/en/function.array-filter.php
https://www.php.net/manual/en/function.array-values.php
Laravel Collection Methods:
https://laravel.com/docs/5.8/collections#method-filter
https://laravel.com/docs/5.8/collections#method-values
This works for me. I hope this will help anyone.
return response(['STATUS'=>'true','message'=>'Your Message','response'=>
array_values('clients' => array_filter($users, function ($r) {
return $r['group']['name'] === 'client';
})),
'employes' => array_values(array_filter($users, function ($r) {
return $r['group']['name'] !== 'client';
}))
)]);
If in response array you will get a result like an index key and you want the response in object array [{ ... }] then use array_values() will resolve your problem.
"clients": {
"2": {
"id": 3,
"name": "Client 1",
"email": "client#a.fr",
"email_verified_at": null,
"created_at": null,
"updated_at": null,
"group_id": 4,
"group": {
"id": 4,
"name": "client"
}
},
simply add ->values() it will reorder array keys
users = User::with('group')->values();

Categories