Issue Regarding BehaviorSubject Observable - angular6

I am trying to Sync the data from REST API to my UI. but when i fetch the record from Rest API and transforms it,it gives an error of undefined:-
I am attaching my code:-
private datalist: Data[];
private dataUpdated = new Subject<Data[]>();
constructor(private http:HttpClient) {
}
getData()
{
this.http.get<{datalist:any}>("http://myserever/posts")
.pipe(map((dummydata)=>{
return dummydata.datalist.map(da=>{
return {
Status:da.status
};
})
}))
.subscribe(data=>{
this.datalist=data
console.log("The data is",data);
this.dataUpdated.next([...this.datalist]);
})
}
Actual Results:-
On pipe Operator it is giving me undefined Error, Here is my Error stack:-
ERROR TypeError: Cannot read property 'map' of undefined
at MapSubscriber.eval [as project] (get-dummy-data.service.ts:25)
at MapSubscriber._next (map.js:79)
at MapSubscriber.Subscriber.next (Subscriber.js:95)
at MapSubscriber._next (map.js:85)
at MapSubscriber.Subscriber.next (Subscriber.js:95)
at FilterSubscriber._next (filter.js:90)
at FilterSubscriber.Subscriber.next (Subscriber.js:95)
at MergeMapSubscriber.notifyNext (mergeMap.js:151)
at InnerSubscriber._next (InnerSubscriber.js:25)
at InnerSubscriber.Subscriber.next (Subscriber.js:95)
How i can solve the above probelm
Thank you

