I have problem, in the code below I'm trying to console.log only name of the playLists from state with console.log(this.state.playLists.name); I get undefined.
getPlaylist() {
spotifyApi.getUserPlaylists().then((response) => {
if (response.items) {
const items = response.items;
console.log(items);
const playListsId = items.map((obj) => {
const playList = {
name: obj.name,
id: obj.id,
};
return playList;
});
console.log(playListsId);
this.setState({
playLists: playListsId,
});
}
console.log(this.state.playLists.name);
});
}
Since this.state.playLists is an array you cannot get name on it. you have to get the name of all elements in an array.
Try this in place of console.log(this.state.playLists.name);
this.state.platLists.map(playList => console.log(playList.name));
Related
How can I get a list of cars for a customer
clients:
w21rffa3:
name: Johny
phone: 123123
cars:
fn1jnr12:
brand: AUDi
model: a6
number: 24f1
dsdasgf122:
brand: AUDi
model: a3
number: 62s14
My code
const ref = firestore().collection('clients');
const [clientsList, setClientsList] = useState([]);
useEffect(() => {
return ref.onSnapshot(clientsSnapshot => {
const clients = [];
const cars = [];
clientsSnapshot.forEach(client => {
const carsRef = ref.doc(client.id).collection('cars').onSnapshot(carsSnapshot => {
carsSnapshot.forEach(car => {
if (car.data().brand.length > 0) {
const {
brand,
model,
number
} = car.data();
cars.push({
id: car.id,
brand,
model,
number,
});
}
});
//Good result`
console.log('After forEach: ', cars);
});
//Bad result
console.log('After snapshot: ', cars);
const {
name,
phone
} = client.data();
clients.push({
id: client.id,
name,
phone,
cars: cars,
});
});
setClientsList(clients);
});
}, []);
cars list for customers
The error you facing is due to misuse/misunderstanding of how async/callback-based functions works. As I said in my comment - good result and bad result - bad result scripts are executed before good result due to onSnapshot is async, and you pass a callback function to it, which will be executed when data is available from firebase, so a bit "later" than the rest of the code.
Now about what can be done. The code is a bit tricky and I didnt really test it, so if anything - please, let me know.
const [clientsList, setClientsList] = useState([]);
useEffect(() => {
let carsUnsubscribeFns = [];
const clientUnsubscribeFn = ref.onSnapshot((clientsSnapshot) => {
// Reset everything and stop previously created listeners for Cars
setClientsList([]);
carsUnsubscribeFns.forEach((x) => x());
carsUnsubscribeFns = [];
clientsSnapshot.forEach((c) => {
const { name, phone } = c.data();
const client = { id: c.id, name, phone };
// In case you dont want to use optional chaining,
// remove the const client = ... line above
// and uncomment the line below
// but optional chaining is prefered anyway
// const client = { id: c.id, name, phone, cars: [] };
const carsUnsubscribeFn = ref
.doc(client.id)
.collection("cars")
.onSnapshot((carsSnapshot) => {
// Mutate the Client object directly
client.cars = carsSnapshot.docs
.map((x) => ({ id: x.id, ...x.data() }))
.filter((x) => x.brand?.length > 0);
// mark ClientsList as updated to force a rerender
// due to we mutated one of the entities inside
setClientsList((curr) => [...curr]);
});
carsUnsubscribeFns.push(carsUnsubscribeFn);
setClientsList((curr) => {
curr.push(client);
return [...curr];
});
});
// clean-up function returned from hook to stop all the listeners
return () => {
[clientUnsubscribeFn, ...carsUnsubscribeFns].forEach((x) => x());
};
});
}, []);
I'm trying to run a getUserName function that is being called inside an Observable pipe, map, then another map. I can return a single value but I can't seem to map the passed array to then filter out item.name if it matches the id passed in. If I show the code maybe it will be easier to understand:
Not working:
export const fetchDesignsData = (usersArray: [Users]) => (dispatch: Dispatch<Action>) => {
console.log(usersArray);
const DESIGNS_URL = `http://localhost:5000/designs`;
dispatch({
type: "FETCH_DATA_REQUEST",
});
const responsePromise = axios.get(DESIGNS_URL);
const response$ = from(responsePromise);
response$
.pipe(
map((response) => {
const newArray: { name: string; courses: number; wales: number; last_updated: string; by: any }[] = [];
response.data.map((item: { name: any; courses: any; wales: any; updated: any; user_id_last_update: any }) => {
return newArray.push({
name: item.name,
courses: item.courses,
wales: item.wales,
last_updated: item.updated,
by: getUserName(item.user_id_last_update, usersArray),
});
});
dispatch({
type: "FETCH_DATA_SUCCESS",
payload: newArray,
});
})
)
.subscribe();
};
const getUserName = (userNumber: number, usersArray: [Users]) => {
return () => {
usersArray.forEach((item) => {
if (item.id === userNumber) {
return item.name;
}
});
};
};
Basically usersArray looks like this:
[{id: 1, name: "Walter Doe"},
{id: 2, name: "John Doe"}]
so I need to map that array then see if the item.id === userNumber, if yes, return item.name. But it just returns blank every time. Probably because its inside an Observable
You need to use filter as there you need to return array which satisfy condition.
//...
const getUserName = (userNumber: number, usersArray: [Users]) => {
return () => {
usersArray.filter((item) => item.id === userNumber)
.map(item => item.name)
});
};
};
//...
This worked in the end, but it doesn't show the item.name value in my component on page load, only if I route away and come back, something to do with my useEffect and dispatch.
const getUserName = (userNumber: number, usersArray: [Users]) => {
return usersArray.filter((item) => item.id === userNumber).map((item) => item.name);
};
I was using this test when I had a bug, so I used the trim function for resolve it, and the these test fail, tried in different ways but didn't found the solution
const generalWrapper = shallow(<AddVehiclesTable {...generalProps} />)
const generalInstance = generalWrapper.instance()
describe('onSearchChange', () => {
test('should change the "search" state', () => {
const theFilterValue = 'a new filter value'
generalWrapper.find('.filter-input').simulate('change', { target: { value: theFilterValue } })
const expectedState = Object.assign({}, generalInstance.state)
expectedState.searchValue = { 'target': { 'value': theFilterValue } }
expect(generalInstance.state).toEqual(expectedState)
expect(generalInstance.state.userInteractedWithComponent).toBe(true)
})
})
onSearchChange (searchValue) {
const value = searchValue.trim()
this.setState({ searchValue: value, userInteractedWithComponent: true })
}
Error message
TypeError: searchValue.trim is not a function
Any suggestions
Your function gets the Object as a parameter.
Expose field that you needed
I don't see the whole picture, but can guess that you need something like
onSearchChange ({ target: { value: incomeValue } }) {
const value = incomeValue.trim()
this.setState({ searchValue: value, userInteractedWithComponent: true })
}
I have a unit test that is producing something I didn't expect:
Background: I'm making a simple todo list with Angular/test driven development.
Problem: When I call editTask on an item in the array, it changes the item's value. But, I don't see how it's changed in the original array because the original array is never accessed in the method I'm testing. Please help me connect HOW the original array is being changed? It seems Object.assign is doing this, but why?
describe('editTask', () => {
it('should update the task by id', () => {
const dummyTask1 = { id: 1, name: 'test', status: false };
service.tasks.push(dummyTask1); //refers to TestBed.get(TaskService)
const id = 1;
const values = { name: 'cat', status: false };
service.editTask(id, values);
console.log(service.tasks); // why does this log this object? [Object{id: 1, name: 'cat', status: false}]
expect(service.tasks[0].name).toEqual(values.name); // Test passes
});
});
Here is the method I'm testing:
editTask(id, values) {
const task = this.getTask(id);
if (!task) {
return;
}
Object.assign(task, values); //How does this line change the array?
return task;
}
getTask(id: number) {
return this.tasks.filter(task => task.id === id).pop(); //is this altering the original array somehow?
}
If needed, here's the full Angular service:
export class TaskService {
tasks: any = [];
lastId = 0;
constructor() { }
addTask(task) {
if (!task.id) {
task.id = this.lastId + 1;
}
this.tasks.push(task);
}
editTask(id, values) {
const task = this.getTask(id);
if (!task) {
return;
}
Object.assign(task, values);
return task;
}
deleteTask(id: number) {
this.tasks = this.tasks.filter(task => task.id !== id);
}
toggleStatus(task) {
const updatedTask = this.editTask(task.id, { status: !task.status});
return updatedTask;
}
getTasks() {
return of(this.tasks);
}
getTask(id: number) {
return this.tasks.filter(task => task.id === id).pop();
}
}
Here is the github repo: https://github.com/capozzic1/todo-tdd
The getTask() method is getting a reference to the item in the array using the array filter() method.
It then uses Object.assign() to change the properties of the item. The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.
So now the values of the reference in memory of the item is changed. Because it is a reference in memory you will see the original item being changed.
The below is a sample structure of the database.
root: {
users: {
user_uid_0: {
name: 'AJ',
age: 20,
gender: 'male'
}
}
}
The below is how I am fetching data from Firebase:
getData(myValue) {
// direct ref to a key of 'name' from user_uid_0
const name = firebase.database().ref('/users/user_uid_0/name');
// name will go through a listener
name.on('value', (snapshot) => {
// define myValue to the snapshot
myValue = snapshot.val()
// this.myValue = snapshot.val() tried this...
});
// spit out myValue which we defined
// myValue should be 'AJ'
// but its not... its undefined
return myValue;
// im guessing because myValue is actually not defined...
// then how do I define it with my snapshot.val()?
}
The below is a react native component that is displaying what the function is returning.
// this should return the string 'AJ' from myValue
// this returns nothing
<Text>{this.getData()}</Text>
The below is what I get when I console log.
// undefined is what I get
console.log(this.getData());
So since this wont work, what will? How can I fetch a data through ref and display it? Please help. I have been struggling with this for days.
Try something like this -
getData = async () => {
const name = firebase.database().ref('/users/user_uid_0/name');
var data = await name.once('value')
.then(snapshot => {
console.log("value", snapshot.val());
return snapshot.val();
})
.catch(e => {
console.log("firebase error", e);
return null;
});
return data;
}