I´m trying to loop over a content. I tried some answers found here in StackOverflow but none works for me.
I have this JSON
{
"-KmdNgomUUnfV8fkzne_":{
"name":"Abastecimento"
},
"-KmdNgzguGKbCEfyQ3F0":{
"name":"Consórcios"
},
"-KmdNh9_jtBlFqY1Y_Rj":{
"name":"Consultoria aeronáutica"
},
"-KmdNhKNCVEiJ2Ou8bUV":{
"name":"Cursos e treinamentos"
},
"-KmdNhVRoKfaCM--304M":{
"name":"Financiamento"
},
"-KmdNhfIC6fA0kDJcVBq":{
"name":"Hangaragem"
},
"-KmdNhu0X-PteQMyHp_n":{
"name":"Mecânica"
},
"-KmdNi6ZmmYXnoOTXoC5":{
"name":"Táxi Aéreo"
},
"-KmdNiHFhiX_crXB1L2R":{
"name":"Outros"
}
}
I´m trying to loop using this code
<button ion-item *ngFor="let cat of subcategories" (click)="onSubcategorySelect(cat)">
{{ cat.name }}
</button>
It's not working. What am I doing wrong?
Angular's ng-for requires any element with Iterable interface to work and it's not the case for a plain Object. You need to "convert" this object in an array, the easier way is with forEach or a for/in loop:
Anywhere in your code you'll iterate through your object and save it in a new variable to be used in ngFor:
public newSubcategories: any[] = []; // DECLARE A NEW EMPTY ARRAY IN THE TOP OF YOUR CLASS
this.subcategories.forEach(item => {
this.newSubcategories.push(a);
});
If you need to mantain the key use for/in to push a new object with the key.
public newSubcategories: any[] = []; // DECLARE A NEW EMPTY ARRAY IN THE TOP OF YOUR CLASS
for(let key in this.subcategories){
this.newSubcategories.push({
key: key,
name: this.subcategories[key].name
});
}
Finally your HTML
<button ion-item *ngFor="let cat of newSubcategories" (click)="onSubcategorySelect(cat)">
{{ cat.name }}
</button>
With this you'll be able to use ng-for in your new array.
Hope this helps.
Related
I'm trying to include external data/value into a v-for loop in VueJS. Have no idea how to go about it. Basically I have data/value in value as follows:
External Data
{{ time.one }}
{{ time.two }}
NOTE: I am receiving the data exactly as above as its coming from an API
JSON (own data)
{
"persons": [
{
"title": "Prof",
"name": "SomeProf"
},
{
"title": "Dr",
"name": "SomeDr"
},
]
}
And the loop is basic v-for loop
<ul v-for="person in persons">
<li> {{ person.title }}{{ person.name }} - <!-- Inc. external data {{ time.one }} -->
</ul>
The end result being:
Prof. SomeProf - 10:00pm
Dr. SomeDr - 09:00am
Thank You
I don't know if I understood your question properly, but you can also just modify the data right away.
Let's say you have your own data and make a call to the API when the component is created. What you can do is:
import persons from '#/data/persons'
export default {
data() {
return {
dataToLoop: []
}
},
async created() {
const timeData = await yourApiCall();
let results = [];
for (let i in persons) {
results.push({
...persons[i],
time: timeData[i] // or whatever key matches the person
})
}
this.dataToLoop = results;
}
}
And then all you need to do is loop through "dataToLoop" in your component.
i'm creating quiz app using angular and i have code like this
ngOnInit() {
this.myForm = this.fb.group({
lessonCode: "test",
answer: this.fb.array([])
});
}
onChange(email: string, code: string, isChecked: boolean) {
const emailFormArray = <FormArray>this.myForm.controls.answer;
if (isChecked) {
let array = new FormGroup({
questionCode: new FormControl(email),
emailCode: new FormArray([
new FormControl(code)
]),
});
emailFormArray.push(array);
} else {
let index = emailFormArray.controls.findIndex(x => x.value == email);
emailFormArray.removeAt(index);
}
}
which producing array like this
Form values: {
"lessonCode": "test",
"answer": [
{
"questionCode": "pertanyaan2",
"emailCode": [
"option2"
]
},
{
"questionCode": "pertanyaan2",
"emailCode": [
"option1"
]
}
]
}
but what i'm actually needed is like this
Form values: {
"lessonCode": "test",
"answer": [
{
"questionCode": "pertanyaan2",
"emailCode": {
"option2",
"option1"
}
}
]
}
how can i achieve that? any thoughts would be very helpful
i have minimal reproduce here https://stackblitz.com/edit/angular-ca1jin?file=src%2Fapp%2Fapp.component.ts
I suggested another aproach
If we create a formGroup like
this.myForm = this.fb.group({
lessonCode: "test",
answer: this.fb.array(this.users.map(x=>this.fb.group({
questionCode:x.code,
email:[[]]
})))
});
See that answer is a FormArray of FormGroup, each FormGroup has two FormsControl, questionCode and email, that is still a FormControl (but store an array). You need don't confussed with a FormArray. A FormControl can store an array, an object, an string, a number, etc.. And it's no so strange store an array, e.g. the mat-select multiple store an array too
As always we work with formArrays we declare a getter to manage in the .html
get answers()
{
return this.myForm.get('answer') as FormArray
}
Well, the form is a bit complex
<form [formGroup]="myForm">
<div formArrayName="answer">
<div *ngFor="let group of answers.controls;let i=index">
<p>{{users[i].code}}</p>
<div *ngFor="let user of users[i].email">
<input #check type="checkbox"
[value]="answers.at(i).value.email.indexOf(user.code)>=0"
(change)="onChange(i,user.code,check.checked)" >{{user.code}}<br>
</div>
</div>
</div>
</form>
See how we use [value]="answers.at(i).value.email.indexOf(user.code)>=0" Really it's not necesary if our "email" control is at first empy, but it possible we want in a future use this form to show the result, and our "eamil" can value, e.g. "[option1]"
Another thing to take account is that I use a template reference variable #check and send to the function OnChange check.checked -so we received in the function a boolean-
Our function OnChange get more simple
onChange(index:number, code: string, isChecked: boolean) {
const control=this.answers.at(index).get('email')
if (isChecked && control.value.indexOf(code)<0)
control.setValue([...control.value,code]
.sort((a:string,b:string)=>
this.users[index].email.findIndex(x=>x.code==a)>
this.users[index].email.findIndex(x=>x.code==b)?1:-1)
)
if (!isChecked && control.value.indexOf(code)>=0)
control.setValue(control.value.filter(x=>x!=code))
}
I like check if exist or not before remove/add the element
See that we need "sort" the response when the check is true -else we received the response, e.g. [option2,option1] -If our requeriments don't required we can remove the sort-
The stackblitz
What you need to do is to add emailCode as FormArray instead of FormControl, this way you will be able to check whether the questionCode already exists, and if yes, you can append to emailCode the option you checked.
The only things to change are on your onChange method
First you array variable, you need to add FormArray instead of FormControl
let array = new FormGroup({
questionCode: new FormControl(email),
emailCode: new FormArray([])
});
Then create a FormControl for your checked option
let codeOption = new FormControl(code)
And finally, in your if condition, check if the questionCode already exist to just append your formControl to it, or to create a new object.
if (isChecked) {
if (emailFormArray.controls.some(obj => obj.get('questionCode').value == email)){
(<FormArray>emailFormArray.controls.find(obj => obj.get('questionCode').value == email).get('emailCode')).push(codeOption);
}else{
(<FormArray>array.get('emailCode')).push(codeOption)
emailFormArray.push(array)
}
}
To be more clear I have modified your stackblitz to fit with your needs
I have not modified the else condition to remove the options on your FormArray but you just need to copy the if condition to get the index of the code element on your FormArray of emailCode.
You can make a function that traverses every answer and returns an object in your desired schema.
I am currently getting json object from server and the object also has many nested json object as well. So far, I've been using *ngFor = "let a of data | pipe" (the pipe to get deeply nested value) and single interpolation {{a.value['someValue']}} to get the deep nested value of json object for other situations but this isn't serving my purpose right now since I don't want to loop my json.
Is there any way to get deeply nested json value without using ngFor?
The part of json object I am getting from server.
UserProfile:
{name: 'Jess'
University: 'UC Berkley'
Major: 'Media Communication'
birthday: 1994}
categoryInfo:
["inish work with quality"]
currentArea
:"CA"
introInfo {
experience: [
0: {Company: 'Atlas', workingYears: 1, **recLetter**:'She was on time always,
never late. The quality of her work is very high-level.'}
1: {Company: 'Footstep', workingYears: 2, recLetter:'She was on time always,
never late. The quality of her work is very high-level.'}
]
introduction: "Hello I'm Jess"
}
And if I use aforementioned method, it will just loop 4 keys (UserProfile, categoryInfo, currentArea, and introInfo) which I don't want.
How can I get value that's in bold (recLetter) without using *ngFor?
in my component, I am doing this.
userInfo: UserDetailInfo[];
getUserDetail(): void {
this.userDetail.getUserDetail()
.subscribe
(
userInfo => this.userInfo = userInfo,
error => this.errorMessage = error
)
}
And I tried this in the html template but didn't work and I didn't know how to get 'recLetter'
{{userInfo.experience['0']}}
Please help!
Thank you in advance
For the starters, lets assume you get experience array always the same, with 2 elements.
The only thing that you need to do in the html is this:
{{ userInfo.experience[0].recLetter }}
In case you want to loop through the whole array exeperience and display recLetter you can do this:
<div *ngFor="let item of userInfo.experience">
{{item.recLetter}}
</div>
Try this
properties.pipe.ts
import {Pipe} from '#angular/core';
#Pipe({name: 'properties'})
export class PropertiesPipe {
transform(o: {}) {
return Object.entries(o).map(([key, value]) => ({
key,
value
}));
}
}
app.module.ts
import {propertiesPipe} from './properties.pipe';
#NgModule({
declarations: [PropertiesPipe, /* whatever else was here */],
// ... whatever else was here
}) export class AppModule { }
component.html
<ul>
<li *ngFor="property of userInfo | properties">
<span *ngIf="!Array.isArray(property.value)">
{{property.key}}: {{property.value}}
</span>
<span *ngIf="Array.isArray(property.value)">
{{property.key}}: <span *ngFor="value of property.value">{{value}}, </span>
</span>
</li>
</ul>
I've been stuck with one problem - I'm getting JSON from my service class, I am able to write to the console whole object, I'm able to display root level values, but for the nested values I get [object Object] or nothing at all; depends on various approaches.
I was trying to find a solution across StackOverflow and they all seemed to point for using pipes. Would that be something that you suggest in my case as well?
Here is my code:
In a parent component I simply pass the object to child:
`<app-item *ngFor="let item of items; let i = index" [item]="item[itemId]="i"></app-item> `
On a child class I have
#Input() item: Item;
And finally on a child html template I have the following structure:
<a [routerLink]="[itemId]" class="list-group-item clearfix" routerLinkActive="active">
<div class="pull-left" (click)="stateInfo()">
<h4 class="list-group-item-heading">{{ item.name }}</h4>
<p class="list-group-item-text">Item code : {{ item.code }}</p>
<p class="list-group-item-text">Item tag : {{ item?.tags }}</p>
</div>
</a>
I'vealso tried to extend like {{ item?.tags[i].name }} and various other ways I can think of but none seems to be working.
Tags entity is optional, hence the '?' in a path.
I also attached click event listener, so I can console.log(this.item). This is what I get in the console:
Object:
code: "001"
name: "Kitchen"
tags: Array[2]
0: Object
name: "tag1"
value: "32"
1: Object
name: "tag2"
value: "44"
...
As I understand you have your service as your middle layer between your DB and the view. You inject service in your component, then you call a method that is in your service (from your component). Your service is responsible for getting the data (using http) and mapping it to json. Your component is subscribing to the response, converts json to array and through interpolation is showing to the view. Right?
Tags are an array, so you would need to iterate that array and display them.
First, let's fix an error in your parent template:
[item]="item[itemId]="i"
is wrong. As you can see in your template you are iterating let item of items... so on that same line you can just pass the current item in the itreration, so simply pass that single (current) item:
[item]="item"
Then to iterating the tags. As mentioned it is an array, so you just iterate through it like you did with the items:
<p *ngFor="let tag of item.tags">{{tag.name}}</p>
That should work! :) Here's a Plunker
As a sidenote, is there a special reason why you are iterating through the items and assigning them to a new array and then back to the items array? Why not simply do:
.subscribe(data => {
this.items = data;
})
I got this code in AppComponent:
getPlanetsToView(page){
let pageToView = page*10 + 10;
for(var i=0; i<pageToView; i++){
this.planetsToView.push(this.planets.planets[i]);
}
}
ngOnInit() {
this.http.get('app/planets.json').subscribe(res => {
this.planets = res.json();
console.log(this.planets);
this.getPlanetsToView(0);
});
And I have this in template:
{{planetsToView[0].name | json}}
I have got problem:
Photo
When I tried with {{planetsToView[0] | json }} it works but contain another properties also.
Could be this problem:
At the time your component is initialized your JSON is not yet loaded into this.planets because the http.get call is asynchronous. Can you try this in your template: (Note the ? which is added)
{{planetsToView[0]?.name | json}}
The ? is called elivs operator and is used to safe guard against undefined references in view templates. Read more here: