Compine Pipes in array with angular Observable - javascript

I have Observable where I'm piping it to multipe pipes as follows.
getOrders(filters: any, page: any = 1, orderBy: string = 'deliver_on', sort: string = 'asc') {
const opCityPipe = pipe(
filter((obj: any) => obj.payload.order.op_city_id === 1)
);
const storeRefPipe = pipe(
filter((obj: any) => obj.payload.order.store.ref.match(/^Your.*/))
);
const statusPipe = pipe(
filter((obj: any) => ['assign_request', 'accepted',
'in_store', 'en_route_to_client', 'arrived',
'canceled'].indexOf(obj.payload.order.status) !== -1)
);
return Observable.create((observer: Observer<any>) => {
this.socket.on('private-order.status.changed.1:order.status',
(obj: any) => {
observer.next(obj);
});
}).pipe(opCityPipe, storeRefPipe, statusPipe);
}
How can I make the pipe as array? I want to dynamically populate it. I tried to add the array but got an error.
ERROR TypeError: Object(...)(...) is not a function
I want to do something like
const pipes = [opCityPipe, storeRefPipe, statusPipe];
Observable.pipe(pipes);
UPDATE SOLUTION
Observable.pipe(...pipes);

I think this should work, but the error you're getting is not clear.
getOrders(filters: any, page: any = 1, orderBy: string = 'deliver_on', sort: string = 'asc') {
const opCityPipe = filter((obj: any) => obj.payload.order.op_city_id === 1);
const storeRefPipe = filter((obj: any) => obj.payload.order.store.ref.match(/^Your.*/));
const statusPipe = filter((obj: any) => ['assign_request', 'accepted',
'in_store', 'en_route_to_client', 'arrived',
'canceled'].indexOf(obj.payload.order.status) !== -1);
const filters = [opCityPipe, storeRefPipe, statusPipe]
return Observable.create((observer: Observer<any>) => {
this.socket.on('private-order.status.changed.1:order.status',
(obj: any) => {
observer.next(obj);
});
}).pipe(...filters);
}

Related

Optimize these 4 methods in 1 method

const getDate = (id) =>{
const userId = info.find(user => user.id === id)
return userId.date;
}
const getValueAtOne = (id) => {
const userId = info.find(user => user.id === id)
if(userId?.value[0]){
return userId?.value[0]
}
}
const getValueAtTwo = (id) => {
const userId = info.find(user => user.id === id)
if(userId?.value[1]){
return userId?.value[1]
}
}
const getAllValues = (id) => {
const userId = info.find(user => user.id === id)
if(userId?.value) {
const arrValue = userId?.roles.map((validData) => {
return { value: validData, label:validData };
});
return arrValue;
}
}
I have these 4 methods, which I am calling from different places in my code.But i want to optimize my code and want all these methods in a single method, but I cant figure out the best way to do it. first method returns me the date, second one returns the value of array at position 1, third method returns value of array at position 2, and 4th method returns the all the value and convert it in object.
You can return a single object like so:
const getAll = (id) => {
const userId = info.find((user) => user.id === id);
const [valueAtOne, valueAtTwo] = userId?.value ?? [];
const allValues =
userId?.value.roles.map((validData) => ({
value: validData,
label: validData,
})) ?? [];
return {
allValues,
valueAtOne,
valueAtTwo,
};
};

Refactor javascript code more elegantly, not using nested ternary expression or let

