I'm using WP Rest API to access my Wordpress database with Angular 2. I use their post API and return a json object which I map to create an object.
Object:
export class BlogPost {
date: Date;
id: number;
link: string;
title: string;
author: number;
excerpt: string;
featuredMediaURL: string;
featuredMediaID: number;
categories: string[];
tags: string[];
constructor(obj?: any) {
this.date = obj && obj.date || null;
this.id = obj && obj.id || null;
this.link = obj && obj.link || null;
this.title = obj && obj.title || null;
this.author = obj && obj.author || null;
this.excerpt = obj && obj.excerpt || null;
this.featuredMediaURL = obj && obj.featuredMediaURL || null;
this.featuredMediaID = obj && obj.featuredMediaID || null;
this.categories = obj && obj.categories || null;
this.tags = obj && obj.tags || null;
}
}
Service:
export class BlogService {
constructor(public http: Http,
#Inject(DOMAIN) private domain: string) { }
getPost(): Observable<BlogPost[]> {
return this.http.get(`${this.domain}/wp-json/wp/v2/posts/?page=1`)
.map((response: Response) => {
return (<any>response.json()).map(item => {
return new BlogPost({
date: item.date,
id: item.id,
link: item.link,
title: item.title,
author: item.author,
excerpt: item.excerpt,
featuredMediaID: item.featured_media,
categories: item.categories,
tags: item.tags
});
});
});
}
My problem is that for certain properties such as media, the API returns an ID for the media and not the url. I was able to mix and match and get the url into the template by creating a separate service which returns all media stored on the database and then compares the id numbers between the two arrays and returns the correct one:
mediaURL(id: number): string {
for (let med of this.media) {
if(med.id === id) {
return med.url;
};
};
return 'error';
}
but this is a bit tedious. I was wondering if there is a clean rxjs way to do this by issuing a
this.http.get(`${this._domain}/wp-json/wp/v2/media/<id>`)
line and mapping it to the BlogPost.featuredMediaURL before the whole array of posts is returned to the blog component.
I've messed around with it for a day trying several things and I'm at a loss.
Related
I'm trying to get the last date in the request notes and show it with console.log(), i used console.log(this.changeRequest.reduce((a, b) => (a.ModificationDate > b.ModificationDate ? a : b))); to show the latest date on update and what it show is not the latest date, here is some screens to show the result :
Here is the changeRequest Modal :
export class ChangeRequestModel {
CRId: string;
RId: string;
UserName: string;
Comment: string;
Action: string;
Type: string;
Modified: boolean;
Deleted: boolean;
ActionDate: Date;
ModificationDate: Date;
Request: RequestViewmodel;
constructor(changeRequest?) {
changeRequest = changeRequest || {};
this.CRId = changeRequest.CRId || "0000000001";
this.RId = changeRequest.RId || "";
this.UserName = changeRequest.UserName || "";
this.Comment = changeRequest.Comment;
this.Action = changeRequest.Action;
this.Type = changeRequest.Type;
this.Modified = changeRequest.Modified;
this.Deleted = changeRequest.Deleted;
this.ActionDate = changeRequest.ActionDate;
this.ModificationDate = changeRequest.ModificationDate;
this.Request = changeRequest.Request;
}
}
This is changeRequest type : changeRequest: ChangeRequestModel[];
This is the getRequest in the component.ts :
getRequestInfo() {
this._requestService.getRequestById(this.requestId).subscribe(
(res: any) => {
if (res) {
this.requestInfo = res;
this.getChangeRequestInfo();
this.PId = res.PId;
this._jobPositionService
.GeJobPositionById(this.PId)
.subscribe((res: any) => {
this.jobPositionInfo = res;
});
}
},
(err) => {
this._snotify.error("Error loading request informations");
}
);
}
This is the getChangeRequest in the component.ts :
getChangeRequestInfo() {
this._changeRequestService.getChangeRequestsByRId(this.requestId).subscribe(
(res: any) => {
this.changeRequest = res.changeRequestList;
if(this.requestInfo.RequestStatus.Text == "Closed")
{
for (let i = 0; i < this.changeRequest?.length; i++) {
var str = this.changeRequest[i]?.Comment ;
var commentPattern = str?.match(/(?:closed|Closed)+$/gm);
console.log(this.changeRequest[i].ModificationDate);
if (commentPattern?.length == null) {
console.log(str);
console.log("no match");
} else if (commentPattern?.length > 0 && this.requestInfo.RequestStatus.Text != "Closed") {
console.log(str);
console.log("Request not closed yet");
}
else if (commentPattern?.length > 0 && this.requestInfo.RequestStatus.Text == "Closed") {
console.log(str);
console.log("match");
console.log(this.changeRequest.reduce((a, b) => (a.ModificationDate > b.ModificationDate ? a : b)));
}
}
}
}
);
}
For some requests it show me a correct result and for some requests it shows me a wrong result like the one shown before, can anyone help me ?
I want to serialize circular reference to JSON
This is the part generating the JSON array and it causes a circular reference because it creates a child inside an element and I want to display the result.
const mappedData = this.state.treeData
.filter(data => data.title === "Category")
.map(categ => {
const { id, title, children, subtitle, type } = categ;
function getChildren(children) {
return children
? children.map(child => {
if (child.title === "Item" || child.title === "Group") {
const data = {
id: child.id,
name: child.subtitle,
type: child.type,
children: getChildren(child.children),
child_id: child.children
? child.children.map(child => child.id)
: []
};
if (data.children.length === 0) delete data.children;
if (data.child_id.length === 0) delete data.child_id;
return data;
} else {
return {
id: child.id,
name: child.subtitle,
type: child.type
};
}
})
: [];
}
const data = {
id: id,
name: subtitle,
type: type,
children: getChildren(children),
child_id: children ? children.map(child => child.id) : []
};
if (data.children.length === 0) delete data.children;
if (data.child_id.length === 0) delete data.child_id;
return data;
});
The HTML part that calls the stringify method
<div className="json">
<p> {JSON.stringify(mappedData)}</p>
</div>
I found a Replacer that it works but the JSON result is too long for what I need
const getCircularReplacer = () => {
const seen = new WeakSet();
return (key, value) => {
if (typeof value === "object" && value !== null) {
if (seen.has(value)) {
return;
}
seen.add(value);
}
return value;
};
};
JSON.stringify(circularReference, getCircularReplacer());
And here's the result :
[{"id":"7a69fc68","name":{"type":"input","key":null,"ref":null,"props":{"className":"inputSubs","type":"text","placeholder":"Category Name"},"_owner":{"tag":1,"key":null,"stateNode":{"props":{},"context":{},"refs":{},"updater":{},"notificationAlert":{"current":{"props":{},"refs":{"notifications":{"__reactInternalInstance$6qqi1p3qi9b":{"tag":5,"key":null,"elementType":"div","type":"div","return":{"tag":1,"key":null,"return":{"tag":5,"key":null,"elementType":"div","type" .. etc
Any Help ?
Okej so Im trying to map a list of .Net objects to my Angular frontend by way of Web Api 2. The objects are sent, I get them, but depending on the circumstances the objects and their properties might be an Employment reference, Assignment reference or an Assignment organization unit reference.
Here is an image of how the list of objects can look, with one AssignmentHolder that can be one of those three classes and a list of DependentEntities that can be one of those three classes.
Here is how they look in my Angular app:
This is the object containing them:
#JsonObject('AssignmentListItem')
export class AssignmentListItem {
#JsonProperty('AssignmentHolder')
AssignmentHolder: any = undefined;
#JsonProperty('DependentEntities')
DependentEntities: any = undefined;
#JsonProperty('AssignmentRoles', [AssignmentRole])
AssignmentRoles: AssignmentRole[] = undefined;
#JsonProperty('NumberOfDependentEntities', Number)
NumberOfDependentEntities: Number = undefined;
#JsonProperty('IsInherited', Boolean)
IsInherited: boolean = undefined;
}
These are the classes.
#JsonObject('ReferenceBase')
export class ReferenceBase {
#JsonProperty('OrganizationRegistrationNumber', OrganizationRegistrationNumber)
OrganizationRegistrationNumber: OrganizationRegistrationNumber = undefined;
#JsonProperty('IsIncomplete', Boolean)
IsIncomplete: Boolean = undefined;
#JsonProperty('SortingName', String)
SortingName: string = undefined;
}
-------
#JsonObject('EmploymentReference')
export class EmploymentReference extends ReferenceBase {
#JsonProperty('NationalCivicRegistrationNumber', String)
NationalCivicRegistrationNumber: NationalCivicRegistrationNumber = undefined;
#JsonProperty('GivenName', String)
GivenName: string = undefined;
#JsonProperty('Surname', String)
Surname: string = undefined;
#JsonProperty('FullName', String)
FullName: string = undefined;
constructor() {
super();
this.FullName = (this.GivenName + ' ' + this.Surname);
this.SortingName = this.FullName;
}
}
-----
#JsonObject('AssignmentReference')
export class AssignmentReference extends ReferenceBase {
#JsonProperty('AssignmentRoles', [AssignmentRole])
AssignmentRoles: AssignmentRole[] = undefined;
#JsonProperty('OrganizationName', String)
OrganizationName: string = undefined;
#JsonProperty('NationalCivicRegistrationNumber', NationalCivicRegistrationNumber)
NationalCivicRegistrationNumber: NationalCivicRegistrationNumber = undefined;
#JsonProperty('Surname', String)
Surname: string = undefined;
#JsonProperty('FullName', String)
FullName: string = undefined;
#JsonProperty('GivenName', String)
GivenName: string = undefined;
}
------
#JsonObject('AssignmentOrganizationalUnitReference')
export class AssignmentOrganizationalUnitReference extends ReferenceBase {
#JsonProperty('OrganizationName', String)
OrganizationName: string = undefined;
#JsonProperty('Name', String)
Name: string = undefined;
#JsonProperty('Active', Boolean)
Active: Boolean = undefined;
#JsonProperty('IncludeSubUnits', Boolean)
IncludeSubUnits: Boolean = undefined;
#JsonProperty('AssignmentRoles', [AssignmentRole])
AssignmentRoles: AssignmentRole[] = undefined;
#JsonProperty('UnitId', String)
UnitId: string = undefined;
#JsonProperty('Type', OrganizationalUnitReferenceType)
Type: OrganizationalUnitReferenceType = undefined;
}
So those are the objects I want to map too depending on what Is in the assignmentlist I get back
This is my custom DTO so that I can use a custom converter:
#JsonObject('AssignmentsDto')
export class AssignmentsDto {
#JsonProperty('AssignmentList', ObjectConverter)
AssignmentList: AssignmentListItem[] = undefined;
}
this is my JsonCustomConverter
#JsonConverter
export class ObjectConverter implements JsonCustomConvert<AssignmentListItem[]> {
// We receive the instance and just serialize it with the standard json2typescript method.
serialize(assignmentListItems: AssignmentListItem[]): any {
const jsonConvert = new JsonConvert();
return jsonConvert.serialize(assignmentListItems);
}
// We receive a json object (not string) and decide
// based on the given properties whether we want to
// create an instance of AssignmentReference or AssignmentOrgUnitReference.
deserialize(assignmentListItems: any): AssignmentListItem[] {
const jsonConvert = new JsonConvert();
let assignments = new Array<AssignmentListItem>();
//Map the Holder entity.
for (let assignment of assignmentListItems) {
if (assignment.AssignmentHolder['__type'] === 'something.something.Web.Models.EmploymentReference' ||
assignment.AssignmentHolder['__type'] === 'something.something.Web.Models.AssignmentEmploymentReference') {
let tempAssignment: AssignmentListItem = jsonConvert.deserialize(assignment.AssignmentHolder, EmploymentReference);
//For every assignment there is a list of Dependents. Here we map those.
for (let dependent of assignment.DependentEntities) {
if (dependent['__type'] === 'something.something.Web.Models.EmploymentReference' ||
dependent['__type'] === 'something.something.Web.Models.AssignmentEmploymentReference') {
let tempDependent: EmploymentReference = jsonConvert.deserialize(dependent, EmploymentReference);
tempAssignment.DependentEntities.push(tempDependent);
} else if (dependent['__type'] === 'something.something.Web.Models.AssignmentOrganizationalUnitReference') {
let tempDependent: AssignmentOrganizationalUnitReference = jsonConvert.deserialize(dependent, AssignmentOrganizationalUnitReference);
tempAssignment.DependentEntities.push(tempDependent);
}
}
assignments.push(tempAssignment);
} else if (assignment.AssignmentHolder['__type'] === 'something.something.Web.Models.AssignmentOrganizationalUnitReference') {
let tempAssignment: AssignmentListItem = jsonConvert.deserialize(assignment.AssignmentHolder, AssignmentOrganizationalUnitReference);
//For every assignment there is a list of Dependents. Here we map those.
for (let dependent of assignment.DependentEntities) {
if (dependent['__type'] === 'something.something.Web.Models.EmploymentReference' ||
dependent['__type'] === 'something.something.Web.Models.AssignmentEmploymentReference') {
let tempDependent: EmploymentReference = jsonConvert.deserialize(dependent, EmploymentReference);
tempAssignment.DependentEntities.push(tempDependent);
} else if (dependent['__type'] === 'something.something.Web.Models.AssignmentOrganizationalUnitReference') {
let tempDependent: AssignmentOrganizationalUnitReference = jsonConvert.deserialize(dependent, AssignmentOrganizationalUnitReference);
tempAssignment.DependentEntities.push(tempDependent);
}
}
assignments.push(tempAssignment);
}
}
console.log('return ', assignments);
return assignments;
}
}
And finally, this is the Assignment Api Service where i use the converter.
// GET LIST OF ASSIGNMENTS
getAssignmentList(
filterStr: string,
orgNoParam: string,
skip: number,
take: number
): Observable<any> {
// set headers
let head = new HttpHeaders();
head = head.append('Content-Type', 'application/json');
// set binds to model reciever
const data = {
'orgNoParam': orgNoParam,
'filterStr': filterStr,
};
let body = JSON.stringify(data);
// set query parameters
let url = this.assignmentListUrl + '?skip=' + skip + '&take=' + take;
return this.http.post<any>(url, body, { headers: head })
.map(this.convertData)
.catch(this.handleError);
}
private convertData(res: Response) {
let jsonConvert = new JsonConvert();
jsonConvert.valueCheckingMode = ValueCheckingMode.ALLOW_NULL;
let deSerializedAssignments: AssignmentListItem[] = jsonConvert.deserialize(res, AssignmentsDto).AssignmentList;
return deSerializedAssignments;
The error I get in console is :
Fatal error in JsonConvert. Failed to map the JSON object to the JavaScript class "AssignmentsDto" because of a type error. Class property: AssignmentList Expected type: undefined JSON property: AssignmentList JSON type: [object, object, object, object, object]
I solved this by making sure every single property from the json object was being mapped to the typescript classes and in AssignmentsDto I added a second The object property as well as the converter, like so:
#JsonProperty('AssignmentList',[AssignmentListItem], ObjectConverter)
AssignmentList: AssignmentListItem[] = undefined;
Hope this helps someone!
I'm getting this error at angular service's map method but my returned datas doesn't seem to contain any circular reference, here is my json object:
[{"id":14,
"sender":
{"id":20,"email":"p.martelliere#gmail.com","username":"test5","roles":
["ROLE_USER"],"status":"active","note":"0","points":0,
"devices":[],"job":"Caisse","showJob":false,"notificationsActivated":true,
"connected":true,"tokenConfirm":"","birthDate":[]
},"receiver":
{"id":12,"email":"test2#yopmail.com","username":"test2","tokenConfirm":"",
"job":"g\u00e9rant","showJob":false,"note":"0","points":0,
"roles":["ROLE_USER"],"status":"active","notificationsActivated":true,
"connected":true,"devices":[]
},
"myNeed":"Te ster",
"whatICanGive":"1",
"messages":[],
"status":"active"
}]
Here's my chatRequest angular Entity:
export class NmChatRequest {
// Raw attributes
id : number;
myNeed : string;
whatICanGive : string;
status : string;
createdAt : Date;
updatedAt : Date;
deletedAt : Date;
// x-to-one
id_receiver: number;
constructor(json? : any) {
if (json != null) {
this.id = json.id;
this.myNeed = json.myNeed;
this.whatICanGive = json.whatICanGive;
this.status = json.status;
this.id_receiver = json.id_receiver;
if (json.createdAt != null) {
this.createdAt = new Date(json.createdAt);
}
if (json.updatedAt != null) {
this.updatedAt = new Date(json.updatedAt);
}
if (json.deletedAt != null) {
this.deletedAt = new Date(json.deletedAt);
}
}
}
}
This entity is used to get the object from json.
Here's my ChatRequestService:
/**
* Create the passed nmChatRequest.
*/
add(nmChatRequest : NmChatRequest, token: string) : Observable<NmChatRequest> {
let body = nmChatRequest;
return this.http.post(this.chatUrl, body, {headers: new HttpHeaders({ 'Content-Type': 'application/json', 'X-Auth-Token': token })})
.pipe(
map(response => new NmChatRequest(response)),
catchError(this.handleError)
);
}
What am I missing ?
Thanks to anyone who will take the time to read/answer this question.
I built a stackblitz from the above provided pieces. It seemed to work fine for me if I changed the json string to an object instead of an array.
So no outside brackets:
{"id":14,
"sender":
{"id":20,"email":"p.martelliere#gmail.com","username":"test5","roles":
["ROLE_USER"],"status":"active","note":"0","points":0,
"devices":[],"job":"Caisse","showJob":false,"notificationsActivated":true,
"connected":true,"tokenConfirm":"","birthDate":[]
},"receiver":
{"id":12,"email":"test2#yopmail.com","username":"test2","tokenConfirm":"",
"job":"g\u00e9rant","showJob":false,"note":"0","points":0,
"roles":["ROLE_USER"],"status":"active","notificationsActivated":true,
"connected":true,"devices":[]
},
"myNeed":"Te ster",
"whatICanGive":"1",
"messages":[],
"status":"active"
}
If you are indeed getting an array and not a single object, you may need to modify your code to pass in the first element of the array. Something like this:
map(response => new NmChatRequest(response[0]))
Here is the stackblitz: https://stackblitz.com/edit/angular-wgunjb?file=src%2Fapp%2Fapp.component.ts
I have a problem consuming data from an ASP.NET Core 2.0 Web API with Angular 5+.
Here the steps i have done:
I have built an ASP.NET Core 2.0 WebAPI and deployed it on a server. I can consume data from postman or swagger without any problems.
Then i have created with NSwagStudio the client TypeScript service classes for my angular frontend app.
Now the problem:
I can make a request to the wep api from the frontend app and i am also recieveing the correct data in JSON-Format.
But while the mapping process to the poco object in the generated client service class, something doesnt work. I always get an object with empty attributes.
Here my code:
product.service.ts
export class ProductService {
private http: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> };
private baseUrl: string;
protected jsonParseReviver: (key: string, value: any) => any = undefined;
constructor() {
this.http = <any>window;
this.baseUrl = "http://testweb01/FurnitureContractWebAPI";
}
getByProductId(productId: string): Promise<Product[]> {
let url_ = this.baseUrl + "/api/Product/GetById?";
if (productId === undefined)
throw new Error("The parameter 'productId' must be defined.");
else
url_ += "productId=" + encodeURIComponent("" + productId) + "&";
url_ = url_.replace(/[?&]$/, "");
let options_ = <RequestInit>{
method: "GET",
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
}
};
return this.http.fetch(url_, options_).then((_response: Response) => {
return this.processGetByProductId(_response);
});
}
protected processGetByProductId(response: Response): Promise<Product[]> {
const status = response.status;
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200) {
return response.text().then((_responseText) => {
let result200: any = null;
let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
if (resultData200 && resultData200.constructor === Array) {
result200 = [];
for (let item of resultData200) {
var x = Product.fromJS(item);
//console.log(x);
result200.push(Product.fromJS(item));
}
}
//console.log(result200);
return result200;
});
} else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve<Product[]>(<any>null);
}
And here the methods from the Product-class:
init(data?: any) {
console.log(data);
if (data) {
this.productId = data["ProductId"];
this.productNameDe = data["ProductNameDe"];
this.productNameFr = data["ProductNameFr"];
this.productNameIt = data["ProductNameIt"];
this.supplierProductId = data["SupplierProductId"];
this.supplierProductVarId = data["SupplierProductVarId"];
this.supplierProductVarName = data["SupplierProductVarName"];
this.supplierId = data["SupplierId"];
this.supplierName = data["SupplierName"];
this.additionalText = data["AdditionalText"];
this.installationCost = data["InstallationCost"];
this.deliveryCost = data["DeliveryCost"];
this.sectionId = data["SectionId"];
this.categorieId = data["CategorieId"];
this.price = data["Price"];
this.ean = data["Ean"];
this.brand = data["Brand"];
this.modifiedDate = data["ModifiedDate"] ? new Date(data["ModifiedDate"].toString()) : <any>undefined;
this.categorie = data["Categorie"] ? ProductCategory.fromJS(data["Categorie"]) : <any>undefined;
this.section = data["Section"] ? ProductSection.fromJS(data["Section"]) : <any>undefined;
}
}
static fromJS(data: any): Product {
data = typeof data === 'object' ? data : {};
let result = new Product();
result.init(data);
return result;
}
In the init() method when i look at data, it contains all the values i need. But when i for example use data["ProductId"] the value is null/undefined.
Can anyone please help?
Thanks
Here is a screenshot of my console output of the data object:
enter image description here
Now I could figure out, that i can cast the data object directly to Product:
init(data?: any) {
var p = <Product>data;
This works, but i am asking myself, why does the generated class have an init-method with manually setting of the attributes, when it is possible to cast the object directly?
NSwag is misconfigured, use DefaultPropertyNameHandling: CamelCase for ASP.NET Core
Or use the new asp.net core api explorer based swagger generator which automatically detects the contract resolver. (Experimental)