angular 2 how to add a model within model - class

I am getting a response json from API like below.
student: {
name : abc,
address : {
city : ca,
state:abc
},
age : 10
}
In order to bind this to a model, i need a model similar to this
class student {
name:string;
age:number;
address:{
city:string;
state:string
}
}
But when I bind the data to the above model. Address data is not binding to model.
Please suggest the right way to write a model to bind the above data.

export class A {
name:string;
age:number;
address:Adress;
}
export class Adress
city:string;
state:string
}

You need to instantiate an instance of the Student class, i.e.
class Student {
// Define Student properties here
name:string;
age:number;
// ...
constructor(options) {
// Set Student properties here
this.name = options.name;
this.age = options.age;
this.address = options.address;
// ...
}
}
// Then:
const student = new Student(jsonData);

Related

Is it possible to create dynamic getters/setters in typescript?

I'm new in typescript, and I'm trying to rewrite our application from es2016 to TypeScript.
My task is to have a class with data property and make each element from data object available as class property.
I get stuck on this JavaScript code:
for(let key in this.data) {
Object.defineProperty(this, key, {
get: function(value:any) { return this.data[key]; },
set: function(value:any) {
if (this.data[key] !== value) {
this.data[key] = value;
this.updatedKeys.push(key);
}
},
});
}
It is pretty easy to use getter/setters for typescript, but i get confused if i can create them dynamically?
interface IData {
id: number;
[propName: string]: any;
}
class Model {
protected updatedKeys:string[] = [];
baseUrl:string = null;
data:IData;
fields:IData;
constructor(data:IData={id:null}, fields:IData={id:null}) {
super();
this.data = data;
this.fields = fields;
for(let key in this.data) {
Object.defineProperty(this, key, {
get: function(value:any) { return this.data[key]; },
set: function(value:any) {
if (this.data[key] !== value) {
this.data[key] = value;
this.updatedKeys.push(key);
}
},
});
}
}
}
tsc -t ES2016 --lib "es2016","dom" models.ts
will give this error:
models.ts(33,40): error TS2345: Argument of type '{ get: (value: any) => any; set: (value: any) => void; }' is not assignable to parameter of type 'PropertyDescriptor & ThisType<any>'.
Type '{ get: (value: any) => any; set: (value: any) => void; }' is not assignable to type 'PropertyDescriptor'.
Types of property 'get' are incompatible.
Type '(value: any) => any' is not assignable to type '() => any'.
And I don't know how to get rid of this problem.
thanks to the https://github.com/epicgirl1998, she helped me to find the solution. I'll post it here:
the error is that the getter has a value parameter even though getters
aren't passed any value
i replaced it with get: function() { return this.data[key]; }, and now
the only error is that there's a super call in the class which is only
needed if the class extends another class
also, this inside the accessors doesn't refer to the class instance,
but using arrow functions for them should fix it
try this:
interface IData {
id: number;
[propName: string]: any;
}
class Model {
protected updatedKeys:string[] = [];
baseUrl:string = null;
data:IData;
fields:IData;
constructor(data:IData={id:null}, fields:IData={id:null}) {
this.data = data;
this.fields = fields;
for(let key in this.data) {
Object.defineProperty(this, key, {
get: () => { return this.data[key]; },
set: (value:any) => {
if (this.data[key] !== value) {
this.data[key] = value;
this.updatedKeys.push(key);
}
},
});
}
}
}
In typescript, you generally don't need to create objects with methods and properties dynamically. You either create instances of classes, or you type your data using an interface.
If all you want is to convert loaded (json) data to typed data, you can use an interface that describes the structure of your json data.
interface describes the properties of actor data
interface Actor {
name: string;
height: number;
}
fetch generic json data from somewhere
let data : any = getSingleActorData();
type the actor to an interface and put it in an actor array
let actorData : Actor[] = [];
actorData.push(data as Actor);
Now your IDE will allow you to access the name and height of the actor variable:
console.log(actorData[0].name);
If you do want a complete 'object' with getters and setters you can create an Actor class and then instantiate it with the data you loaded:
class Actor {
private _name:string;
private _height:string;
get name {}
set name {}
get height {}
set height {}
constructor(name:string, height:number){
}
}
And then you can put your json data in an actor instance:
actorData.push(new Actor(jsondata.name, jsondata.height));

Can I add non-persistent fields to a model?

Is there a recommended practice for adding non-persistent attributes to an Objection model object such that it that won't overwrite predefined attributes?
Objection models have the virtualAttributes field. From the documentation:
The virtual values are not written to database. Only the “external” JSON format will contain them.
It is important to note these are functions, not just model properties.
Example from the docs:
class Person extends Model {
static get virtualAttributes() {
return ['fullName', 'isFemale'];
}
fullName() {
return `${this.firstName} ${this.lastName}`;
}
get isFemale() {
return this.gender === 'female';
}
}
const person = Person.fromJson({
firstName: 'Jennifer',
lastName: 'Aniston',
gender: 'female'
});
console.log(person.toJSON());
// --> {"firstName": "Jennifer", "lastName": "Aniston", "isFemale": true, "fullName": "Jennifer Aniston"}