I have this simplified code, quite simple:
export const OwnRedirect = () => {
const { pipelineType, ticketId, productId } = useParams<{
pipelineType?: string;
ticketId?: string;
productId?: string;
}>();
let path = '';
if (pipelineType) {
path = `/pipeline/${pipelineType}`;
} else if (ticketId) {
path = `/ticket/${ticketId}`;
} else if (productId) {
path = `/product/${productId}`;
} else {
path = '/pipeline/local';
}
return <Redirect to={path}/>;
};
But I found it not readable enough. Anybody has an idea how to refactor this code not using if or switch or let or nested ternary operator?
To make it easier to read, you can take advantage of short-circuit evaluation with && and ||. To make things cleaner and easier to test, I also like creating really small functions that only do one thing, but do it well. It avoids mixing logic (which path to choose) and functionality (building those paths):
export const OwnRedirect = () => {
const { pipelineType, ticketId, productId } = useParams<{
pipelineType?: string;
ticketId?: string;
productId?: string;
}>();
const path = (
(pipelineType && buildPipelinePath(pipelineType)) ||
(ticketId && buildTicketPath(ticketId) ) ||
(productId && buildProductPath(productId) ) ||
`/pipeline/local`
);
return <Redirect to={path} />;
};
function buildPipelinePath(pipelineType) {
return `/pipeline/${Number(pipelineType) === 1 ? 'local' : 'global'}`;
}
function buildTicketPath(ticketId) {
return `/ticket/${ticketId}`;
}
function buildProductPath(productId) {
return `/product/${productId}`;
}
sometimes just separating it into a function
helps with readability.
const toUrl = ({ pipelineType = '', ticketId = '', productId = '' }) => {
if (pipelineType) {
return `/pipeline/${pipelineType}`;
}
if (ticketId) {
return `/ticket/${ticketId}`;
}
if (productId) {
return `/product/${productId}`;
}
return '/pipeline/local';
}
export const OwnRedirect = () => {
const params = useParams<{
pipelineType?: string;
ticketId?: string;
productId?: string;
}>();
return <Redirect to={toUrl(params)}/>;
};
You may use a tagged sum. For example:
// Generic functions
// B is the function compose combinator
const B = g => f => x => g (f (x))
const taggedSum = xs => Object.fromEntries (
xs.map(tag => [tag, value => ({ tag, value })])
)
const cata = matches => ({ tag, value }) => matches[tag] (value)
/////////////////////////
const Kind = taggedSum (['pipeline', 'ticket', 'product', 'local' ])
const path = cata ({
pipeline: x => `/pipeline/${x}`,
ticket: x => `/ticket/${x}`,
product: x => `/product/${x}`,
local: () => `/pipeline/local`
})
const output1 = B (path) (Kind.pipeline) (1)
const output2 = B (path) (Kind.ticket) (14)
const output3 = B (path) (Kind.product) (3421)
const output4 = B (path) (Kind.local) (0)
console.log ('pipeline:', output1)
console.log ('ticket:', output2)
console.log ('product:', output3)
console.log ('local:', output4)

Typescript: Type 'X' provides no match for the signature '(prevState: undefined): undefined'

So I have a React Native application using TypeScript, with an error that's driving me crazy.
Basically, there is a Searchable List. It is initiated with an Array of values. Once the user types in a SearchBar, the initiated Array is filtered, returning an updated Array.
However, TypeScript gives me the error: Type '{ id: string; name: string; selected: boolean; }[]' provides no match for the signature '(prevState: undefined): undefined'.
I am confused because I don't know where this '(prevState: undefined): undefined'actually comes from and why. Do you know what I am doing wrong here? Help will be much appreciated.
Here is the code:
const defaultChoices = [
{
id: '1',
name: 'default',
selected: false,
},
];
let choicesList;
const getChoicesList = () => {
if (listName === 'include') {
choicesList = Object.values(includeChoices).map(choice => ({
...choice,
}));
} else if (listName === 'exclude') {
choicesList = Object.values(excludeChoices).map(choice => ({
...choice,
}));
}
};
const [filteredChoicesList, setFilteredChoicesList] = useState(choicesList);
useEffect(() => {
getChoicesList();
}, []);
useEffect(() => {
let choices = defaultChoices;
if (listName === 'include') {
choices = includeChoices;
} else if (listName === 'exclude') {
choices = excludeChoices;
} else {
choices = defaultChoices;
}
const newChoices = choices.filter(item => {
const itemData = `${item.name.toUpperCase()}`; // ignore Uppercase/Lowercase and make equal
const textData = query.toUpperCase();
return itemData.indexOf(textData) > -1;
});
setFilteredChoicesList(newChoices); // error occurs for "newChoices"
}, [effect]);
The problem is, you have set the choicesList as undefined. and getChoicesList is called on the first initialization of component but before that the state us being set where the choicesList is undefined.
Update the part of your code as
let choicesList: any[] = [];
const getChoicesList = () => {
let data: any[] = [];
if (listName === 'include') {
data = Object.values(includeChoices).map(choice => ({
...choice,
}));
} else if (listName === 'exclude') {
data = Object.values(excludeChoices).map(choice => ({
...choice,
}));
}
return data;
};
const [filteredChoicesList, setFilteredChoicesList] = useState<any[]>(choicesList);
useEffect(() => {
const updatedList = getChoicesList();
setFilteredChoicesList(updatedList)
}, []);
Now, you'll have the filteredChoicesList with data you need and you shouldn't have any compilation error.
Another thing is, create an interface and replace any with that interface in the state and while defining.

Combining observables of array objects

