I'm new to RxJs. I'm trying to run observable function recursively with no luck. I want to print in this order.
form textbox icon textarea
Here is what I tried so far. Any help will be very much appreciated.
const args = {
name: 'form',
children: [{
name: 'textbox',
children: [{
name: 'icon',
children: []
}]
}, {
name: 'textarea',
children: []
}]
};
import { of, from, Observable, concat } from 'rxjs';
import { map, concatAll, combineAll } from 'rxjs/operators';
const render = (component) => {
return new Observable<any>(observer => {
console.log(component.name);
concat(...component.children.map(x => render(x)))
.subscribe(() => observer.next());
});
};
render(args).subscribe(() => console.log('done'));
This gives the correct order. If I've missed something, please comment:
const { of, concat } = rxjs;
const args = {
name: 'form',
children: [
{
name: 'textbox',
children: [
{
name: 'icon',
children: []
}
]
},
{
name: 'textarea',
children: []
}
]
};
const render = (component) => concat(of(component), ...component.children.map(render));
render(args).subscribe(({name}) => console.log(name));
<script src="https://unpkg.com/#reactivex/rxjs#6.4/dist/global/rxjs.umd.js"></script>
Related
Following test case, will return the data correctly but JEST show as failed. The test is written using TestScheduler
Jest Result
expect(received).toEqual(expected) // deep equality
- Expected
+ Received
- Array [
- Object {
- "frame": 3,
- "notification": Notification {
- "error": undefined,
- "hasValue": true,
- "kind": "N",
- "value": Object {
- "type": "INITIALIZED",
- },
- },
- },
- ]
+ Array []
Code
import { ofType } from 'redux-observable';
import { mergeMap, map, tap } from 'rxjs/operators';
import { of, from } from 'rxjs';
import { TestScheduler } from 'rxjs/testing';
describe('routechange epic', () => {
const testScheduler = new TestScheduler((actual, expected) => {
expect(actual).toEqual(expected);
});
it('check apollo', () => {
const dependencies = {
apolloClient: {
mutate: ({ mutation, variables }: { mutation: any, variables: any }) =>
Promise.resolve({
data: { param: 'testA' }
})
},
};
const initializeOrg = (action$, state$, { apolloClient }) =>
action$
.pipe(
ofType('START'),
tap(act => console.log('---AAA', act)),
mergeMap(action =>
from(
apolloClient.mutate({
mutation: `something`,
variables: {
orgId: (action as any).params || ''
}
})
)
.pipe(
tap(x => console.log('----x', x)),
map(response => ({
type: 'INITIALIZED',
response,
}))
)
)
);
testScheduler.run(({ hot, cold, expectObservable }) => {
const action$ = hot('-a', {
a: { type: 'START', params: 'SomethingA' }
});
const state$ = null;
const output$ = initializeOrg(action$, state$, dependencies);
expectObservable(output$).toBe('---a', {
a: {
type: 'INITIALIZED'
}
})
});
});
});
We cannot use Promise.resolve as someone commented it.
It worked now with cold observable like below.
import { ofType } from 'redux-observable';
import { mergeMap, map, tap, toArray, take } from 'rxjs/operators';
import { of, from } from 'rxjs';
import { TestScheduler } from 'rxjs/testing';
describe('routechange epic', () => {
it('check apollo', async () => {
const testScheduler = new TestScheduler((actual, expected) => {
expect(actual).toEqual(expected);
});
const initializeOrg = (action$, state$, { apolloClient }) =>
action$
.pipe(
ofType('START'),
tap(act => console.log('---AAA', act)),
mergeMap(action =>
from(
apolloClient.mutate({
mutation: `something`,
variables: {
orgId: (action as any).params || ''
}
})
)
.pipe(
tap(x => console.log('----x', x)),
map(response => ({
type: 'INITIALIZED',
response,
}))
)
)
);
testScheduler.run(({ hot, cold, expectObservable }) => {
const action$ = hot('-a', {
a: { type: 'START', params: 'SomethingA' }
});
const state$ = null;
const dependencies = {
apolloClient: {
mutate: ({ mutation, variables }: { mutation: any, variables: any }) =>
cold('--a|', {
a: { data: { param: 'testA' } }
})
},
};
const output$ = initializeOrg(action$, state$, dependencies);
expectObservable(output$).toBe('---a', {
a: {
type: 'INITIALIZED',
response: {
data: { param: 'testA' }
}
}
})
});
});
});
I have date value in this format from a for each loop. Each loop provides value in the following format.
start: 2021-06-30T18:30:00.000Z
title: one
start: 2021-07-31T18:30:00.000Z
title: two
start: 2021-08-31T18:30:00.000Z
title: three
function loadItems() {
firebase.database().ref("events").once("value", (userSnapshot) => {
userSnapshot.forEach(element => {
const start = moment(element.child('start').val()).toDate();
const title = element.child('title').val();
)}
)}
}
I have created variables like this.
const [items, setItems] = useState([]);
const [markedDates, setMarkedDates] = useState([]);
I need to convert this to the following format. How can I use useState to update the value on for each loop.
markedDates={{
'2021-06-30': {selected: true, marked: true},
'2021-06-30': {selected: true, marked: true},
'2021-06-30': {selected: true, marked: true},
}}
items={{
'2021-06-30': [{name: 'one'}],
'2021-06-30': [{name: 'two'}],
'2021-06-30': [{name: 'three'}],
}}
Reduce your firebase array to required format. Something along these lines would do the job.
const items = userSnapshot.reduce((accumulator: any, item: any) => {
if(accumulator.hasOwnProperty(item.start.slice(0, 10))) {
accumulator = {...accumulator, [item.start.slice(0, 10)]: [...accumulator[item.start.slice(0, 10)], { name: item.title }]}
} else {
accumulator = {...accumulator, [`${item.start.slice(0, 10)}`]: [{ name: item.title }]}
}
return accumulator
}, {})
I'm new to RxJS, and I'm trying to figure out how to observe the data when it become available. I'm using Nuxt SSR and I'm fetching data from Firebase. The initial post value is set to null, and once the data object become available, it should run the head() function only once. I get this type error.
Cannot read property 'pipe' of null
If I initiate post: {}, as empty object, I get this type error.
post$.pipe is not a function
Appreciate if I can get some help or guidance.
// page\:post.vue
<script>
import { mapState, mapActions } from 'vuex'
import { take } from 'rxjs/operators'
export default {
fetch() {
this.fetchPost()
},
computed: {
...mapState('posts', ['post']),
},
methods: {
...mapActions('posts', ['fetchPost']),
},
head() {
const post$ = this.post
post$.pipe(take(1)).subscribe((post) => {
return {
title: this.post.title,
link: [{ rel: 'canonical', href: this.post.canonical }],
meta: [
{ hid: 'name', itemprop: 'name', content: this.post.title },
{
hid: 'description',
itemprop: 'description',
content: this.post.content,
},
],
}
})
},
}
</script>
// store\posts.js
export const state = () => ({
post: null,
})
export const mutations = {
setPost(state, payload) {
state.post = payload
},
}
export const actions = {
async fetchPost({ commit }, key) {
const doc = await postsCollection.doc(key).get()
if (doc.exists) commit('setPost', doc.dat())
},
}
Edit
Using Subject. However, there is still issue where the meta tags are generated before the post data is set.
// page\:post.vue
<script>
import { mapState, mapActions } from 'vuex'
import { take } from 'rxjs/operators'
export default {
fetch() {
this.fetchPost()
},
computed: {
...mapState('posts', ['post']),
},
methods: {
...mapActions('posts', ['fetchPost']),
},
head() {
const postSubject = new Subject()
const post = postSubject.asObservable()
postSubject.next(this.post)
post.subscribe((post) => {
return {
title: post.title,
link: [{ rel: 'canonical', href: post.canonical }],
meta: [
{ hid: 'name', itemprop: 'name', content: post.title },
{
hid: 'description',
itemprop: 'description',
content: post.content,
},
],
}
})
},
}
</script>
// store\posts.js
export const state = () => ({
post: null,
})
export const mutations = {
setPost(state, payload) {
state.post = payload
},
}
export const actions = {
async fetchPost({ commit }, key) {
const doc = await postsCollection.doc(key).get()
if (doc.exists) commit('setPost', doc.dat())
},
}
You need to subscribe to an Observable. As I understood, in your case this.post is not type of an Observable.
As this.post is populated at some point of time, you need to subscribe to an observable which should emit data when you say this.post is now populated with data. For that you can use a Subject.
See this example: link
I have an iOS app that needs to pass data to a vue front-end:
const customerStore = new Vuex.Store({
state: {
data: [
{ id:1, title: 'Foo' },
{ id:2, title: 'Bar' }
]
},
mutations: {
list (state, data) {
state.data = data
}
}
})
const ListCustomersPage = {
key: 'ListCustomersPage',
template: '#ListCustomersPage',
components: { toolbar, cellcustomer },
data() {
return {
title: 'Select Customer',
items: customerStore.state.data
}
},
methods: {
push() {
}
}
};
However, I need to mutate the store from an injection on the webview:
web.InjectJavascriptAsync("customerStore.commit('list', [])").Start()
But the list is not changed. No error is shown when calling the injection.
I'm using GraphQL in Javascript, and I'd like to be able to pass arguments to a resolve() function in a GraphQLObjectType's field.
Here is the GraphQLObjectType declaratio:
export const ModelSchema = new GraphQLObjectType({
name: 'Model',
description: 'Model information',
fields: () => ({
tags: {
type: TagList,
description: 'Model\'s UUID',
async resolve(obj, args) {
console.log('args', args); // expecting to see an object
},
},
}),
});
And here is how I want to query in GraphQLI:
{
getModels(UUIDs:"0AAAA2EFF6677194ED227EE4AAAA8D4A") {
total
models {
tags (limit: 1) {
tags {
UUID
name
}
}
}
}
}
So I want to be able to send parameters (in this case limit) to tags so when the resolve() function is being invoked, I can use this parameter and limit the results, or do something else.
How can I do it?
Thanks
Ok, got it... Needed to add args like so:
export const ModelSchema = new GraphQLObjectType({
name: 'Model',
description: 'Model information',
args: {
limit: {
type: GraphQLInt,
},
},
fields: () => ({
tags: {
type: TagList,
description: 'Model\'s UUID',
async resolve(obj, args) {
console.log('args', args); // expecting to see an object
},
},
}),
});
And now it works.