How to traverse a typed array? - javascript

I have the following class model in my application Angular:
export class IItemsModel {
public description: string;
public itemDetail: IItemDetailModel;
public itemCategories: IItemCategoriesModel[]; // array of IItemCategoriesModel
}
export class IItemCategoriesModel {
public id: string | number;
public description: string;
}
And my Controller:
itemModel: IItemsModel;
selectedCategories: any[] = [];
ngOnInit() {
this.itemModel = new IItemsModel();
this.itemModel.itemCategories = [];
}
onSubmit(form: NgForm) {
// here I format the data
}
In the template I have a multiple select where I fill an array with the id's of the chosen categories.
[25, 38] // selectedCategories
Problem, I'm using ngModel to link the form with the controler, but to send the pre-filled data to the API, I have to format the id's to the model format, that is:
{
...,
itemDetail: 'something',
itemCategories: [
{ id: any Id },
{ id: other Id }
]
}
I try to format the data as follows in the onSubmit() method:
for(let i=0; i<this.selectedCategories.length; i++) {
this.itemModel.itemCategories[i].id = this.selectedCategories[i];
}
But I get the error:
TypeError: Cannot set property 'id' of undefined # undefined:undefined
How could you be formatting the itemCategories to be able to send the data correctly to the API?

Use forEach to iterate instead of for loop.
this.selectedCategories.forEach(f => {
this.itemModel.itemCategories.push({ id: f, description: '' })
});
Since your selectedCategories object is an array of numbers, it doesn't have id property in it. That's why you're getting errors.
Working demo at StackBlitz.
Click the button and check the console log.

Related

Angular interfaces -- inserting object to a nested array ( Cannot read properties of undefined)

I want to push object to subCategory which is an array under ITemplate interface but I am receiving error TypeError: Cannot read properties of undefined (reading 'subCategory') .
How do i push an object to subCategory array?
Any idea guys how to make this possible and what causes the error ?
Thanks, appreciated.
#ts code
import { Component, OnInit } from '#angular/core'
interface ITemplate {
id: number;
entitlement: string;
required: boolean;
isHeaderCategory: boolean;
subCategory: ITemplate2[]
}
interface ITemplate2 {
id: number;
sub_name: string;
}
const mockData: ITemplate[] = []
#Component({
selector: 'app-template',
templateUrl: './template.component.html',
styleUrls: ['./template.component.css'],
})
export class TemplateComponent implements OnInit {
constructor() {}
ngOnInit(): void {
console.log('thiss' , this.templates)
}
add() {
this.templates[0].subCategory.push({
id: 0,
sub_name: 'test'
})
}
templates: ITemplate[] = mockData
}
You're trying to access this.templates 0th element and inside that element you are trying to push into subCategory, but first you should have 0th element in first place for this.templates.
try this.
add() {
this.templates.push({
id:1,
entitlement: 'string related to entitlement',
required: true;
isHeaderCategory: false;
subCategory: []
});
this.templates[0].subCategory.push({
id: 0,
sub_name: 'test'
}) ;
}
The issue is that you are trying to push an item to an array position/index that doesn't exist, hence the error.
the variable templates which is an array is of length 0.
In order to be able to do what you want to do, the variable templates must have values.

How to serialize enum in borsh-js

Trying to serialize an object in Rust and deserialize it in JS
We got 000100000031 hash, after serialization this:
pub enum Service {
Stackoverflow,
Twitter,
Telegram,
}
pub struct ServiceId {
pub service: Service,
pub id: ExternalId,
}
When trying to deserialize in JS use this:
const Service = {
Stackoverflow: 0,
Twitter: 1,
Telegram: 2
}
class ServiceId {
constructor(service, id) {
this.service = service
this.id = id
}
}
const value = new ServiceId(Service.Stackoverflow, userId)
const schema = new Map([
[ServiceId,
{ kind: 'struct', fields: [['service', 'u8'], ['id', 'string']] }]
]);
After deserialization, we got this, but it is incorrect because we have an object inside an object and a redundant id parameter:
ServiceId { service: { service: undefined, id: '1' }, id: undefined }
Firstly it could be because in Rust we have enum type, so how we can use enum in borsh-js.
Second if not, why do we have an incorrect results?
It is hard to understand from documentation, but you need to create your class like this and all will be okay.
class ServiceId {
constructor({ service, id }) {
this.service = service
this.id = id
}
}
new ServiceId({ service: 'lol', id: 'kek' })
So you need to pass your params as object.

Issues patching FormArrays values with data from server in Angular

