Return from inside an observable - javascript

I'm think fundamentally i'm doing something wrong. I'm trying to find a single entity by pulling it from filtered list, if there isn't an entity there I need to create one.
I feel like this function is wrong because I should be returning an observable but instead returning nothing
getOrCreateNew(receiverId: number) : Observable<Conversation> {
var userId = this.identity.userInfo.id;
//TODO: you should be using an expression here, and having a builder for generating your
//filters in case you want to switch them in the future
var employerFilter = new PropertyFilterNode("EmployerUserId", FilterCondition.Equal, receiverId.toString());
var employeeFilter = new PropertyFilterNode("EmployeeUserId", FilterCondition.Equal, userId.toString());
let conversationFilter = new BinaryFilterNode(employerFilter, employeeFilter, Combiner.Or);
this.getList(conversationFilter).subscribe(entities => {
if (entities == null || entities.length == 0) {
let conversation: Conversation;
conversation.employerUserId = receiverId;
conversation.employeeUserId = userId;
return this.create(conversation);
}
else {
let entity = entities[0];
return Observable.of(entity); //.Return(entity)
}
});
return null;
}
How can I return an observable which is return from inside subscribe?

The way getList subscription works suggests that it is supposed to be mergeMap or switchMap (considering that create returns an observable as well):
return this.getList(conversationFilter).mergeMap(entities => {
if (entities == null || entities.length == 0) {
let conversation: Conversation;
conversation.employerUserId = receiverId;
conversation.employeeUserId = userId;
return this.create(conversation);
}
else {
let entity = entities[0];
return Observable.of(entity); //.Return(entity)
}
});
In this case an observable that is returned from getOrCreateNew should be subscribed in order to emit values because it isn't subscribed internally.