How do you combine two or more observable of array i.e. Observable<Object[]>, Observable<Object[]> using rxjs in order to return one Observable<Object[]>?
forkJoin and merge are emitting the two Observable<Object[]> arrays independently.
getEmployeesLeavesByEmployeeNumber2(employeeNumber,afromDate,atoDate) {
const scenario1 = this.afs.collection(`${environment.FB_LEAVES}`, ref => {
let query: firebase.firestore.CollectionReference | firebase.firestore.Query = ref;
query = query.where("employeeNumber", "==", employeeNumber);
query = query.where("fromDate",">=",afromDate);
query = query.where("fromDate","<=",atoDate);
return query;
}).snapshotChanges()
.pipe(take(1))
.pipe(
map(changes => {
return changes.map(a => {
const data = a.payload.doc.data() as Leave;
data.docId = a.payload.doc.id;
return data;
})
})
).pipe(map(leaves => {
let leavesArr=leaves.filter(leave => leave.status!==environment.LEAVE_STATUS_DECLINED)
return leavesArr;
}));
const scenario2 = this.afs.collection(`${environment.FB_LEAVES}`, ref => {
let query: firebase.firestore.CollectionReference | firebase.firestore.Query = ref;
query = query.where("employeeNumber", "==", employeeNumber);
query = query.where("toDate","<=",afromDate);
query = query.where("toDate","<=",atoDate);
return query;
}).snapshotChanges()
.pipe(take(1))
.pipe(
map(changes => {
return changes.map(a => {
const data = a.payload.doc.data() as Leave;
data.docId = a.payload.doc.id;
return data;
})
})
).pipe(map(leaves => {
let leavesArr=leaves.filter(leave => leave.status!==environment.LEAVE_STATUS_DECLINED)
return leavesArr;
}));
const scenario3 = this.afs.collection(`${environment.FB_LEAVES}`, ref => {
let query: firebase.firestore.CollectionReference | firebase.firestore.Query = ref;
query = query.where("employeeNumber", "==", employeeNumber);
query = query.where("fromDate","<=",afromDate);
return query;
}).snapshotChanges()
.pipe(take(1))
.pipe(
map(changes => {
return changes.map(a => {
const data = a.payload.doc.data() as Leave;
data.docId = a.payload.doc.id;
return data;
})
})
).pipe(
filter(leave => {
return leave!==undefined;
})
);
return merge(scenario1,scenario2);
}
I am expecting a single observable of array but getting 2 i.e.
emp's leaves: [{…}]
assign.component.ts:198 leaves array length at assignment error 1
assign.component.ts:168 emp's leaves: (2) [{…}, {…}]
assign.component.ts:198 leaves array length at assignment error 2
I have got it to work using:
return forkJoin(scenario1,scenario2).pipe(map((arr) => [...arr[0],...arr[1]] ));

Create elements dynamically with CycleJS

I'm trying to learn some CycleJS and I ended up not knowing what to do exactly with this. The goal is to create inputs via configuration, instead of declaring them manually. The problem is I'm only getting rendered the last of the inputs from the array, instead of both. I'm assume the error is in view$ and how I'm dealing with the stream.My naive implementation is this:
Main.js
const sliderGunProps$ = xs.of({
value: 30,
id: 'gun'
});
const sliderCannonProps$ = xs.of({
value: 70,
id: 'cannon'
});
const propsConfig = [sliderGunProps$, sliderCannonProps$];
function view$(state$) {
return xs.fromArray(state$)
.map(state => {
return xs.combine(state.sliderVDom$, state.values)
.map(([sliderVDom, value]) =>
div([sliderVDom, h1(value)])
);
})
.flatten();
}
function model(actions$) {
return actions$.map((action) => {
const sliderVDom$ = action.DOM;
const sliderValue$ = action.value;
const values$ = sliderValue$.map(val => val);
return {
sliderVDom$: sliderVDom$,
values: values$
};
});
}
function intent(sources) {
return propsConfig.map(prop$ => Slider({
DOM: sources.DOM,
props$: prop$
}));
}
function main(sources) {
const actions$ = intent(sources);
const state$ = model(actions$);
const vdom$ = view$(state$);
const sink = {
DOM: vdom$
};
return sink;
}
Thanks!
I ended up figuring out how to solve it. The point was that I was not understanding how view$ handle the streams. The proper code:
function total(values) {
return xs.combine(...values)
.map(val => val.reduce((acc, x) => acc + x));
}
function view$(state$) {
const DOMElements = state$.map(slider => slider.sliderVDom$);
const values = state$.map(slider => slider.values);
const totalValue$ = total(values);
return xs.combine(totalValue$, ...DOMElements)
.map(([totalValue, ...elements]) => (
div([
...elements,
h1(totalValue)
])
));
}
function model(actions$) {
return actions$.map((action) => ({
sliderVDom$: action.DOM,
values: action.value.map(val => val)
}));
}
function intent(sources) {
return propsConfig.map(prop$ => Slider({
DOM: sources.DOM,
props$: prop$
}));
}

Categories