map array to another array in TypeScript - reactive

Can I improve my code and replace for-loop by array.map?
I searched and I think I could do that but I didn't find how could I apply that.
This is what I found :
var result = arr.map(person => ({ value: person.id, text: person.name }));
And my code is here:
public getFlights(): Observable<RowItem[]> {
return this.http
.get(this.apiHostFlights)
.map((res: any) => {
return <LocationModelItem[]>res.json();
})
.map((items: LocationModelItem[]) => {
var rowItems: RowItem[]=[];
var cachedLenght = items.length;
for (var i = 0; i < cachedLenght; i++) {
rowItems.push(
new RowItem(i, items[i].name, items[i].img, items[i].category)
);
}
return rowItems;
})
.catch((error: any) => {
return Observable.throw(error.statusText);
});
}

public getFlights(): Observable<RowItem[]> {
return this.http
.get(this.apiHostFlights)
.map((res: any) => {
return <LocationModelItem[]>res.json();
})
.map((items: LocationModelItem[]) => {
return items.map((item, index) => ({
index: index,
name: item.name,
img: item.img,
category: item.category)
}))
})
.catch((error: any) => {
return Observable.throw(error.statusText);
});
}
This should do it hopefully

Related

Redux toolkit createAsyncThunk using Parameter

I need your help.
We implemented createAsyncThunk using the Redux Toolkit.
However, as shown in the picture, I need a function to change ChannelId flexibly. Can't I use the parameter in createAsyncThunk?
How can I use it if I can?
Or is there any other way?
I am sorry that the quality of the question is low because I am Korean using a translator.
enter image description here
// ACTION
export const getYoutubeList_PlayList = createAsyncThunk(
"GET/YOUTUBE_PLAYLIST",
async (data, thunkAPI) => {
try {
const { data } = await axios.get<youtubeResponse>(
`https://www.googleapis.com/youtube/v3/playlists?key=${youTubeAcsses.apiKey}&channelId=${channelId}&part=snippet&maxResults=30`
)
return data
} catch (err: any) {
return thunkAPI.rejectWithValue({
errorMessage: '호출에 실패했습니다.'
})
}
}
);
// SLICE
const youtube_PlaylistSlice = createSlice({
name: "YOUTUBE_PLAYLIST",
initialState,
reducers: {},
// createAsyncThunk 호출 처리 = extraReducers
extraReducers(builder) {
builder
.addCase(getYoutubeList_PlayList.pending, (state, action) => {
state.loading = true;
})
.addCase(getYoutubeList_PlayList.fulfilled, (state, action: PayloadAction<youtubeResponse>) => {
state.loading = false;
state.data = action.payload;
})
.addCase(getYoutubeList_PlayList.rejected, (state, action: PayloadAction<any>) => {
state.error = action.payload;
});
},
});
You named both the incoming argument data as well as the result of your axios call. That will "shadow" the original data and you cannot access it any more. Give those two variables different names.
Here I called it arg, which allows you to access arg.channelId.
export const getYoutubeList_PlayList = createAsyncThunk(
"GET/YOUTUBE_PLAYLIST",
async (arg, thunkAPI) => {
try {
const { data } = await axios.get<youtubeResponse>(
`https://www.googleapis.com/youtube/v3/playlists?key=${youTubeAcsses.apiKey}&channelId=${arg.channelId}&part=snippet&maxResults=30`
)
return data
} catch (err: any) {
return thunkAPI.rejectWithValue({
errorMessage: '호출에 실패했습니다.'
})
}
}
);
You would now dispatch this as dispatch(getYoutubeList_PlayList({ channelId: 5 }))

Redux Toolkit - action from one slice to be caught in another slice

There's an action (addOrder) in an orderSlice
orderSlice.js
import { createSlice } from '#reduxjs/toolkit';
const initialState = {
orders: []
};
const ordersSlice = createSlice({
name: 'orders',
initialState,
reducers: {
addOrder: {
reducer: (state, action) => {
state.orders.push(action.payload)
},
prepare: (orderItems, orderTotal) => {
const orderDate = new Date().toDateString();
return { payload: { orderDate, orderItems: orderItems, orderTotal: orderTotal }}
}
}
}
})
export const { addOrder } = ordersSlice.actions;
export default ordersSlice.reducer;
I'd like it to also affect the state in another slice (cartSlice). Once the 'addOrder' is fired, it should also bring the cartReducer to its initial state. Some googling suggested that I should use extrareducers for that but I'm really not getting its syntax. See below (not valid code in extrareducers)
cartSlice
import { createSlice } from '#reduxjs/toolkit';
import { addOrder } from './ordersSlice';
const initialState = {
items: {},
totalAmount: 0
};
const cartSlice = createSlice({
name: 'cart',
initialState: initialState,
reducers: {
addToCart: (state, action) => {
// p = product to be added or amended
const p = action.payload;
if (state.items[p.id]) {
// already exists
state.items[p.id].quantity += 1;
state.items[p.id].sum += p.price;
state.totalAmount += p.price;
} else {
state.items[p.id] = { price: p.price, quantity: 1, title: p.title, sum: p.price};
state.totalAmount += p.price;
}
},
removeFromCart: (state, action) => {
console.log('remove from cart');
console.log(action.payload);
const currentQuantity = state.items[action.payload].quantity;
console.log(currentQuantity);
if (currentQuantity > 1) {
state.items[action.payload].quantity -= 1;
state.items[action.payload].sum -= state.items[action.payload].price;
state.totalAmount -= state.items[action.payload].price;
} else {
state.totalAmount -= state.items[action.payload].price;
delete state.items[action.payload];
}
}
},
extraReducers: (builder) => {
builder
.addCase(addOrder(state) => {
return initialState;
})
}
});
export const { addToCart, removeFromCart } = cartSlice.actions;
export default cartSlice.reducer;
You're almost there! The builder.addCase function takes two arguments. The first is the action creator and the second is the case reducer. So you need a comma after addOrder.
extraReducers: (builder) => {
builder.addCase(addOrder, (state) => {
return initialState;
});
}