How to instantiate model Angular 2

I'm creating a very basic Angular 2 Application with the purpose of CRUD products. I have a CreateProductComponent but I'm having trouble instantiating the model that I wan't to use on my view. I'm getting this error:
This is my code:
create-product.component.ts
import { Component, OnInit } from '#angular/core';
import { ROUTER_DIRECTIVES } from '#angular/router';
import { Product } from '../product'
import { ProductService } from '../product.service'
#Component({
moduleId: module.id,
selector: 'app-create-product',
templateUrl: 'create-product.html',
styleUrls: ['create-product.css'],
})
export class CreateProductComponent {
model: new Product(1,'2',1); <- error on this line
constructor(private productService: ProductService) { }
addProduct() {
//this.productService.addProduct(this.product);
}
}
product.ts
export class Product {
constructor(
public ID: number,
public Name: string,
public Price: number
) { }
}
Ideally, I would like to create an empty product, or a product with defaul values so that when a form in the view is filled with the product data this data is passed down to the product. Does anyone know how to solve this?
In typescript terminology ':' means you are declaring a type for a variable you have defined.
'=' means you are assigning a value to your variable.
But here what you did is instead of assigning a value you are trying to declare a value (which is not correct according to syntax)
so either you can directly assign a value like
model = new Product(1,'2',1);
or else you can first declare a type for your variable and then assign a value in either of these two ways (I personally prefer this way)
model: Product = new Product(1,'2',1);
or
model: Product;
model = new Product(1,'2',1);
The issue is that you're syntax is a little off. You should be using any of the following:
This creates a property with an instantiated value of Product.
export class CreateProductComponent {
// Define model, declare type, and assign/instantiate.
model = new Product(1,'2',1);
constructor(private productService: ProductService) { }
}
Or this one, which defines the property model as a type of Product but doesn't assign it a value. Instead it's assigned in the constructor.
export class CreateProductComponent {
// Define model, declare type
model: Product;
constructor(private productService: ProductService) {
this.model = new Product(1,'2',1);
}
}
Alternatively you could even be more explicit, even though it is not required as the types can easily be inferred.
export class CreateProductComponent {
// Define model, declare type, and assign/instantiate.
model: Product = new Product(1,'2',1);
constructor(private productService: ProductService) { }
}
There is some great documentation here as well as a REPL playground which I highly suggest using.
It should be
model = new Product(1,'2',1);
You are creating an field in CreateProductComponent. Use '=' instead of ':' like
model = new Product(1,'2',1); <- error on this line

How to exclude property of a collection in JSON rendering in Grails 2.3

I am trying to setup a rest webservice (JSON) this is what I am getting:
{"name":"test","routines":[{"class":"Routine","id":1},{"class":"Routine","id":2}]}
This is what I want to get:
{"name":"test","routines":[{"name": "routine-1"},{"name": "routine-2"}]}
I have these domains:
class Program {
String name;
static hasMany = [routines: Routine]
}
class Routine {
String name
}
I have this controller:
class ProgramController extends RestfulController {
static responseFormats = ['json']
def show(Program program) {
respond program
}
}
I added this in the resources.groovy
programRenderer(JsonRenderer, Program) {
excludes = ['class', 'id']
}
routineRenderer(JsonRenderer, Routine) {
excludes = ['class', 'id']
}
How do I include the name property of Routine in the json response using the show method/action of ProgramController?
The ObjectMarshaller approach is the technically correct way. However, the code is cumbersome to write and it's a maintenance headache syncing the fields of the domain with the marshaller.
In the spirit of being Groovy and keeping things really simple, we've been quite happy just adding a little out() method to each REST domain.
Program.groovy
class Program {
String name
static hasMany = [routines: Routine]
def out() {
return [
name: name,
count: routines?.size(),
routines: routines?.collect { [name: it.name] }
]
}
}
ProgramController.groovy
import grails.converters.JSON
class ProgramController {
def show() {
def resource = Program.read(params.id)
render resource.out() as JSON
}
}
JSON Response
{
name: "test",
count: 2,
routines: [{ name: "routine-1" }, { name: "routine-2" }]
}
The out() method approach makes it easy to customize the response JSON, such as adding count for the number of routines.

Grais Rest: get a Json object from a "lastName" and not "id"

How get a user of this class, from a lastName, not from the id.
in my example i use a REST web service.
My class USER.groovy in Grails:
class User {
String firstName
String lastName
String zipcode }
class UrlMappings.groovy
class UrlMappings {
static mappings = {
/user/$id" (controller: "user") {
action = [GET: "show"]
}
}
}
def show in UserController.groovy
def show = {
User user = User.get(params.id)
if (user) {
render user as JSON
} else {
SendNotFoundResponse()
}
}
As I understand, your problem that you don't know how to query domain by other fields that id. For current example you can use:
User.findByFirstName(params.id)
And, please read about GORM querying - http://grails.org/doc/latest/guide/GORM.html#querying