is there a way to compose the key value of an object in typescript from strings? Here's an example:
object[index].key=value
should be,
object[index].["String".array[i]]=value
The following does not work:
{{ object[index].{{"string".concat(Variable[index])}} }} <-- the rendering is perfectly fine but the execution is missing
I'm trying to read an object in two "ngFor" loops, with the first loop acting as a counter for an array whose element acts as a key for the object in the second loop.
thx
EDIT:
tage=['Montag','Dienstag','Mittwoch']
objectArray: {
id:Number;
name:String;
Montag:String;
Dienstag:String;
Mittwoch:String;
}[]=[
{id:0,name:'Klaus',Montag:'arbeiten',Dienstag:'rumgammeln',Mittwoch:'Frei'},
{id:1,name:'Dieter',Montag:'frei',Dienstag:'arbeiten',Mittwoch:'rumgammeln'},
{id:2,name:'Peter',Montag:'rumgammeln',Dienstag:'frei',Mittwoch:'arbeiten'},
]
Template
1:{{objectArray[0].Montag}}<br>
2:{{objectArray[0]['Montag']}}<br>
<br>
<ng-container *ngFor="let tag of tage; let i=index">
{{i}}:{{objectArray[0][tage[i]]}}<br> <------- NOT WORKING
</ng-container>
Error Message
(property) AppComponent.tage: string[]
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ id: Number; name: String; Montag: String; Dienstag: String; Mittwoch: String; }'.
No index signature with a parameter of type 'string' was found on type '{ id: Number; name: String; Montag: String; Dienstag: String; Mittwoch: String; }'.ngtsc(7053)
app.component.ts(8, 53): Error occurs in the template of component AppComponent.
I think you are looking for the keyvalue pipe which will let you access object's key/value in template. https://angular.io/api/common/KeyValuePipe
testObject: { [key: number]: string } =
{
1: 'Object Value 1',
2: 'Object Value 2',
3: 'Object Value 3'
};
testMap = new Map([
[2, 'Map Value 2'],
[null, 'Map Value 3'],
[1, 'Map Value 1'],
]);
arrTest = ["Array Item 1",
"Array Item 2",
"Array Item 3"]
<p>Object & KeyValue Pipe</p>
<div *ngFor="let item of testObject | keyvalue">
Key: <b>{{item.key}}</b> and Value: <b>{{item.value}}</b>
</div>
<p>Maps & KeyValue Pipe</p>
<div *ngFor="let item of testMap | keyvalue">
Key: <b>{{item.key}}</b> and Value: <b>{{item.value}}</b>
</div>
<p>Arrays & KeyValue Pipe</p>
<div *ngFor="let item of arrTest | keyvalue:descOrder">
Key: <b>{{item.key}}</b> and Value: <b>{{item.value}}</b>
</div>
Example: https://stackblitz.com/edit/angular-key-value-pipe-demo-kphrro?file=src%2Fapp%2Fapp.component.html
Related
1. Array of Strings -> Union of Strings (It works)
I saw a solution creates a union of string literals from an array of strings.
const keys = ["cat", "dog"] as const;
type Keys = typeof keys[number]; // "name" | "age"
2. Array of Strings -> Union of Objects (Is it possible?)
My question is if it's possible to create a union of objects from an array of strings? The code below works, I just want to shorten the SET_PROPERTY_PAYLOAD with something like keyof IObject and generate a union of object types from there.
interface IObject = {
id: string;
name: string;
age: number;
}
// Is it possible to shorten this type using typescript's primitives
type SET_PROPERTY_PAYLOAD =
| {
id: string;
propertyName: "id"; // keyof IObject at index 0
value: string; // IObject["id"]
}
| {
id: string;
propertyName: "name"; // keyof IObject at index 1
value: string; // IObject["name"]
}
| {
id: string;
propertyName: "age"; // keyof IObject at index 2
value: number; // IObject["age"]
};
My goal for this is to narrow the type of value by inferring from the current value of propertyName.
You want a mapped type.
interface IObject {
id: string;
name: string;
age: number;
}
type SET_PROPERTY_PAYLOAD = {
[K in keyof IObject]: {
id: string,
propertyName: K,
value: IObject[K]
}
}[keyof IObject]
This type maps over the keys in IObject and create a new object type for each key.
SET_PROPERTY_PAYLOAD should then be exactly equivalent to your long form version above.
See Playground
'arr: { a: string[];b: string[];c: {id: number; name: string; }[]; } '
'''arr= {
a: ['rose', 'kelly', '35'],
b: ['marry', 'hadden', '40'],
c:[
{ id: 1, name: "Mark" },
{ id: 2, name: "John" },
{ id: 3, name: "Franc" },
{ id: 4, name: "Andrew " }
]
}
How to iterate above array using *ngFor loop in Angular'''
*ngFor directive expects the Array object to loop over. That's why you're receiving an error.
You can use keyvalue pair pipe to loop over this object, basically that will convert an object to an array, which would have key and value in separate object properties.
Since strictTemplate checking, typescript is throwing an error. To fix/suppress that error you can use define type of arr: {[key: string]: any}.
TS
arr: {[key: string]: any} = {
a: ...,
b: ...,
}
HTML
<div *ngFor="let item of arr | keyvalue">
<b>{{ item.key }}</b>
<div *ngFor="let val of item.value">
{{ val.name ?? val }}
</div>
</div>
Stackblitz
I want to set up a checkbox structure and I want to handle it dynamically. I have an object response returned from my service. However, when I use this function in context, I get a string return and I cannot use ngFor.
form.demo.component.ts
getElementChoicesByNKey(nkey:string):choiceModel[]{
var element = this.findInComponentsByNKey(nkey);
var res = element.Choices;
return res;
}
this function gives the correct return.
form.demo.component.html
...
<ng-container *ngIf="item.Type == 'Choice'">
<ng-container *ngTemplateOutlet="choiceTheme; context:{ Id: item.Id, Label: item.Label, Choices: getElementChoicesByNKey(item.Id) }"></ng-container>
</ng-container>
...
<ng-template #choiceTheme let-Id="Id" let-Label="Label" let-Choices="Choices">
<nz-form-item>
<nz-form-label nzFor="Id">{{Label}}</nz-form-label>
<nz-form-control [formControlName]="Id" nzErrorTip="{{ 'form.requiredText' | translate }}">
<p>{{Choices.length}}</p>
<div *ngFor="let item of Choices">
<p>test</p>
</div>
</nz-form-control>
</nz-form-item>
</ng-template>
...
here Choices appears as string and won't let me use ngFor. I am getting an error as below.
Cannot find a differ supporting object '[
{ label: 'Apple', value: 'Apple', checked: true },
{ label: 'Pear', value: 'Pear', checked: false },
{ label: 'Orange', value: 'Orange', checked: false } ]' of type 'string'. NgFor only supports binding to Iterables such as Arrays.
What is the point I missed? Thank you for your help.
Use
*ngFor="let item of getChoices(Choices)" in template
and in component.ts
getChoices(choiceStr) {
return JSON.parse(choiceStr);
}
Since you are getting Choices as a string, parse the string to an array inorder for ngFor to work
I would like to define my interface so that when you give a nav that is a navigationItem, you can optionally give childs for a dropdown. when the childs property is given I would like to enforce the icon property of the navigationItem.
When no childs property are given the icon property should not be given.
Any idea on how I could achieve that ?
this is my current interface
interface dropdown {
name: string;
href: string;
icon: IconDefinition;
}
interface navigationItem {
name: string;
href: string;
icon: IconDefinition; // only needed if the childs is given
childs?: dropdown[];
}
You should be able to do this using two different Interfaces like this.
Have one with
interface Type1 {
name: string;
href: string;
childs: never;
}
The second one will be
interface Type2 {
name: string;
href: string;
childs: dropdown[];
icon: IconDefinition;
}
Then you can use both the types using a conditional like this
value: Type1 | Type2
Why this works is, when you add icon: never to Type1, you can only have name and href keys.
So if someone adds the childs key, then the type becomes Type2 which needs to have icon given as well.
So, if const a: Type1 | Type2 = { name: '', href: '', childs: [] };, it throws
Type '{ name: string; href: string; childs: []; }' is not assignable to type 'Type1 | Type2'.
Property 'icon' is missing in type '{ name: string; href: string; childs: dropdown[]; }' but required in type 'Type2'.
If you want to use a single type instead, define a new type like this.
type Type3 = Type1 | Type2;
Then use it like this
const a: Type3;
Im using Angular 5 with typescript 2.7.1.
In typescript i have a custom type
arr: {id: string; name: string; }[];
and i want to push an element to the array, and have tried the following:
this.arr.push({id: "text", name: "text"})
ERROR TypeError: Cannot read property 'push' of undefined
let array2 : {id: "id", name: "name"}
this.arr.push(array2)
ERROR TypeError: Cannot read property 'push' of undefined
I don't understand why it wont work, I am defining id and name in push, I just want to add more elements to the array, am i missing something?
You need to initialize the array with an empty array before you use the field:
this.rows = [];
Or directly upon declaration
rows: {id: string; name: string; }[] = [];
I just ran into this myself and it wasn't initially clear to initialize the array. Once you do that, the array can accept objects of its type:
type arr = {id: string, name: string}
const array1: arr[] =[];
const array2: arr = {id: "id", name: "name"}
array1.push(array2);
console.log(array1) // prints [{"id": "id","name": "name"}]
Typescript Playground Example