I have an Angular form where a user fills in the form and selects multiple books via checkboxes and send the data to the server. The user can later edit the form again. When a user wants to edit the form, the form must be shown to the user pre-filled with the previous data the user has already submitted.
The problem I am having now is how to pre-filled the checkboxes with the values the user has already submitted. There are five checkboxes and the user can select two. When he wants to edit the data later, i want to pre-select the checkboxes he has selected before.
Current problem
When I run my code, the checkboxes appears and vanishes instantly within a second. Because of that am not able to see whether they are checked or not.
The following is a stripdown of my code so that you can understand the problem.
// Model Interface
export interface BooksModel {
books?: Array<any>;
}
export class AdviesHandicapComponent implements OnInit {
private sub: any;
service: DataService;
books = new FormArray([]);
booksModel: BooksModel;
booksForm: FormGroup;
booksOptions = [
{id: 1, book: 'Biology'},
{id: 2, book: 'Physics'},
{id: 3, book: 'Chemistry'},
{id: 4, book: 'Maths'},
{id: 6, book: 'None of the above'}
];
constructor(private fb: FormBuilder){}
ngOnInit(): void {
this.service = new DataService();
this.sub = this.route.queryParams.subscribe(params => {
const tok = params['tok'];
if (tok) {
const results = this.service.getBooks();
booksModel = results.reg;
patchBooksForm();
}
});
const booksFormControls = this.booksOptions.map(book => new FormControl(false));
this.books = new FormArray(booksFormControls);
this.booksForm = this.fb.group({
books: this.books,
});
}
patchBooks(ind: string[]) {
for (let i = 0; i < this.books.controls.length; i++) {
for (const d of ind) {
if (this.booksOptions[i].book === d) {
this.books.controls[i].patchValue(true);
}
}
}
}
patchBooksForm(): void {
patchBooks(this.booksModel.books); // I call this method here to patch the formarray values
this.booksForm.patchValue({
books: this.books.controls
});
}
}
Data from server
The user may have selected the following books. So when he comes back later I want these books to be selected before he starts editing the form.**
export class DataService {
getBooks() {
return {"reg":{"books":["Biology","Maths"]}};
}
}
Based on your code, your untouched form looks like:
{
"books": [
false,
false,
false,
false,
false
]
}
To achieve the same when patching, you are now having issues, that you are patching it twice, first time with correct values in your for loop in patchBooks(), second time patching it with the books controls in patchBooksForm(). You should remove those lines:
// remove
// this.booksForm.patchValue({
// books: this.books.controls
// });
STACKBLITZ
Just a remark, does it make sense to not having any identifier in the formarray, now there's just a bunch of falses and trues, but that is of course up to you :) Also another remark, not related, you should inject your service in the constructor, and not call: this.service = new DataService();.

How to initialize a typed Object in TypeScript/Angular?

I'm new to Angular & TypeScript and trying to figure out how to instantiate an object (before an api request is returned with the real data).
For example, my model looks like this:
//order.model.ts
export class Order {
constructor(public id: number, currency: string, public contact: Object, public items: Array<Object>) {}
}
And then I try to instantiate that in one of my components, let's say the App component:
//app.component.ts
export class AppComponent {
#Input()
public order: Order = new Order();
}
Of course, it expected to receive 4 arguments when instantiating new Order() but received 0. Do I actually have to pass in undefined/empty values for each attribute of Order?
In good ol' React (without TS) I would just initialize with an empty object and call it a day:
this.state = {
order: {}
}
What's best practice for this sort of thing in Angular/TS?
Yes as it is currently set up you would have to pass 4 default arguments to the constructor.
public order: Order = new Order(1, '', {}, []);
Or you can set each property as nullable by adding a ? like so:
export class Order {
constructor(public id?: number, currency?: string, public contact?: Object, public items?: Array<Object>) {}
}
If the class doesn't have functionality (you are simply using it for type checking) the best way to do it would be to declare an interface like so (you can also make them nullable here with ?s):
export interface Order {
id: number;
currency: string;
contact: Object;
items: Object[];
}
then in your component do not initialize the value until you have all of the needed values:
//app.component.ts
export class AppComponent {
#Input()
public order: Order;
// just an example
setValues(id: number, currency: string, contact: Object, items: Object[]) {
this.order = {
id: id,
currency: currency,
contact: contact,
items: items
}
}
// example for if you receive object with correct fields from backend
getData() {
this.service.getData().subscribe(result => {
this.order = result;
});
}
}

Parsing Map with null value in Typescript from JSON

I am using the following class in Typescript to parse Employee data received as JSON using TypedJson.parse()
#JsonObject()
export class Employee {
#JsonMember()
public name: string;
#JsonMember()
public columns: { [name: string]: any };
}
columns is a Map<String, Object> sent from Spring backend.
While parsing TypedJson ignores all the keys with value as null and thus no key values pair objects of the form myKey: null are created. I do not have options of replacing all null with ''
How to get those null values parsed to objects with null values?
So, I've seen the code of TypedJson - in current version 0.1.7 it is bug, but in the repository this bug is fixed, but not published yet.
So you can use workaround until next release just adding = null! as property default value:
#JsonObject()
export class Employee {
#JsonMember()
public name: string = null!;
#JsonMember()
public columns: { [name: string]: any } = null!;
}
As #JonnyAsmar suggested JSON.parse works for this scenario.
I was previously doing
this._http.get(`${HTTP_URL}/${params.EmployeeId}/EmployeeData`, { params: params })
.map(response => TypedJSON.parse(response.text(), Employee)
})
.catch(this.handleError);
as a workaround I am now doing:
this._http.get(`${HTTP_URL}/${params.EmployeeId}/EmployeeData`, { params: params })
.map(response => {
let obj:JSON = JSON.parse(response.text());
return obj;
})
.catch(this.handleError);

Categories