I'm trying to pass an array of objects through activeroute. When I pass it to the next page I get [object Object]. I saw a question on Stackoverflow where they use JSON.stringify but that didn't work for me. Or is it better to use application providers instead of queryparams.
TS of page sending the data
criteriaList: ShipmentLookupCriteria[] = [];
navigateTo() {
const navigationExtras: NavigationExtras = {
queryParams: {
criteriaList: this.criteriaList
}
};
this.router.navigate(['/lookup/results'], navigationExtras);
}
TS of page receiving the data
this.sub = this.route.queryParams.subscribe(params => {
console.log(params.criteriaList);
});
ShipmentLookUpCriteria model
import { EquipReferenceTuple } from './equip-reference-tuple.model';
export class ShipmentLookupCriteria {
terminal: string;
equipReferenceList: EquipReferenceTuple[];
constructor(terminal: string, equipReferenceList: EquipReferenceTuple[]) {
this.terminal = terminal;
this.equipReferenceList = equipReferenceList;
}
}
UPDATE
I decided to start with something simple. So I create an array of objects with dummy data.
navigateTo() {
const navigationExtras: NavigationExtras = {
queryParams: {
criteriaList: [{ name: 1, age: 1 }, { name: 2, age: 2 }]
}
};
this.router.navigate(['lookup/results'], navigationExtras);
}
PAGE RECEIVING THE PARAMS
this.route.queryParams.subscribe(params => {
console.log(params.criteriaList[0]);
});
RETURNS = [object Object] If I do again JSON.stringify it shows it as string "[object Object]". if I do params.criteriaList[0].name returns undefined
You can simply pass,
this.router.navigate(['/lookup/results'], {queryParams: {criteriaList: this.criteriaList }});
and access it using
this.sub = this.route.snapshot.queryParamMap.get('criteriaList');
Related
I have a simple Angular HttpClient, which is correctly returning JSON. I am attempting to cast the results to enforce type safety (not sure if this is correct).
But how do I actually access the returned JSON to copy it into an array?
The httpClient get() request is (and seems to be working fine):
public sendGetRequest(): Observable<Symbols[]> {
return this.httpClient.get<Symbols[]>(this.REST_API_SERVER);
}
The Symbols interface is
export interface Symbols {
code: string
desc: string
}
I have a component which calls the data service and is getting a response. However the code below returns an error when attempting to map the JSON into a string array
ERROR TypeError: syms.map is not a function
listOfOption: Array<{ value: string; label: string }> = []
this.dataService.sendGetRequest().subscribe((syms: Symbols[]) => {
console.log('return value ' + JSON.stringify(syms))
// console output shows the returned JSON and it looks correct
//this does not work, how do I copy the results to a string array??
this.listOfOption = syms.map(results => {
return {
value: results.code,
label: results.code,
}
})
})
The JSON data structure is:
{
"results": [
{
"code": "code1",
"desc": "Long description of code 1"
},
{
"code": "code2",
"desc": "Long description of code 2"
},
{
"code": "code3",
"desc": "Long description of code 3"
},
{
"code": "code4",
"desc": "Long description of code 4"
}
]
}
This is driving me crazy
Model a new interface called responseData to support response type.
export interface responseData{
results: Symbols[]
}
export interface Symbols {
code: string
desc: string
}
Update the same in service
public sendGetRequest(): Observable<responseData> {
return this.httpClient.get<responseData>(this.REST_API_SERVER);
}
You can now retrieve the results using array.map()
listOfOption: Array<{ value: string; label: string }> = []
this.dataService.sendGetRequest().subscribe((syms: responseData) => {
console.log('return value ' + syms)
this.listOfOption = syms.results.map(result => {
return {
value: result.code,
label: result.code,
}
})
})
The response data has an object root, but you're trying to parse it as an array root. I think the simplest solution would be something like this:
public sendGetRequest(): Observable<Symbols[]> {
return this.httpClient.get<{results: Symbols[]}>(this.REST_API_SERVER)
.pipe(pluck('results'));
}
Which specifies that the response data is an object with a field named results which holds an array of Symbols.
Alternatively you could also extract the response type to a separate definition:
interface ApiResponse {
results: Symbols[]
}
public sendGetRequest(): Observable<Symbols[]> {
return this.httpClient.get<ApiResponse>(this.REST_API_SERVER)
.pipe(pluck('results'));
}
So i have following JSON:
.json
"type": [ {
"id": 2,
"secondid": "1",
"name": "f",
"positionX": 0,
"positionY": 0
}]
and following Service:
public updateposition(Model: typemodel): Observable<any> {
return this.http.post(this.apiEndPoint + '/type' + '/' + typemodel.id , typemodel);
}
and following TS:
.ts
x: number;
y: number;
updateposition()
{
}
So the goal is to update the json object "type" by clicking a button with html. The html part is no problem. But i don't know how to update the json object with the two new positions x and y which are declared in ts. I want to have the process in the function updateposition(). Do you have any suggestions :) ?
You would have to use Dependency Injection to obtain a reference to the Service in your component and use it to retrieve and store the JSON object. Then update it like you would any other object in JS when the button is clicked, and make the API call. Be sure to subscribe to the result or the API call will not go through.
// ...
export class MyComponent {
public jsonObject: TypeModel = { ... };
public constructor(private service: Service) { }
// ...
public function updateposition() {
this.jsonObject[0].positionX = 52;
this.jsonObject[0].positionY = 42;
this.jsonObject = this.service.updateposition(this.jsonObject).subscribe(
result => {
console.log("The API call returned", result);
}
);
}
}
My json data:
{
"Temp": [
{
"dt": 1485717216,
"temp":30,
"time":"05:17:55 PM"
}
]
}
I can parse above json -
ngOnInit() {
this._weather.dailyForecast()
.subscribe(mdata => {
let temp1 = mdata['Temp'].map(mdata => mdata.temp)
let time = mdata['Temp'].map(mdata => mdata.time)
}
}
But I'm facing problem while parsing below json data-
{
"temp":30,
"time":"05:17:55 PM"
}
Can any one tell me how to parse json data?
Update code:
Service code
export class WeatherService {
constructor(private _http: HttpClient) { }
dailyForecast() {
return this._http.get("----url----")
.map(result => result);
}
}
I think OP's facing an issue while getting response as object rather than an Array.
You need to handle that in case with custom code and add for a check as necessary,
also you need to make mdata to type of any since it varies.
Inside your subscribe,
.subscribe((mdata :any) => {
if(mdata['Temp']){
let temp1 = mdata['Temp'].map(mdata => mdata.temp)
let time = mdata['Temp'].map(mdata => mdata.time)
}
else
{
let temp1 = mdata.temp;
let time = mdata.time;
}
}
I'm trying to read some test data from a local json file and output the data with correct formatting into a textarea. Right now though it just outputs [object Object]. How would I go about getting it so it outputs:
Id: theIdGoesHere
Title: theTitleGoesHere
step.service.ts The service used to call the json data
public getJson(): Observable<any>{
return this.http.get('/assets/jsonData/MyJson.json')
.map(response => response.json());
}
MyJson.json
{
"data":[
{
"id": 1,
"title":"Test1"
},
{
"id": 2,
"title":"Test2"
}
]
}
main.componenet.ts
private testVar: any;
test(){
this.stepService.getJson().subscribe(data => (this.testVar = data));
}
anothermethod(){
this.test();
this.mainStepText = this.testVar; //mainStepText binded to textarea with [(ngModel)]="mainStepText"
}
get mainStepText2() { //Rebinded this one
const text = [];
const { data } = this.testVar;
for (let item of this.testVar.data) {
Object.keys(item).forEach(key => {
text.push(key + ': ' + item[key]);
});
}
return text.join('\r\n'); // \r\n is the line break
}
You can use json pipe to format your object into a json string:
[(ngModel)]="mainStepText | json"
If you want to show a specific property of your object, you can access it in your template:
[(ngModel)]="mainStepText.data[0].title"
This will display "Test1" in your field.
You could loop through your json.data and through their keys to extract the text and values and generate the string you need for the text area.
const text = [];
for (let item of this.textVar.data) {
Object.keys(item).forEach(key => {
text.push(key + ': ' + item[key]);
});
}
return text.join('\r\n'); // \r\n is the line break
Here's the running code, I put it in app.ts: http://plnkr.co/edit/3AbQYQOW0MVBqO91X9qi?p=preview
Hope this is of help.
Given a JSON output of an api:
{
"id": 13,
"name": "horst",
"cars": [{
"brand": "VW",
"maxSpeed": 120,
"isWastingGazoline": true
}]
}
I would like to define interfaces for typescript:
export interface Car {
brand: string;
maxSpeed: number;
isWastingGazoline: boolean;
}
export interface RaceCarDriver {
id: number;
name: string;
cars: Car[];
}
Yet I don't want them to type them manually, I rather have a script generate them for me.
How can I convert json into typescript interfaces? I also don't want to use webservices like MakeTypes or json2ts.
You can write the script using typescript compiler API and its ability to infer types. I was really surprised how easy it was.
You have to wrap your sample data to make it compile-able as typescript code. The script will pick all variable declarations and try to print inferred types for them. It uses variable names and property names for assigning names to types, and if two objects have a property with the same name, it will pick the type from the first one. So it will not work in case these types are actually different (the fix is left as an exercise). For your JSON output, the data sample will look like
file sample.ts
let raceCarDriver = {
"id": 13,
"name": "horst",
"cars": [{
"brand": "VW",
"maxSpeed": 120,
"isWastingGazoline": true,
}]
};
The script was tested with Typescript 2.1 (just released):
npm i typescript
npm i #types/node
./node_modules/.bin/tsc --lib es6 print-inferred-types.ts
node print-inferred-types.js sample.ts
output:
export interface RaceCarDriver {
id: number;
name: string;
cars: Car[];
}
export interface Car {
brand: string;
maxSpeed: number;
isWastingGazoline: boolean;
}
Here is the script: print-inferred-types.ts:
import * as ts from "typescript";
let fileName = process.argv[2];
function printInferredTypes(fileNames: string[], options: ts.CompilerOptions): void {
let program = ts.createProgram(fileNames, options);
let checker = program.getTypeChecker();
let knownTypes: {[name: string]: boolean} = {};
let pendingTypes: {name: string, symbol: ts.Symbol}[] = [];
for (const sourceFile of program.getSourceFiles()) {
if (sourceFile.fileName == fileName) {
ts.forEachChild(sourceFile, visit);
}
}
while (pendingTypes.length > 0) {
let pendingType = pendingTypes.shift();
printJsonType(pendingType.name, pendingType.symbol);
}
function visit(node: ts.Node) {
if (node.kind == ts.SyntaxKind.VariableStatement) {
(<ts.VariableStatement>node).declarationList.declarations.forEach(declaration => {
if (declaration.name.kind == ts.SyntaxKind.Identifier) {
let identifier = <ts.Identifier>declaration.name;
let symbol = checker.getSymbolAtLocation(identifier);
if (symbol) {
let t = checker.getTypeOfSymbolAtLocation(symbol, identifier);
if (t && t.symbol) {
pendingTypes.push({name: identifier.text, symbol: t.symbol});
}
}
}
});
}
}
function printJsonType(name: string, symbol: ts.Symbol) {
if (symbol.members) {
console.log(`export interface ${capitalize(name)} {`);
Object.keys(symbol.members).forEach(k => {
let member = symbol.members[k];
let typeName = null;
if (member.declarations[0]) {
let memberType = checker.getTypeOfSymbolAtLocation(member, member.declarations[0]);
if (memberType) {
typeName = getMemberTypeName(k, memberType);
}
}
if (!typeName) {
console.log(`// Sorry, could not get type name for ${k}!`);
} else {
console.log(` ${k}: ${typeName};`);
}
});
console.log(`}`);
}
}
function getMemberTypeName(memberName: string, memberType: ts.Type): string | null {
if (memberType.flags == ts.TypeFlags.String) {
return 'string';
} else if (memberType.flags == ts.TypeFlags.Number) {
return 'number';
} else if (0 !== (memberType.flags & ts.TypeFlags.Boolean)) {
return 'boolean';
} else if (memberType.symbol) {
if (memberType.symbol.name == 'Array' && (<ts.TypeReference>memberType).typeArguments) {
let elementType = (<ts.TypeReference>memberType).typeArguments[0];
if (elementType && elementType.symbol) {
let elementTypeName = capitalize(stripS(memberName));
if (!knownTypes[elementTypeName]) {
knownTypes[elementTypeName] = true;
pendingTypes.push({name: elementTypeName, symbol: elementType.symbol});
}
return `${elementTypeName}[]`;
}
} else if (memberType.symbol.name == '__object') {
let typeName = capitalize(memberName);
if (!knownTypes[typeName]) {
knownTypes[typeName] = true;
pendingTypes.push({name: typeName, symbol: memberType.symbol});
}
return typeName;
} else {
return null;
}
} else {
return null;
}
}
function capitalize(n: string) {
return n.charAt(0).toUpperCase() + n.slice(1);
}
function stripS(n: string) {
return n.endsWith('s') ? n.substring(0, n.length - 1) : n;
}
}
printInferredTypes([fileName], {
noEmitOnError: true, noImplicitAny: true,
target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS
});
Found a npm package that converts a arbitrary JSON file without a schema into a TS interface:
https://www.npmjs.com/package/json-to-ts
The author also provided a VSCode plugin.
You can use an npm module instead of the web hosted solution:
https://www.npmjs.com/package/json-schema-to-typescript
If your JSON comes from an HTTP API and the API has an swagger code definition, you can generate a TypeScript client:
https://github.com/swagger-api/swagger-codegen#api-clients
If you json comes from a Java ot .Net backened, you can generate TypeScript from Java or C# classes:
http://type.litesolutions.net
https://github.com/raphaeljolivet/java2typescript
Using only sed and tsc
sed '1s#^#const foo = #' sample.json > sample.$$.ts
tsc sample.$$.ts --emitDeclarationOnly --declaration
Append const foo = to beginning of file
Using sed to replace (s) nothing (#^#) at the beginning of the first line (1) with const foo =
output to sample.$$.ts
the extension is the required to be .ts
$$ expands to the shells process id, handy for a temp file that is unlikely to overwrite stuff you care about
ask tsc to only emit a .d.ts typings file
this file has pretty much everything you want for the interface. You might need to replace a few strings and customize it in a way you want but most of the leg work is done