Place the return before this.getList also :
return this.getList(conversationFilter).subscribe(entities => {

Related

Simplify forEach in forEach React

I have a function where I have to return for each "subcontractor" its response for each selection criteria.
Subcontractor object contains a selectionCriteria object. selectionCriteria object contains an array of data for each selectionCriteria a user has responded to.
Each array item is an object, that contains files, id, request (object that contains info about selection criteria user is responding to), response (contains value of the response).
Here is an example of how a subcontractor looks:
This is the function I come up with, but it's quite complex:
const { subcontractors } = useLoaderData<typeof loader>();
const { t } = useTranslation();
const submittedSubcontractors = subcontractors.filter(
(s) => s.status === 'submitted'
);
const subcontractorsResponsesToSelectionCriteria: Array<ISubcontractor> = [];
let providedAnswersResponded: boolean | null = null;
let providedAnswersFiles: Array<IFile> | [] = [];
let providedAnswersRequiresFiles: boolean | null = null;
submittedSubcontractors.forEach((u) => {
u.selectionCriteria.forEach((c) => {
if (c.request.id === criteriaId) {
if (c.response && 'answer' in c.response) {
if (typeof c.response.answer === 'boolean') {
providedAnswersResponded = c.response.answer;
} else {
providedAnswersResponded = null;
}
} else {
providedAnswersResponded = null;
}
providedAnswersFiles = c.files;
providedAnswersRequiresFiles = c.request.are_files_required;
subcontractorsResponsesToSelectionCriteria.push(u as ISubcontractor);
}
});
});
How could I simplify this code by using .reduce() method, or maybe even better ideas?
You should start working on reducing the level of nesting in your if/else like so:
function getProvidedAnswersResponded(response: any) {
if (response && ('answer' in response) && (typeof response.answer === 'boolean')) {
return response.answer;
}
return null;
}
submittedSubcontractors.forEach(u => {
u.selectionCriteria.forEach(c => {
if (c.request.id !== criteriaId) {
return;
}
providedAnswersResponded = getProvidedAnswersResponded(c.response);
providedAnswersFiles = c.files;
providedAnswersRequiresFiles = c.request.are_files_required;
subcontractorsResponsesToSelectionCriteria.push(u);
});
});
The strategy followed was basically to invert the special cases (such as c.requet.id === criteriaId) and exit the function immediately.
Also, extracting the "provided answer responded" function seems atomic enough to move it to a separate block, giving it more verbosity about what that specific code block is doing.

React filters products in a one go

I just came from the interview, I have implemented multiple filter feature in my assignment.
assignment is live here: https://tooth-store.netlify.app/
here is my code where I am filtering with according to the value of filters state.
const filterData = () => {
let data = [...products];
if (byCategory !== 'all') {
data = data.filter((item) => {
return item.category.toLowerCase() === byCategory.toLowerCase();
});
}
if (byRating !== 'all') {
data = data.filter((item) => Math.floor(item.rating.rate) == byRating);
}
if (bySearch != '') {
data = data.filter((item) =>
item.title.toLowerCase().includes(bySearch.toLowerCase())
);
}
return data;
};
Interviewer told me if we will be having a lot of products then going with this approach is not a good idea, so we have to filter at a one go not for all single value of filters.
example: category filter is applied earlier, and now we are changing the rating then it will again filters the category first. so filter it in a one go.
Can anyone explain me in a detail how I have to deal with this, I got blank at that time, but now i am guessing i simply have to check for all filters values with && operator in a single filter
Is there is any other best way?
You can make a common function, where you can check the category against data, here I give you an example in the below code, I make a common function where I get a two param, one is item this is list of items and the second is category user which category against wants data, In the function, I define the some categories array, you can store the categories dynamically in the state and then check if category exists in the categories array, If exists then you can filter the data against the categories list and If you want to see the full example CLICK HERE.
const func = (item, category) => {
let newArr = [];
if (category !== "all") {
const categories = ["electronics", "men's clothing", "jewelery"];
const ratings = [1.9, 2.5, 6.7];
if (categories.includes(category)) {
newArr = item.category.toLowerCase() === category.toLowerCase();
} else if (ratings.includes(category)) {
newArr = Math.floor(item.rating.rate) === category;
} else {
newArr = item.title.toLowerCase().includes(category.toLowerCase());
}
}
return newArr;
};
const filterData = () => {
let data = [...products];
data = data.filter((item) => {
return func(item, byCategory);
});
return data;
};
you can use this method where your filter option will run for only one type at a time just you have to pass a parameter like this
const filterData = (type) => {
let data = [...products];
if (byCategory !== 'all' && type == 'cat') { // call this filterData('cat')
data = data.filter((item) => {
return item.category.toLowerCase() === byCategory.toLowerCase();
});
}
if (byRating !== 'all'&& type == 'rate') { // call this filterData('rate')
data = data.filter((item) => Math.floor(item.rating.rate) == byRating);
}
if (bySearch != ''&& type == 'search') { // call function by filterData('search')
data = data.filter((item) =>
item.title.toLowerCase().includes(bySearch.toLowerCase())
);
}
return data;
};

Angular-Mapping value from NgRx selector into an object to be returned as an Observable

I want to return an observable (line 6) as DataObject. Line 9 is listening to store changes, so when there is a store change - lines 10,11,12 execute but not before store change right? Or Will it get the existing value in the store and execute the block (lines 10,11,12).
But if store hasnt changed yet, will line 14 wait until line 10,11,12 execute or will it return line 14 as empty object? What can I do if I want to listen to changes -> map the data from store into DataObject and return it as observable, not before that?
class DataObject {
propA: string = '';
propB: string = '';
propC: SecondDataObject;
}
getDataModel(): Observable<DataObject> {
let data = new DataObject();
this.store.pipe(select(appState)).subscribe((val) => {
const data = new DataObject();
data.propA = val.propA;
data.propB = val.propB;
data.propC = val.propC;
});
return of(data);
}
You can achieve that without subscribing to the selector, just by using the map operator and retuning the Observable itself, like the following:
getDataModel(): Observable<DataObject> {
return this.store.pipe(select(appState)).pipe(
map((val) => {
const data = new DataObject();
data.propA = val.propA;
data.propB = val.propB;
data.propC = val.propC;
return data;
})
);
}
You can return a new observable like below :-
getDataModel():Observable<DataObject>()
{
let data = new DataObject();
return new Observable((observer) => {
this.store.pipe(select(appState)).subscribe((val)=>{
data.propA = val.propA;
data.propB = val.propB;
data.propC = val.propC;
observer.next(data);
observer.complete();
}));
});
}

angular rxjs pipe remove element from array

I have a service with a delete function. The delete function will call an api and it will return true or false. When true, I will lookup the index in my array, splice it and return the new array. So for example
private items = [];
onItemDeleted = new Subject<any>();
delete(id:number): Observable<any> {
return this.http.delete('http://my.api.com/item/' + id)
.pipe(
switchMap(checkServerSuccessResponse),
map(data => {
const index1 = this.items.findIndex((element) => {
return element.id === id;
});
if (index1 >= 0 ) {
this.items.splice(index1,1);
}
this.onItemDeleted.next(this.items);
return this.items;
}
),
catchError(returnFalse),
);
}
I have a helper for the switchmap :
export function checkServerSuccessResponse(data: Response): Observable<any> {
return (data && data['success'] === true) ? of(data) : throwError("server responded false");
}
Although this works, I have a feeling the map section can reformatted. I first thought of filter (after the switchmap) to exclude the element with the id I've supplied, then emit the new array, but then I realised, the filter is not subscribed to the this.items array.
What would be the best approach to do this?
I don't know you other code, for example where this.items coming from, why do you publish updated items to onItemDeleted. But I would probably: a) pass this.items to delete method also like delete(id, items) because on the time when response will arrive, you don't know what will happen with this.items; b) that thing within the map, move to separate function, that will be removeById(items, id); c) simplify pipe. Like this:
private items = [];
onItemDeleted = new Subject<any>();
removeById(fromItems, id) {
const index1 = fromItems.findIndex((element) => {
return element.id === id;
});
if (index1 >= 0 ) {
fromItems.splice(index1,1);
}
return fromItems;
}
// who ever calls this, should provide copy of items also
// then you will be kinda protected from concurrent
// modification, when http response complete, but this.items
// is completely different, from when http request started
delete(fromItems, id:number): Observable<any> {
return this.http.delete('http://my.api.com/item/' + id)
.pipe(
switchMap(checkServerSuccessResponse),
map(data => this.removeById(fromItems, id)),
tap(items => this.onItemDeleted.next(items)),
catchError(returnFalse),
);
}