How to dynamically add parameters to firestore query and map to object

What is the recommended way to map the data to an object and return it as a promise/observable while being able to add dynamic/conditional parameters to the query.
In getCompanies2 I can dynamically add parameters to the query but I can't figure out how to map the data returned to my object and return it as a promise/observable.
In getCompanies everything works as I want it but I have to duplicate the code (as below) if I have dynamic query parameters to add.
Note: convertDocTimeStampsToDate just does what it says. I have excluded it to reduce the size of the code section.
getCompanies(searchText: string, useWhereActive: boolean): Observable<Company[]> {
if (useWhereActive) {
return this.db.collection('companies', ref => ref
.orderBy('name').startAt(searchText).endAt(searchText + '\uf8ff')
.where('active', '==', true)
)
.snapshotChanges()
.pipe(
map(snaps => convertSnaps<Company>(snaps)),
first()
);
} else {
return this.db.collection('companies', ref => ref
.orderBy('name').startAt(searchText).endAt(searchText + '\uf8ff')
)
.snapshotChanges()
.pipe(
map(snaps => convertSnaps<Company>(snaps)),
first()
);
}
}
​
getCompanies2(searchText: string, useWhereActive: boolean) {
let query = this.db.collection('companies').ref
.orderBy('name').startAt(searchText).endAt(searchText + '\uf8ff');
​
if (useWhereActive) {
query.where('active', '==', true);
}
​
query.get().then(querySnapshot => {
const results = this.convertDocuments<Company>(querySnapshot.docs);
console.log(results);
});
}
convertDocuments<T>(docs) {
return <T[]>docs.map(doc => {
return {
id: doc.id,
...doc.data()
};
});
}
export function convertSnaps<T>(snaps) {
return <T[]>snaps.map(snap => {
const data = convertDocTimeStampsToDate(snap.payload.doc.data());
return {
id: snap.payload.doc.id,
...data
};
});
}
I got it to work like below, I guess I am still getting my head around promises.
Any better solutions will be accepted though as I am still learning and don't know if this is the best method.
getCompanies2(searchText: string, useWhereActive: boolean) {
let query = this.db.collection('companies').ref
.orderBy('name').startAt(searchText).endAt(searchText + '\uf8ff');
if (useWhereActive) {
query.where('active', '==', true);
}
return query.get().then(querySnapshot => {
return this.convertDocuments<Company>(querySnapshot.docs);
});
}

How do I chain promises before returning?

Ok, I'm trying to encode image files to base64 and then make a POST to the API and return the response.
The trouble I'm having is, the base64 encodes run async, so it's not making the api post before the encoding has completed.
Any help appreciated.
makePost()
{
return Observable.create((observer) => {
this.myPost.base64images = new Array(10);
for (var i = 0; i < this.myPost.images.length; i++)
{
if (this.myPost.images[i])
{
this.base64.encodeFile(this.myPost.images[i].path).then((base64File: string) => {
this.myPost.base64images[i] = base64File;
}, (err) => {
this.myPost.base64images[i] = null;
});
}
}
observer.next(1);
observer.complete();
}).pipe(mergeMap((result) => {
var payload = {
PostTitle: "Hello",
Images: this.myPost.base64images
}
return this.apiService.makePost(payload).pipe(map(
response => {
return response;
},
err => {
return err;
}
));
}));
}

Brezze.js - Query fail if I use .Include

I have following javascript in my ViewModel:
manager.executeQuery(query)
.then(function (projects) {
projects.results.forEach(function (item) {
if (item.IsFavorite() == true) {
self.favoriten.push(item);
}
else {
self.zuletzt.push(item);
}
});
console.log("Query favorite finished");
})
.fail(function (error) {
console.log("Query failed: " + error.message);
});
The Controller:
var res = _contextProvider.Context.Projects
.Include("User11")
.Include("User12")
.Include("Timestamps")
.Where(p => p.Finished == false)
.Where(p => p.User12.Any(u => u.Guid == ID));
var erg = res.OrderByDescending(r => r.Timestamps.Min(t => t.Start));
return erg;
I get an error: Query failed: + a lot of Data
If I remove the three Include statements the query work, but the odrderBy does not work.
Is there a solution?