I'm trying to make an application with both front-end and back-end. I have finished both, but now I'm having some trouble trying to connect them. I keep getting this error:
catalog.component.ts:45 ERROR Error: NG0900: Error trying to diff '[object Object]'. Only arrays and iterables are allowed
at DefaultIterableDiffer.diff (core.mjs:28514:19)
First, I'm trying to get the array response, where the products are located:
product.service.ts
public getAll(): Observable<Product[]> {
return this.http.get<Response["response"]>(this.productsUrl);
}
This method receives the following response:
{
"httpCode": 200,
"message": "OK",
"response": [
{
"pieceName": "Mini Figure Trophy",
"pieceImageURL": "https://www.lego.com/cdn/product-assets/element.img.lod5photo.192x192/6335932.jpg",
"piecePrice": 0.3,
"pieceTag": "Bestseller",
},
{
"pieceName": "Animal No. 17 Dog",
"pieceImageURL": "https://www.lego.com/cdn/product-assets/element.img.lod5photo.192x192/6076467.jpg",
"piecePrice": 2.76,
"pieceTag": "Bestseller",
}
]
}
Then, when my catalog page opens, I run these two functions:
catalog.component.ts
ngOnInit(): void {
this.getProducts();
this.searchSubject.subscribe(value => this.searchService.setSearchValue(value));
this.searchService.searchValue$.subscribe(value => {
this.productService.getProductByNameLike(value).subscribe(productsCalled => {
this.products = productsCalled})
})
}
getProducts(): void {
this.productService.getAll().subscribe({ <- Line where the error occurs
next: (productsCalled: Product[]) => {
this.products = productsCalled
this.checkProductsOnCart()
},
error: (err) => console.log(err),
complete: () => console.log("completo")
});
}
But I keep getting the NG0900 error. I believe it might be because I'm not reading the array where the products are.
I have changed the getAll method, as originally it was:
public getAll(): Observable<Product[]> {
return this.http.get<Product[]>(this.productsUrl);
}
I also tried searching for other responses here, but none seem to be applicable to my problem, or maybe I'm just too much of a newbie to see the relation. Does anyone know what am I doing wrong here? Thanks in advance.
Your JSON response is an object.
export interface ProductListResponse {
httpCode: Number;
message: string;
response: Product[];
}
Work with map from rxjs to return the array from the response property.
import { map } from 'rxjs';
public getAll(): Observable<Product[]> {
return this.http.get<ProductListResponse>(this.productsUrl)
.pipe(map((data) => data.response));
}
Related
I am trying to use the nativescript-ocr plugin, and keep on getting this error message
CONSOLE ERROR file:///app/newcard/newcard.component.js:133:34: {
"error": "Recognize failed, check the log for possible details."
}
It is very unhelpful, and i have been stuck on it for too long.
Bellow you can see how i am implementing the ocr:
doRecognize(source: string): void {
console.log({source});
let img: ImageSource = new ImageSource()
img.fromResource(source).then((success: boolean) => {
if (success) {
this.ocr.retrieveText({
image: img,
language: 'eng',
onProgress: (percentage: number ) => {
console.log(`Decoding progress: ${percentage}%`);
}
}).then(
(result: RetrieveTextResult) => {
console.log(`Result: ${result.text}`);
},
(error) => {
})
}
});
}
The source string looks like so:
CONSOLE LOG file:///app/newcard/newcard.component.js:122:20: {
"source":
"file:///Users/georgekyr/Library/Developer/CoreSimulator/Devices/0723299A-7C8B-40C3-AE74- FEE8E08BB52D/data/Media/DCIM/100APPLE/IMG_0007.PNG"
}
Looking around, I find that there are cases wehere the folder app/tesseract/tessadata was created in the wrong way, so i have double checked that the folder exists in the right place with the right data in it.
I am trying to parse an array inside an object. I tried to map the result to get the array but could not reach to the point of the array.
My JSON looks like this.
{
"id": 1,
"projectName": "Opera house",
"projectDescription": "This image was taken during my first photography course.",
"thumbnailImageName": "1.JPG",
"projectDetails": {
"id": 1,
"relatedPhotos": [
"1.JPG",
"2.JPG",
"3.JPG"
],
"location": "Sydney",
"scope": "Learn basic of photography",
"description": "Some description"
},
"favouriteProject": true
}
And I am mapping the HTTP response from a server like this.
this.projectService.getProjectDetailsByProjectName(projectName).subscribe(res =>
{
Object.keys(res).map(key => {
this.projectDetails = res[key];
})
});
The above mapping gives me the projectDetails object but cannot access the array inside it. While accessing the array, I get output three times. Two times undefined and finally the actual value. Can anyone guide me how to parse the above JSON file properly?
Thank you very much..
************Edited code****************
My code to get the http response and parse each object is as follows:
getSelectedProjectWithDetails(){
const projectName:string = this.activatedRoute.snapshot.paramMap.get("project-name");
this.projectService.getProjectDetailsByProjectName(projectName).subscribe(res => {
// console.log(res.relatedPhotos);
Object.keys(res).map( (key, value) => {
this.projectDetails = res[key];
console.log(this.projectDetails["relatedPhotos"])
})
})
}
I have project interface as
export interface project{
id:number;
projectName: string;
projectDescription: string;
favouriteProject: boolean;
thumbnailImageName: string;
projectDetail: projectDetail;
}
and projectDetails interface as:
export interface projectDetail{
id: number;
relatedPhotos: String [];
location: string;
scope: string;
description: string;
}
and http get request is
getProjectDetailsByProjectName(projectName: String): Observable<project>{
return this.http.get<project>("http://127.0.0.1:8080/project/"+projectName);
}
As an alternate you can user JSON.parse(res); after you have mapped your response from observable.
like this
Object.keys(res).map(key => {
JSON.parse(res);
this.projectDetails = res[key];
})
However I am using res.json();
addNewProduct(data: any): Observable<string> {
return this._http.post(this.addNewProdUrl, data).map(res => res.json());
}
Not sure what is the issue with your res.
You can use map() to transform HttpResponse body to JSON using json() method. Since response contains body, headers etc. json() can be used to only parse body.
Please look into below code to understand the same.
this.http.get('https://api.github.com/users')
.map(response => response.json())
.subscribe(data => console.log(data));
To know more, please refer documentation
I would like the proper way to convert an object of type any to an object that conforms to a particular interface, say ApiResponse with proper error handling if it doesn't have the necessary properties for it to become that object. The object of type any came from a JSON payload, from a JSON.parse or equivalent. I would ideally like some proper error handling dealing with this conversion, as well. I have come up with the following approach, but not sure if it's using TypeScript properly or exploiting the best patterns.
`
export interface ApiResponse {
code: number
type: string
message: string
}
export function readApiResponse(json: any): ApiResponse {
if (!json.hasOwnProperty('code')) {
throw 'No code property'
}
if (!json.hasOwnProperty('type')) {
throw 'No type property'
}
if (!json.hasOwnProperty('message')) {
throw 'No message property'
}
return json
}
loadData() {
fetch("data.json")
.then(response => response.json())
.then( (json: any) => {
console.log(json)
let r = readApiResponse(json)
console.log(r)
this.setState( {message : r.message })
})
.catch ( (error) => {
console.log(error)
})
}
`
I have a webapp that gets via Json stuff put it in objects to display them.
I already did it two times with services and classes.
But now i copy and paste the old code make some slight changes to make sure it redirect to the good classes but now i get an array with functions instead an array with objects.
Here is my constructor that calls upon the the service classes and send things to the console
constructor(private featureService : FeatureService, private scenarioservice : ScenarioService, private failuresService : FailuresService){
//hier worden de features en failures opgehaald
this.featureService.getFeatures().subscribe(res => {
this.featureArray = res.getFeatureArray();
console.log(res.getFeatureArray());
});
this.failuresService.getFailures().subscribe(res => {
this.failureArray = res.getFailureArray();
console.log(res.failures[0].method);
console.log(this.failureArray);
});
}
}
Here is failuresService.getFailures:
import { Injectable } from "#angular/core";
import {Http, Response} from "#angular/http";
import {Failure} from "./Failure";
import {Failures} from "./failures";
#Injectable()
export class FailuresService {
constructor(protected http: Http) {}
getFailures() {
return this.http.get('http://localhost:8080/testresultaten')
.map((response: Response) => response.json())
.map(({failures = [Failure]}) => new Failures(failures));// deze error is bullshit
}
}
This is the Json that I get and want to get in an class:
{
"failures:": [
{
"method": "canRollOneGame",
"object": "BowlingGame.GameTest"
},
{
"method": "canCountNighteeneight",
"object": "FizzBuzz.FizzBuzzTest"
}
]
}
Here are the Failure and Failures classes:
import {Failure} from "./Failure";
export class Failures {
constructor(public failures : Failure[]){}
public getFailureArray(): Failure[]{
return this.failures;
}
}
export class Failure{
constructor(public method : String , public object : String ){ }
}
I could be wrong but this doesn't look right:
getFailures() {
return this.http.get('http://localhost:8080/testresultaten')
.map((response: Response) => response.json())
.map(({failures = [Failure]}) => new Failures(failures));// deze error is bullshit
}
That last mapping, I'm not sure what it is supposed to do. I've never seen that syntax (doesn't mean it's wrong). I get that you have an incoming array. But what this syntax does {failures = [Failure]} is what I think your problem is. I don't think that will do what you think.
Try this and see what happens:
.map(failures => { console.log ( failures ); new Failures(failures) } );// deze error is bullshit
If you try that with your old mapping, and then this new one, it'd be interesting to see what that console.log traces out. I think doing it your way, you won't see what you expect.
If that sorts you out, then you can try typing the incoming payload (though I'm not sure it'll work; it should be receiving JSON from the previous mapping).
.map( (failures: Array<Failure>) => { console.log ( failures ); new Failures(failures) } );
So if I read it correctly: Your goal is to create an array of Failure objects with the values coming from a JSON array where each of this has a method you'd like to execute somewhere in the code.
If thats the case then I understand what went wrong. As Tim Consolazion mentioned in the comments you only get the values for the Failure object not the Failure object itself (See custom created method error: "is not a function"). So in order to execute the commands from Failure you have to create for each object in your JSON array a Failure object. Something like this:
return this.http.get('http://localhost:8080/testresultaten')
.map((response: Response) => {
let content = response.json();
let failureList: Failure[] = [];
content.forEach(failure => {
failureList.push(new Failure(failure.method, failure.object))
});
return failureList || {};
}
What I wonder is where you found {failures = [Failure]}? I've never seen this before and I've no idea what this is for.
EDIT: I edited the question so it fits your class Failure. The failure in content.forEach(failure => { in an object from your JSON array. You can access the values of it like it is a normal object. In your case with failure.method and failure.object.
I found my problem in the Json the name was function: but in my code it was function so all that was necessary was to make sure it sends function instead of function:
Consider this simple snippet of an AngularJS 2 application:
TestObject
export class TestObject {
id: number;
name: string;
}
TestService
[...]
export class TestService {
constructor(private http: Http) {}
test(): Observable<TestObject> {
return this.http
.get("http://www.example.com")
.map(this.save)
.catch(this.fail);
}
private save(response: Response) {
let testObject: TestObject = <TestObject> response.json();
return testObject || {};
}
private fail(error: any) {
return Observable.throw("error!");
}
}
AppComponent
[...]
export class AppComponent implements OnInit {
testObject: TestObject;
constructor(private testService: testService) {}
ngOnInit() {
this.testService.test().subscribe(
data => {
this.testObject = new TestObject();
console.log(this.testObject); // prints (empty) TestObject
this.testObject = data;
console.log(this.testObject); // prints object, not TestObject?
},
error => { }
);
}
}
Here my questions:
1) Why does my application print out (using Chrome Inspector) object and not TestObject as type?
2) The property testObject of class AppComponent should be of type TestObject. Why does my application not fail?
3) How can I achieve that I really get TestObject? What would be the best way to do it? Of course I could just manually fill up my TestObject, but I hoped there is some way of automatically mapping the json to my object.
Here is an answer that I wrote to a question which explained the handling of observables in angular2.
Angular 2 http post is returning 200 but no response is returned
Here you can see how I am handling the Response object as returned by the service. It is very important that you return your response object from the map function in service.
Similarly you can convert your response object to typescript type by casting your response object. The example can be:
this._loginService.login(this.username, this.password)
.subscribe(
(response) => {
//Here you can map the response to a type.
this.apiResult = <IUser>response.json();
//You cannot log your object here. Here you can only map.
},
(err) => {
//Here you can catch the error
},
() => {
//this is fired after the api requeest is completed.
//here you can log your object.
console.log(this.apiResult);
//result will only be shown here.
}
);
Here, it can be clearly seen that I am casting the response object to IUser type.
Another thing is while handling apiresponse in your component it is to be noted that the subscribe function has three arguments and if you will like to log your object, you must do it in the last function of subscribe.
Hope this helps!
your call must be like
ngOnInit() {
this.testService.test().subscribe(
(data) => {
this.testObject = new TestObject();
console.log(this.testObject); // prints (empty) TestObject
//only mapping
this.testObject = data;
},
error => { },
() => {
console.log(this.testObject);
}
);
}