How to get data stored as subject rxjs - rxjs

I am working on displaying the details of event clicked. I have stored all the events inside an array.
When the user clicks on the event then its id is passed which checks inside the array and it passes the result into service.
showDetail(id){
let obj = this.events;
let newArr = Object.values(obj);
let result = newArr.filter(function(el) {
return el["id"] == id;
});
this.articleService.sendMessage(result);
let url = `/article/${id}`;
this.router.navigate([url]);
}
service
private detailSubject = new Subject<any>();
sendMessage(formData: any) {
this.detailSubject.next({formData});
}
getMessage(): Observable<any> {
return this.detailSubject.asObservable();
}
Now in my article/id page.
I am not being able to retrieve this passed array.
I have following code
ngOnInit() {
this.articleService.getMessage().subscribe(
res => {
this.loadArticleDetail(res["formData"]);
},
error => {
console.log("Error loading data");
}
);
}

this.articleService.sendMessage(result); // <-- Subject.next()
let url = `/article/${id}`;
this.router.navigate([url]); // <-- Subject.subscribe() after Subject.next(), so value already emitted
You already added BehaviorSubject tag. So use it. Also, getMessage(): Observable<any> { doesnt do anything except returns Observable. Feels redundant:
private detailSubject = new BehaviorSubject<any>(null);
message$ = this.detailSubject.asObservable();
sendMessage(formData: any) {
this.detailSubject.next({formData});
}
And
ngOnInit() {
this.articleService.message$.subscribe(...

Related

using return statement in an async to sync javascript function/class

I'm querying a mariadb using a class i wrote, my code works when i use console.log but not when i use a return statement:
class DBinteractor{
//constructor of my class
constructor(){
this.mariadb = require('mariadb');
this.pool = this.mariadb.createPool({
socketPath: '/run/mysql/mysql.sock',
user: 'me_user',
password: 'me_password',
database: 'me_database',
connectionLimit: 5
});
}
//asyncronous method
async asyncQuery(){
var quest = "SELECT DISTINCT `Modalite1` FROM `synth_globale` WHERE 1;";
try {
this.conn = await this.pool.getConnection();
const rows = await this.conn.query(quest);
this.conn.end();
return rows;
}
catch (err) {
throw err;
}
finally {
}
}
// I need at some point a method able to return the result of my query
// to put it in a variable and use it outside:
syncQuery(){
// as is, a non-async function/method can not include async calls
// I must use an iife to be able to do it
(async () => {
let ResultOfQueryWithinMethod = (await this.asyncQuery());
console.log(ResultOfQueryWithinMethod);
//OK, my result query is rightfully printed on the console
return(ResultOfQueryWithinMethod);
})()
}
}
queryator = new DBinteractor();
let ResultOfQueryOutsideMethod = queryator.syncQuery();
console.log(ResultOfQueryOutsideMethod);
//NOT OK, ResultOfQueryOutsideMethod is undefined
It's just like the return statement in syncQuery doesn't make the link between ResultOfQueryWithinMethod and ResultOfQueryOutsideMethod
What am i missing ?
thanks for your help

How to create an RxJS Observable such that it returns a value when call back function completes

I need to create an RxJS Observable such that it returns a value when call back function completes.
Below is the code, I have tried.
I want to return 'resources' to be returned in the caller subscribing to loadMarkerImages function
loadMarkerImages(markerNameAndImageUrlMap) {
let loader = new PIXI.loaders.Loader();
for (let markerKey in markerNameAndImageUrlMap) {
let imageUrl = markerNameAndImageUrlMap[markerKey];
loader.add(markerKey, imageUrl);
}
Observable.create()
return defer(() => {
loader.load((loader, resources) => {
return of(resources);
});
})
}
See the documentation for how to create an observable:
return new Observable(subscriber => {
let loader = new PIXI.loaders.Loader();
for (let markerKey in markerNameAndImageUrlMap) {
let imageUrl = markerNameAndImageUrlMap[markerKey];
loader.add(markerKey, imageUrl);
}
loader.load((loader, resources) => {
subscriber.next(resources);
subscriber.complete();
});
}
Make sure to also handle the error case if the loader.load() call can fail, though. Otherwise the returned observable will never emit, never complete, and never error.

angular 5, subject.next(value) does not fire

I have a problem trying to pass values into my subject and subscribing to it from another component. Here is my code that is supposed to pass my value into an observable.
private pdfLink = new Subject<string>();
pdfLinkCast = this.pdfLink.asObservable();
getPdfById(id: string): void {
this.httpClient.get<any>(this.apiUrl + id + '/pdf', this.httpOptions).subscribe((pdf) => {
// this prints
console.log(pdf);
// not sure if this is working as expected
this.pdfLink.next(pdf.url);
});
}
In my component I subscribe to it on ngOnInit as follows:
ngOnInit() {
this.subscription.add(this.someService.pdfLinkCast.subscribe((pdf) => {
// these do not print for some reason
console.log('hello world');
console.log(pdf);
}));
}

Angular5 RXJS recursive http requests

I currently have this situation:
#Service My Service
private users = ['user1','user2'];
//Generate list of requests to join
private getHttpList(): any[] {
let gets = new Array();
for(let index in this.users)
gets.push(this.http.get('https://api.github.com/users/' + this.users[index]))
return gets;
}
...
getList(): Observable<any[]> {
return forkJoin(this.getHttpList())
}
And in my component, I do the subscribe
this.MyService.getList().subscribe(results => {
for(let res in results) {
//...Do something here
//..I wanna do the get in of https://api.github.com/users/{user}/starred
}
})
Suppose that I just know that the "starred url" after the result of getList(), how to I can "synchronous" this part, or what's the correct form to do this?
**I try do it hardcoded --Result id wrong, because the "res" is a "interable"
this.MyService.getList().subscribe(results => {
let url = 'https://api.github.com/users/';
for(let res in results) {//This don't do the things "synchronous"
this.http.get(url + res.login +'/starred').catch(err => {
throw new Error(err.message);
}).subscribe(starred_res => {
//So we set the starred_list
res.starred_list = starred_res
})
}
})
Thanks...
As I understand you want to get starred list for every user.
The simplest way is to get all starred lists and match them with users result.
// Get users
this.MyService.getList().subscribe((results: any[]) => {
const url = 'https://api.github.com/users/';
// Create requests to get starred list for every user
const starredRequests = results.map(
res => this.http.get('https://api.github.com/users/' + res.login + '/starred')
);
// Wait when all starred requests done and map them with results array
Observable.forkJoin(starredRequests).subscribe(starred => {
results.forEach((res, index) => {
res.starred_list = starred[index];
});
console.log(results);
});
});

Admin on rest - implementing aor-realtime

I'm having a real hard time understanding how to implement aor-realtime (trying to use it with firebase; reads only, no write).
The first place I get stuck: This library generates a saga, right? How do I connect that with a restClient/resource? I have a few custom sagas that alert me on errors, but there is a main restClient/resource backing those. Those sagas just handles some side-effects. In this case, I just don't understand what the role of the client is, and how it interacts with the generated saga (or visa-versa)
The other question is with persistence: Updates stream in and the initial set of records is not loaded in one go. Should I be calling observer.next() with each update? or cache the updated records and call next() with the entire collection to-date.
Here's my current attempt at doing the later, but I'm still lost with how to connect it to my Admin/Resource.
import realtimeSaga from 'aor-realtime';
import { client, getToken } from '../firebase';
import { union } from 'lodash'
let cachedToken
const observeRequest = path => (type, resource, params) => {
// Filtering so that only chats are updated in real time
if (resource !== 'chat') return;
let results = {}
let ids = []
return {
subscribe(observer) {
let databaseRef = client.database().ref(path).orderByChild('at')
let events = [ 'child_added', 'child_changed' ]
events.forEach(e => {
databaseRef.on(e, ({ key, val }) => {
results[key] = val()
ids = union([ key ], ids)
observer.next(ids.map(id => results[id]))
})
})
const subscription = {
unsubscribe() {
// Clean up after ourselves
databaseRef.off()
results = {}
ids = []
// Notify the saga that we cleaned up everything
observer.complete();
}
};
return subscription;
},
};
};
export default path => realtimeSaga(observeRequest(path));
How do I connect that with a restClient/resource?
Just add the created saga to the custom sagas of your Admin component.
About the restClient, if you need it in your observer, then pass it the function which return your observer as you did with path. That's actually how it's done in the readme.
Should I be calling observer.next() with each update? or cache the updated records and call next() with the entire collection to-date.
It depends on the type parameter which is one of the admin-on-rest fetch types:
CRUD_GET_LIST: you should return the entire collection, updated
CRUD_GET_ONE: you should return the resource specified in params (which should contains its id)
Here's the solution I came up with, with guidance by #gildas:
import realtimeSaga from "aor-realtime";
import { client } from "../../../clients/firebase";
import { union } from "lodash";
const observeRequest = path => {
return (type, resource, params) => {
// Filtering so that only chats are updated in real time
if (resource !== "chats") return;
let results = {}
let ids = []
const updateItem = res => {
results[res.key] = { ...res.val(), id: res.key }
ids = Object.keys(results).sort((a, b) => results[b].at - results[a].at)
}
return {
subscribe(observer) {
const { page, perPage } = params.pagination
const offset = perPage * (page - 1)
const databaseRef = client
.database()
.ref(path)
.orderByChild("at")
.limitToLast(offset + perPage)
const notify = () => observer.next({ data: ids.slice(offset, offset + perPage).map(e => results[e]), total: ids.length + 1 })
databaseRef.once('value', snapshot => {
snapshot.forEach(updateItem)
notify()
})
databaseRef.on('child_changed', res => {
updateItem(res)
notify()
})
const subscription = {
unsubscribe() {
// Clean up after ourselves
databaseRef.off();
// Notify the saga that we cleaned up everything
observer.complete();
}
};
return subscription;
}
};
}
};
export default path => realtimeSaga(observeRequest(path));

Resources