How can I use a Javascript object/map as queue

Right now I have a queue (JS array) that is used to store players waiting for a game. I need the FIFO property of a queue so that players who were added to the queue first, get put in a new game first. The problem with a queue is that it doesnt have constant time lookup. It would be great if I could have a map that kept track of the order of insertion (i know that relying on a map to do this is JS is not reliable). If I give the property a value for its insertion order, it would need to be updated if someone leaves the queue, so that isnt helpful either. Anyway around this? A way to get constant lookup and maintain insertion order?
If you don't have memory constraints, maybe you can maintain a map with the queue implemented as a double linked list. Here is a sample implementation:
function Queue() {
var oldestRequest,
newestRequest,
map = {};
this.addUser = function(userID) {
var newRequest = { userID: userID };
map[userID] = newRequest;
// Set this as the oldest request if it is the first request
if (!oldestRequest) {
oldestRequest = newRequest;
}
// If this isn't the first request, add it to the end of the list
if (newestRequest) {
newestRequest.next = newRequest;
newRequest.previous = newestRequest;
}
newestRequest = newRequest;
};
this.nextUser = function() {
// If we don't have any requests, undefined is returned
if (oldestRequest) {
var request = oldestRequest;
oldestRequest = request.next;
delete map[request.userID];
// Make sure we don't hang on to references to users
// that are out of the queue
if (oldestRequest) {
delete oldestRequest.previous;
}
// This is the last request in the queue so "empty" it
if (request === newestRequest) {
newestRequest = undefined;
}
return request;
}
};
this.removeUser = function(userID) {
var request = map[userID];
delete map[userID];
if (request.previous) {
request.previous.next = request.next;
}
if (request.next) {
request.next.previous = request.previous;
}
};
return this;
}
You can use a map together with a queue to provide constant time access. Below is the implementation in TypeScript 4.2. Map is used instead of Object to provide better performance in addition and removal of values.
// TypeScript typing
export type KeyValuePair<K, V> = [ K, V ]
interface ValueData<V> {
value: V
refCount: number
}
// Public classes
export class MapQueue<K, V> {
readonly #queue: Array<KeyValuePair<K, V>>
readonly #map: Map<K, ValueData<V>>
constructor () {
this.#queue = []
this.#map = new Map()
}
get length (): number {
return this.#queue.length
}
unshiftOne (pair: KeyValuePair<K, V>): number {
const [key, value] = pair
const valueData = this.#map.get(key)
if (valueData !== undefined) {
if (valueData.value !== value) {
throw new Error(`Key ${String(key)} with different value already exists`)
}
valueData.refCount++
} else {
this.#map.set(key, {
value,
refCount: 1
})
}
return this.#queue.unshift(pair)
}
pop (): KeyValuePair<K, V> | undefined {
const result = this.#queue.pop()
if (result !== undefined) {
const valueData = this.#map.get(result[0])
if (valueData !== undefined) {
valueData.refCount--
if (valueData.refCount === 0) {
this.#map.delete(result[0])
}
}
}
return result
}
get (key: K): V | undefined {
return this.#map.get(key)?.value
}
}

Categories