Trying to mimic the HTTP requests, and to make a static data to be presented with the async pipe.
ts:
footerContent$: Observable<{ key: string, value: string }>[] = ([
of({ key: '1', value: 'a' }),
of({ key: '2', value: 'b' }),
of({ key: '3', value: 'c' })
])
HTML:
<div *ngFor='let content of footerContent$ | async'>
{{content.value}}
</div>
Here I'm getting an Array of Observables and the pipe doesn't seem to work
ERROR Error: InvalidPipeArgument: '[object Object],[object
Object],[object Object]' for pipe 'AsyncPipe'
Then i tried another approach and switch to from operator (so i can get one observable object):
footerContent$: Observable<{ key: string, value: string }> = from([
({ key: '1', value: 'a' }),
({ key: '2', value: 'b' }),
({ key: '3', value: 'c' })
])
ERROR Error: Cannot find a differ supporting object '[object Object]'
of type 'object'. NgFor only supports binding to Iterables such as
Arrays.
at NgForOf.push../node_modules/#angular/common/fesm5/common.js.NgForOf.ngDoChec
Any suggestions why it doesn't work?
What you are doing is passing a list of observables to an async pipe, but async pipe expects to get only observables and promises.
So what you need to do is convert your list of observables to one combined observable using one of the combination functions that RxJS provides (merge, zip, forkJoin, etc.).
See an example of observables combination using forkJoin.
In this example the combined observable will emit when all observables complete:
footerContent$: Observable<SomeObject[]> = forkJoin(
of({ key: '1', value: 'a' }),
of({ key: '2', value: 'b' }),
of({ key: '3', value: 'c' })
)
After you will subscribe to this combined observables the emitted value will look like this:
[
{ key: '1', value: 'a' },
{ key: '2', value: 'b' },
{ key: '3', value: 'c' }
]
Note that forkJoin can get a map of observables:
footerContent$: Observable<{[key: string]: SomeObject}> = forkJoin({
request1: of({ key: '1', value: 'a' }),
request2: of({ key: '2', value: 'b' }),
request3: of({ key: '3', value: 'c' })
})
In this case, the emitted value will look like this:
{
request1: { key: '1', value: 'a' },
request2: { key: '2', value: 'b' },
request3: { key: '3', value: 'c' }
}
Here is a link for more details about the combination functions of RxJS.
Related
I am trying to skip a query if the object is not there but it seem to not work and I would like to know if there is any solution for this.
Here is my query
graphql(GET_UBO_DECLARATIONS, {
name: "getUboDeclarations",
options: () => ({
fetchPolicy: "network-only"
})
}),
graphql(GET_UBOS, {
name: "getUbos",
skip: props =>
!props.getUboDeclarations ||
!props.getUboDeclarations.getUboDeclarationsForThisUser,
options: props => ({
fetchPolicy: "network-only",
variables: {
_id: props.getUboDeclarations.getUboDeclarationsForThisUser._id
}
})
}),
props.getUboDeclarations.getUboDeclarationsForThisUser return null so it should be false and query skiped
The problem is not the skip as much as the variables -- there's no guarantee around the order these options are evaluated so even if the skip evaluates to true, the options function may still be called. If it is called and props.getUboDeclarations.getUboDeclarationsForThisUser is in fact null, you'll get a TypeError because you're trying to read the _id property of a null value. The fix is to modify variables to account for the possible null:
variables: {
_id: props.getUboDeclarations && props.getUboDeclarations.getUboDeclarationsForThisUser && props.getUboDeclarations.getUboDeclarationsForThisUser_id
}
Note that you can use something like lodash's get to make these null guard clauses easier to deal with.
I believe you are missing where in your getUbos query.
graphql(GET_UBO_DECLARATIONS, {
name: "getUboDeclarations",
options: () => ({
fetchPolicy: "network-only"
})
}),
graphql(GET_UBOS, {
name: "getUbos",
skip: props =>
!props.getUboDeclarations ||
!props.getUboDeclarations.getUboDeclarationsForThisUser,
options: props => ({
fetchPolicy: "network-only",
variables: {
where: {// this is missing
_id: props.getUboDeclarations.getUboDeclarationsForThisUser._id
}
}
})
}),
I am trying to sequence two ajax requests in redux-observables, and second request will be based on response of first, And i individually want to dispatch response or error of both requests.
Using concat to process one request after another but i am stuck on how to use response of first one into second request. If i chain using two switchMap then through result selector i will get inner and outer observables but i am not getting how to dispatch action after first request.
export const deleteSettingsEpic = action$ => action$.pipe(
ofType('DELETE_SETTINGSDATA'),
switchMap(action$ => concat(
ajax.ajaxDelete(`${action$.payload.api}/${action$.payload.id}`)
.pipe(
map(r => ({ type: 'DELETE_SUCCESS', payload: r })),
catchError(e => of({ type: 'DELETE_ERROR' }))
),
ajax.get(`${action$.payload.api}?page=${action$.payload.query.page}&limit=${action$.payload.query.limit}`)
.pipe(
map(r => ({
type: action$.payload.getPaginationAction,
payload: {
data: r.response.docs,
page: r.response.page,
totalPages: r.response.totalPages,
limit: r.response.limit,
totalDocs: r.response.totalDocs
}
})),
catchError(e => of({ type: 'FETCH_ERROR' }))
),
of({ type: 'SET_DIMMER_FALSE' }).pipe(delay(250)),
of({ type: 'RESET_ERRORS' }).pipe(delay(1500)),
)
),
);
Probably you should use concatMap for the second ajax request, in pseudo code:
export const deleteSettingsEpic = action$ => action$.pipe(
ofType('DELETE_SETTINGSDATA'),
switchMap(action$ => ajax.ajaxDelete(...)),
concatMap(result => ajax.get(...))
),
);
I have a situation where I'm making an API call to a Laravel back-end and eager-loading some data. The data is a collection of locations, each of the form:
location = {
id: ..
name: ...
...
docks: [
{
id: ...
name: ...
},
...
]
}
The end result of this epic should be to dispatch 2 actions, one with a list of the locations, and another with the list of all the associated docks
Taking it from the response to the api call, the following throws a Typescript error and won't compile:
.mergeMap(({ response }) => {
if (response.messages) {
return Observable.of(GetLocationsForReceiverFailedAction(response.messages))
}
const locations = response.locations.map((locn: any) => ({
id: locn.id,
receiver_id: locn.receiver_id,
name: locn.name,
address: locn.address,
city: locn.city,
state: locn.state,
zip: locn.zip
}))
const location$ = Observable.of(GetLocationsForReceiverSuccessAction(locations))
const docks: any[] = []
response.locations.forEach((locn: any) => {
locn.docks.forEach((dk: any) => {
docks.push(dk)
})
})
const docks$ = Observable.of(GetDocksForReceiverSuccessAction(docks))
return Observable.merge(location$, docks$)
})
.catch(() =>
Observable.of(
GetLocationsForReceiverFailedAction([
'Something went wrong trying to reach the server'
])
)
)
The error reads:
"Argument of type '({ response }: AjaxResponse) => Observable<{ type: ActionTypes; messages: string[]; }> | Observab...' is not assignable to parameter of type '(value: AjaxResponse, index: number) => ObservableInput<{ type: ActionTypes; messages: string[]; }>'."
If, however, I change the line:
return Observable.merge(location$, docks$)
to:
return Observable.merge(location$, Observable.empty(), docks$)
(ie, separating by 2 observables by an empty observable in the merge (or concat, which works the same way here), it compiles and runs.
What am I not understanding here?
In my application, the state tree has this shape:
{
...otherReducers,
rooms: Map({
// room being the room's id
room: Map({
id: '',
name: '',
users: Map({
// user being the user's id
user: Map({
id: '',
name: '',
rank: ' '
})
})
})
})
}
In order to update a user's state, I've been writing my reducers as follows:
function roomsReducer(state = Map(), action) {
case USER_RENAME:
return selectRoom(state, action);
default:
return state;
}
function selectRoom(state, action) {
let room = state.get(action.payload.id);
return state.set(action.payload.id, roomReducer(room, action));
}
// and so on and so forth until I reach the user I want to update
Is there a way I an combine the users reducer with room, despite it having id and name properties? If not, is there a better way I could be managing my state to make reducing more manageable?
This is a problem with how you structure your state. Editing users would be much easier if it was normalized like so:
{
...otherReducers,
rooms: Map({
5: Map({
id: '5',
name: 'some name',
users: [1,4,52]
})
}),
users: Map({
1: Map({
id: '1',
name: 'Charles',
range: 'Master'
}),
4: Map({
id: '4',
name: 'Sally',
range: 'Master'
}),
52: Map({
id: '52',
name: 'Harry',
range: 'Novice'
})
})
}
I am trying to do sort id
Modal:
module.exports = {
autoPK: false,
attributes: {
id: {
type: 'integer',
autoIncrement:true,
primaryKey: true
},
}
}
Query:
mymodal.find().sort({id: 'asc'}).exec(function (err, res) {
console.log(res)
});
Data:
[ { id: '2', },{ id: '1'},{ id: '11' } ]
Actual:
[ { id: '1', },{ id: '11'},{ id: '2' } ]
**Expected:
[ { id: '1', },{ id: '2'},{ id: '11' } ]**
Can anybody help me out. Please..
Sorting on string working, but on number(interger).
Is there any with my query or issue with sails waterline criteria sort
First you should do query find and later sort()
Modal.find()
.sort({id: 'asc'})
.exec(function(err, res) {
console.log(res)
});
I went through the sails-redis adapter index and schema, few things are missing. while parsing the input data like '11' the method not worried about the data type.
Data like { id: 1 } and { id: '1'} is consider to be different even though in the model
type: 'integer
specified.
sails-redis/lib/database/schema.js
changes code:
Schema.prototype.parse
.
.
case 'integer':
values[key] = parseInt(values[key]);
break;
case 'float':
values[key] = parseFloat(values[key]);
break;
}
}
.
.
changes working for me. Make sure the values[key] is not null
The documentation isn't great on this, but it looks like you might need to use binary notation if you pass an object to sort(). Easier to just pass a string:
Model.find().sort('id asc').exec(function (err, res) {
console.log(res)
});