First of all you are not using a BehaviorSubject but a Subject (the difference matter, the behavior subject has a value at initialization, the Subject hasn't).
This post resume the difference What is the difference between Subject and BehaviorSubject?
It will depends of your needs to switch for a real behavior subject.
The error, "Cannot read property 'map' of undefined" could be due to your dummydata result that does not contains a datalist property (check casing, spelling ?)
The first map will just take the result of the request (dummydata), then the second will try to iterate on dummydata.datalist property (is it an array, an object?).
So you could check first if the dummydata.datalist property is not undefined, and that it is an iterable thing.
You could modify your code to be like this:
getData(){
this.http.get<{datalist:any}>("http://myserever/posts").pipe(
map(dummydata => dummydata.datalist.map(da => {
return {
Status: da.status
}
})),
// Catch it here
catchError(error => of([{Status: 'Fail'}]))
).subscribe(
data => {
this.datalist=data
console.log("The data is",data);
this.dataUpdated.next([...this.datalist]);
},
// Or catch it here
err => {
//Do your error handling
},
() => // Do something in any case
)
}
Hope this can help you.

Related

mediasoup-client TypeError: Cannot read property '_createTransport' of null at createRecvTransport

I've got an error in mediasoup-client while executing "device.createRecvTransport" in the Redux SAGA (I know this is not the best practice, but no choice).
"device.createRecvTransport" is actually an abstraction which holds a webRTC RTCPeerConnection instance. When I call it, it throws this error.
TypeError: Cannot read property '_createTransport' of null at createRecvTransport
the code:
function* createRecvTransport(device: Device) {
const {
id,
iceParameters,
iceCandidates,
dtlsParameters,
sctpParameters
} = yield sendRequest({
action: 'createWebRtcTransport',
data: {
forceTcp: false,
producing: false,
consuming: true
}
});
const recvTransport: Transport = yield call(device.createRecvTransport, {
id,
iceParameters,
iceCandidates,
dtlsParameters,
sctpParameters,
iceServers: []
});
}
the Device is declared with function
function* initDevice() {
const handlerName = detectDevice();
const device = new Device({
handlerName
});
const routerRtpCapabilities = yield sendRequest({
action: 'getRouterRtpCapabilities'
});
device.load({ routerRtpCapabilities });
}
"device.createSendTransport" method also works, the only issue is with creating Receive Transport. The method "router.createWebRtcTransport" get executed in the mediasoup router and it returns data before executing "createRecvTransport" in client side.
Seems the problem is with the "yield call" expression.
As the "device.createRecvTransport" isn't an async (handled with promise) function, it shouldn't be executed using "yield call".
When I removed "yield call", it fixed.

How to get the value of JSON Key when returned from API

My API returns a JSON object to angular function
I need to fetch the value of the key in that JSON.
If I print the value directly on the console, there is no error.
My Angular Code :
submit() : void {
console.log("FORM SUBMITTED")
console.log(JSON.stringify(this.register.value, undefined, 2));
this._registerService.register(this.register.value)
.subscribe(
data => {
console.log("DATA : ", JSON.stringify(data, undefined, 2));
console.log("Status : " + data.status);
if (data.status == "duplicate") {
console.log("DUPLICATE");
} else if (data.status == "success") {
console.log("SUCCESS");
}
},
error => {
console.log("ERRORrrr : ", JSON.stringify(error, undefined, 2));
this._router.navigate(['/500']);
}
)
}
In the above code
console.log("DATA : ", JSON.stringify(data, undefined, 2));
Works Fine.
It shows the data :
But If I try to fetch the value of "status" in "data",
console.log("Status : " + data.status);
It gives error :
error TS2339: Property 'status' does not exist on type 'Object'.
I need to use the value of status in if statement
Please help in getting the value of data.status
I don't know which version of rxjs you use, but in the current version you have to catch errors of Observables with catchError().
This would be my solution:
register(body: any): Observable<{status: string, summary: string, details: string}> {
return this._http.post(
'localhost:3000/register', body,
{observe: 'body'}).pipe(catchError(this.handleError));
}
Maybe that will solve your problem.
Your .register method seems to be returning a Observable<object>, therefore the TS compiler gives you this error. Perhaps it's better to make it a generic method:
register<T>(body: any) {
return this._http.post<T>(
'localhost:3000/register',
body,
{ observe: 'body' }
).catch(this.handleError);
}
Which you can call in your component:
this._registerService.register<RegisterData>(this.register.value).subscribe((data) => {
if (data.status) {
// this will not throw a compiler error anymore as it will be of type RegisterData
}
});
with the interface being:
export interface RegisterData {
status: string;
summary: string;
details: string;
}
I observed that the object which was returned was an associative array.
So I was able to parse the associative array like :
console.log(data["status"]);
and I was able to convert this array to JSON by :
let dataJson = JSON.parse(JSON.stringify(data))
After this conversion I could access the JSON Key value by :
console.log(dataJson.status);

How to catch a property of a JSON object from an Angular HTTP call and fix the "No property" error in Angular CLI?

I am using a public API to fetch movie data. And the following is my service method for getting that data from API:
getMovieList(): Observable<Movie[]> {
return this.http.get(this.moviesURL).pipe(
map((data: Movie[]) => data),
catchError(this.handleError),
);
}
And this is the method in the component for subscribing that data:
getMovieList(): void {
this.movieApiService.getMovieList()
.subscribe(
(data: Movie[]) => {
this.movieList = data.results;
}
);
}
The problem is that the API returns an object which has 4 properties: page, results, total_pages, total_results. And I only need the results property. But when I try to assign data.results to my component's property or send data.results from my service method instead of data then angular cli gives an error of "results is an undefined property of data". My question is how do I get the results property directly without having to touch the data object and i also need to assign Movie[] type to the results. But currently I am setting the type to the data object.
The problem lies in your model, you defined that you expect array of Movies but you receive the object with 4 properties which one of them called results are the model you defined, so the solution is:
Define the interface like this:
export interface IDataFromApi {
results: Movie[];
page: number;
total_pages: number;
total_results: number;
}
Then the first function will be:
getMovieList(): Observable<IDataFromApi> {
return this.http.get(this.moviesURL).pipe(
map((data: IDataFromApi) => data),
catchError(this.handleError),
);
And method in component:
getMovieList(): void {
this.movieApiService.getMovieList()
.subscribe(
(data: IDataFromApi) => {
this.movieList = data.results;
}
);
}

Node.js ERROR: (node:9748) UnhandledPromiseRejectionWarning: Unhandled promise rejection

I'm trying to get a json from "nightmare" in Node.js and then use JSON.parse(), but I'm getting the following error:
(node:9748) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): SyntaxError: Unexpected token ☻ in JSON at position 18509
My code:
var nightmare = Nightmare()
.goto('URL')
.wait(10000) // Need wait some time
.evaluate(() => {
return document.body.innerText;
})
.end()
.then((body) => {
var data;
try {
data = JSON.parse(body);
} catch(e) {
console.log(e);
}
callback(null, data);
});
You can check if the JSON is valid or not simply using the JSON.parse function as you are using.
function validJSON(str) {
try {
// try to parse the JSON
JSON.parse(str);
} catch (e) {
// if not a json
return false;
}
// if it's valid json
return true;
}
It'll check if the string is valid json or not. Now, you can use it with your nightmareJS.
const nightmare = Nightmare()
.goto("URL")
.wait(10000) // Need wait some time
.evaluate(() => {
return document.body.innerText;
})
.end()
.then(body => {
// if it's a valid json, send it,
// otherwise send it as a body object
const data = validJSON(body) ? body : { body };
callback(null, data);
});
Now, the error is showing because you said to catch(e) and console.log(e) the error. Thus it's simply obeying your command.
Since the emoji itself is not a valid json, you have to either make a json from it, or parse it if it was a json string.
A valid json object might look like this,
{emoji: "☻"}
You see how it's all quoted?

Angular4 giving 404 for json data that exists and is publicly serving

I have a test data service written in Angular4. It currently looks like this:
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise'
#Injectable()
export class DataService {
constructor(private http: Http) { }
fetchData(){
return this.http.get('https://dinstruct-d4b62.firebaseio.com/.json').map(
(res) => res.json()).toPromise();
}
}
With thanks to "The Net Ninja" for this code, as this section of the app is basically exactly the same as the tutorial code (I prefer to have something that should be a known working example for testing purposes when building new apps)...
The problem is that though there is definitely test data at https://dinstruct-d4b62.firebaseio.com/.json, which is not hidden or firewalled in any way as far as I can tell (directly accessible via browser), when the app enters the fetchData() function, it logs:
ERROR Error: Uncaught (in promise): Error: Response with status: 404 Not Found for URL: https://dinstruct-d4b62.firebaseio.com/.json
Error: Response with status: 404 Not Found for URL: https://dinstruct-d4b62.firebaseio.com/.json
at the start of the stack trace. What could be going on here?
Update:
I also noticed that in the calling function:
ngOnInit(): void {
this.customerService.getCustomers()
.then(customers => this.customers = customers);
this.dataService.fetchData().subscribe(
(data) => console.log(data));
}
When I have this.dataService.fetchData().subscribe((data) => console.log(data)); in the code, clicking a link to the dashboard it momentarily shows localhost:3000/dashboard in the browser address bar but then immediate flicks back to showing the previous URL. However, when I remove this line, the app correctly shows localhost:3000/dashboard the whole time. I assume this is probably related to the console.logged 404 error.
Also perplexing is that when I check the network traffic, no 404 is shown.
Update:
When the observable is change to a promise I get this output in the console:
Response {_body: Object, status: 404, ok: false, statusText: "Not Found", headers: Headers…}
headers
:
Headers
ok
:
false
status
:
404
statusText
:
"Not Found"
type
:
null
url
:
"https://dinstruct-d4b62.firebaseio.com/.json"
_body
:
Object
error
:
"Collection 'undefined' not found"
__proto__
:
Object
constructor
:
function Object()
hasOwnProperty
:
function hasOwnProperty()
isPrototypeOf
:
function isPrototypeOf()
propertyIsEnumerable
:
function propertyIsEnumerable()
toLocaleString
:
function toLocaleString()
toString
:
function ()
valueOf
:
function valueOf()
__defineGetter__
:
function __defineGetter__()
__defineSetter__
:
function __defineSetter__()
__lookupGetter__
:
function __lookupGetter__()
__lookupSetter__
:
function __lookupSetter__()
get __proto__
:
function __proto__()
set __proto__
:
function __proto__()
__proto__
:
Body
constructor
:
function Response(responseOptions)
toString
:
function ()
__proto__
:
Object
There is still no 404 in the network traffic.
I have now updated the calling function to this:
ngOnInit(): void {
this.customerService.getCustomers()
.then(customers => this.customers = customers);
this.dataService.fetchData().then((data) => {
console.log(data);
})
.catch((error) => console.error(error));
}
The in-memory-web-api will interfere with your "outside" requests. You need to remove that from your NgModule, since otherwise Angular is always trying to look in in-memory-web-api for your requests, which obviously doesn't exist in that place. So removing the equivalent of
InMemoryWebApiModule.forRoot(InMemoryDataService)
from your ngModule and that should clear it out! :)
Try importing import 'rxjs/add/operator/toPromise';
and add toPromise to the end of the http get in the the fetchData() function.
fetchData(){
return this.http.get('https://dinstruct-d4b62.firebaseio.com/.json').map(
(res) => res.json()).toPromise();
}
Your calling function should then look like this:
this.dataService.fetchData()
.then((data) => {
console.log(data);
})
.catch((error) => console.error(error));
In AppModule.ts where you have imports[], you would have imported the HttpClientInMemoryWebApiModule
like =>
HttpClientInMemoryWebApiModule
.forRoot(
InMemoryService, { dataEncapsulation: false }
), 
Now What is happening here is that your application is searching for the public API in the in-memory web API only to solve this just tell In memory module not to behave like that by setting the passing though unknown Url true
like =>
HttpClientInMemoryWebApiModule
.forRoot(
InMemoryService, { dataEncapsulation: false, passThruUnknownUrl: true }
)