Unable to loop array of objects in angular6 - arrays

I'm trying to fetch movie data from omdbapi but i'm not getting able to print this value in html
.ts
import { Component, } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(private _httpClient: HttpClient) {}
results: any = [];
getMovies(title) {
`enter code here`
this._httpClient.get("http://www.omdbapi.com/?apikey=d5dc2a5a&s=" + title)
.subscribe((data) => {
this.results = data;
//this.results.Search;
console.log(this.results)
})
}
}
Console value

You're probably using *ngFor in your template on results. But since you're assigning data to results and data is an Object, it's giving an error as *ngFor assumes an iterative Data Structure.
As can be seen from your Screenshot, there's a Search array on your data.
Change this.results = data; to this.results = data.Search;
import { Component } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(private _httpClient: HttpClient) {}
results: any = [];
getMovies(title) {
this._httpClient.get("https://www.omdbapi.com/?apikey=157f9eb7&s=" + title)
.subscribe((data: any) => {
this.results = data.Search;
console.log(this.results);
})
}
ngOnInit() {
this.getMovies('The Dark Knight');
}
}
Here's a Sample StackBlitz for your ref.

You can achieve this using keyvalue pipe as below:
<div *ngFor="let item of results | keyvalue">
<b>{{item.key}}</b> : <b>{{item.value}}</b>
</div>

You are getting an object in your response. You need use ? operator in *ngFor loop like this to get array for asynchronous http service.
<ul>
<li *ngFor="let result of results?.Search">{{result.Title }}</li>
</ul>
and you can display totalResults like this :
<span>Total: {{results?.totalResults}}</span>

Related

ANGULAR Iterate over an Array within a Model

Synopsis:
I am trying to iterate over an array that is returned as part of an object. The object has three properties 2 string, 1 array. I want to iterate over the array i my html but can't seem to get it to populate. I can get both strings to show, but cannot figure out how to iterate the inner array for values.
Policy.ts
import { Document } from './Document';
export interface Policy {
insuredName: string;
policyNumber: string;
documents: Document[];
}
Document.ts
export interface Document {
url: string,
docType: string
}
I bind the model("policy") in my parent component
#Component({
selector: 'app-search',
templateUrl: './search.component.html',
styleUrls: ['./search.component.css']
})
export class SearchComponent implements OnInit {
policy: any = {};
constructor(private policyService: PolicyService, private alertify: AlertifyService) { }
ngOnInit() {
}
loadPolicy() {
this.policyService.getPolicy(this.policy.policyNumber).subscribe((res) => {
this.policy.insuredName = res.insuredName;
this.policy.policyNumber = res.policyNumber;
this.documents = res.documents;
}, error => {
this.alertify.error(error);
})
}
I pass the data to my child component
Search.component.html
<app-documentList [policy]=policy></app-documentList>
and then bind it in the child
export class DocumentListComponent implements OnInit {
#Input() policy: Policy;
ngOnInit() {
}
but when I finally try the iteration all I get is the first property (insuredName) and nothing for the *ngFor
<div>
<div class="test">
<p>{{policy.insuredName}}</p>
<h2 *ngFor="let doc of policy.documents">{{doc.url}}</h2>
</div>
</div>
Try replacing this.documents = res.documents; with this.policy.documents = res.documents;.
Looks like you are binding the result to a wrong variable.
Also you might not have to assign values manually. You could do the following
import { Policy } from './Policy';
#Component({
selector: 'app-search',
templateUrl: './search.component.html',
styleUrls: ['./search.component.css']
})
export class SearchComponent implements OnInit {
policy: Policy = {};
constructor(private policyService: PolicyService, private alertify: AlertifyService) { }
ngOnInit() {
}
loadPolicy() {
this.policyService.getPolicy(this.policy.policyNumber).subscribe((res: Policy) => {
this.policy = res;
}, error => {
this.alertify.error(error);
});
}
}

Call angular method in series -Highcharts

All I'm a newbie in learning Angular and highchairs. My issue is how to call angular method in series to render charts dynamically.
I referred this link ,but i'm not understanding anything from that:
link:https://www.highcharts.com/blog/tutorials/194-using-highcharts-with-angular-js/.
link: Call an angular component method when we click on highchart series
Kindly app me to solve this.
app.component.ts
import { Component } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
name:string = '';
age:number;
found:boolean;
constructor(private httpClient: HttpClient) { }
onNameKeyUp(event:any){
this.name = event.target.value;
this.found = false;
}
getProfile(){
this.httpClient.get(`https://my-json-server.typicode.com/techsithgit/json-faker-directory/profiles/?name=${this.name}`)
.subscribe(
(data:any[] )=>{
if(data.length){
this.age = data[0].age;
this.found = true;
}
}
)
}
}
app.component.html
<input type ="text" (keyup) = "onNameKeyUp($event)">
<button (click)= "getProfile()">Get User Details</button>
<br>
<div *ngIf="found" >
<span>{{name}}'s age is {{age}}</span>
</div>

Dynamic *ngIf template

Would like to show dynamic data using *ngIf and ng-template. For example I would to display the title 'List of courses' if courses.length > 0 or No courses yet when courses.length == 0
So far, I have my
courses.component.html
<div *ngIf="courses.length > 0; then coursesList else noCourses">
<ng-template #coursesList>
List of courses
</ng-template>
<ng-template #noCourses>
No courses yet
</ng-template>
</div>
my app.component.html
<app-ng-if-courses [courses]="courses"></app-ng-if-courses>
my ng-if-courses.component.ts
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'app-ng-if-courses',
templateUrl: './ng-if-courses.component.html',
styleUrls: ['./ng-if-courses.component.css']
})
export class NgIfCoursesComponent implements OnInit {
#Input('courses') courses = [];
constructor() { }
ngOnInit() {
}
}
my app.component.ts
import { } from './ng-if-courses/ng-if-courses.component';
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'Angular app';
// <app-ng-if-courses>
// courses = [];//no courses
courses = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
}
I think it will be very simple but I am a learning AngularJS

Does array change to an object after #Input() into child?

I'm quite new to Angular 2 and I would like to transfer an array made in a parent component, via #Input(), to its child.
In the parent I create the array, add data from a service, and display it in the console (Console output 1). In the child component I then use ngOnChanges to display it in the console again (Console output 2). As you can see below, the length of the array changes from 12 to 0. I suppose this is because the array changes to an object when it's passed to the child?
How would I fix this?
Parent
import { Component, OnInit } from '#angular/core';
import { Module, MapMarkerData } from './coreclasses';
import { TimelineService } from './input.service';
#Component({
selector: 'my-app',
templateUrl: 'app/app.component.html',
providers: [TimelineService]
})
export class AppComponent implements OnInit {
modules: Module[];
mapMarkerData: any;
constructor(private timelineService: TimelineService) {
this.mapMarkerData = new Array<MapMarkerData>();
}
getModules(): void {
this.timelineService.getModules().then(modules => {this.modules = modules; this.setMapModuleData(this.modules);});
}
setMapModuleData(modules: Array<any>): void {
for (let module of modules) {
if (module.className) {
var id = module.id;
var className = module.className;
let contents: Object = {id: id, className: className};
this.mapMarkerData.push(contents);
}
}
console.log(this.mapMarkerData); // CONSOLE OUTPUT 1
console.log(this.mapMarkerData.length);
}
}
Child
import { Component, Input, OnInit, OnChanges, SimpleChanges } from '#angular/core';
import { MapMarkerData } from './coreclasses';
#Component({
selector: 'timeline-map',
templateUrl: 'app/timeline.map.component.html'
})
export class TimelineMapComponent implements OnChanges {
#Input()
mapMarkerData: any;
ngOnChanges(changes: any) {
console.log(this.mapMarkerData); // CONSOLE OUTPUT 2
console.log(this.mapMarkerData.length);
}
}
Parent Template
...
<div id="map" class="mapLarge">
<timeline-map [mapMarkerData] = "mapMarkerData"></timeline-map>
</div>
...
Console Output 1
Array[12]: [Object, Object, ... ]
Console Output 2
Array[0]: [Object, Object, ... ]
EDIT Important
because you're passing same reference into child component, so the ngOnChanges lifecycle only fired 1 time.
please checkout this version, open your console tabs: https://plnkr.co/edit/WUDGOx?p=preview
so, if you wanna catch every changes in ngOnChanges lifecycle, you must passing a difference array, like this: https://plnkr.co/edit/8awiqe?p=preview
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-root',
template: `
<h2>App Component</h2>
<p><strong>This app will trigger ngOnChanges with immutable array</strong></p>
<app-content [posts]="posts">
</app-content>
`
})
export class AppComponent implements OnInit {
latestPosts: any[] = [];
posts: any[] = [];
ngOnInit() {
// fake api call
setTimeout(() => {
this.latestPosts.push.apply(this.latestPosts, [
{name: 'Post no.1'},
{name: 'Post no.2'},
{name: 'Post no.3'}
]);
this.posts = [].concat(this.latestPosts);
}, 300);
}
}
=== 2nd option === you could check by yourself in DoChecklifecycle: https://plnkr.co/edit/oxsISD?p=preview
import { Component, Input, DoCheck, IterableDiffers } from '#angular/core';
#Component({
selector: 'app-content',
template: `
Status: {{ status }}
<div *ngFor="let post of pp">
{{ post.name }}
</div>
`
})
export class ContentComponent implements DoCheck {
#Input()
posts: any[];
differ: IterableDiffers;
status: string = '';
constructor(private differs: IterableDiffers) {
this.differ = this.differs.find([]).create(null);
}
ngDoCheck() {
var changes = this.differ.diff(this.posts);
if (changes) {
console.log('ngDoCheck');
this.status = 'ngDoCheck invoked!'
}
}
}
Note that you must pay a cost because the above ngDoCheck method will invoke on every change detection run.
https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html
https://angular.io/docs/ts/latest/api/core/index/DoCheck-class.html
https://angular.io/docs/ts/latest/api/core/index/SimpleChange-class.html
https://angular.io/docs/ts/latest/api/core/index/IterableDiffers-class.html
END
for the initial state, it's empty, then the value will assign to this property.
js log async

Angular 2 I don't know how to delete a row of a pushed Object

First let me be clear about my problem/issue:
First it was like this: https://www.dropbox.com/s/92z2oe7f4w5x2b5/conditions.jpg?dl=0 Here it deletes the last created Object in my case Conditions.
but i want to delete each condition separately like this see the red box next to each row: https://www.dropbox.com/s/ptwq6sk6da4p21k/new.jpg?dl=0
import {Component, OnInit, DynamicComponentLoader, Input} from 'angular2/core';
import {Condition} from './condition';
import {DateCondition} from './datecondition.component';
import {StringCondition} from './stringcondition.component';
import {SelectCondition} from './selectcondition.component';
import {ConditionDetailComponent} from './conditiondetail.component';
import {ConditionService} from './condition.service'
#Component({
selector: 'condition-builder',
templateUrl: 'app/conditionbuilder.component.html',
directives: [ConditionDetailComponent],
})
export class ConditionBuilderComponent implements OnInit {
conditions: Condition[] = [];
catalog: Condition[] = [];
constructor(public _conditionService: ConditionService) { }
getConditions() {
this._conditionService.getConditions().then(conditions => this.catalog = conditions);
}
ngOnInit() {
this.getConditions();
}
onChange(conditionsIndex, selectedCondition:string): void {
this.conditions[conditionsIndex] = this.catalog.find(condition => condition.name == selectedCondition);
}
newCondition() {
this.conditions.push(this.catalog[0]);
}
deleteCondition() {
this.conditions.pop();
}
}
In the code above i'll import the getConditions with the object of conditions in my case. Does any one know how i do this and what is the best way to handle this issue?
Here i want to
import {Component, OnInit, Input, DynamicComponentLoader, ElementRef} from 'angular2/core';
import {Condition} from './condition';
import {DateCondition} from './datecondition.component';
import {StringCondition} from './stringcondition.component';
import {SelectCondition} from './selectcondition.component';
import {ConditionBuilderComponent} from "./conditionbuilder.component";
#Component({
selector: 'condition-detail',
template: '<div #child></div>'
+ '<a class="btn btn-danger" (click)="deleteCondition()"><i class="glyphicon glyphicon-minus"></i></a>'
})
export class ConditionDetailComponent implements OnInit {
#Input() condition: Condition;
dcl:DynamicComponentLoader;
elementRef:ElementRef;
constructor(dcl: DynamicComponentLoader, elementRef: ElementRef) {
this.dcl = dcl;
this.elementRef = elementRef;
}
ngOnInit() {
this.dcl.loadIntoLocation(this.condition, this.elementRef, 'child');
}
deleteCondition() {
HOW CAN I DELETE THE CONDITION ROW HERE?
}
Like this is the code build, ill hope it is clear for you to help me out. How does the deleteCondition method know which row he needs to deleten and how do i delete it out of the array in the code above the page?
Ill hope someone can help me out!!
You could provide the list to the sub component and remove the current element from it. This way the associated component in the loop will be removed.
The main component:
#Component({
selector: 'my-app',
template: `
<div *ngFor="#elt of data">
<my-component [elt]="elt" [data]="data"></my-component>
</div>
`,
directives: [MyComponent]
})
export class AppComponent {
constructor() {
this.data = [
{name: 'name1'},
{name: 'name2'},
{name: 'name3'},
{name: 'name4'}
];
}
}
The child component:
#Component({
selector: 'my-component',
template: `
<div>{{elt.name}} <span (click)="delete()">X</span></div>
`
})
export class MyComponent {
#Input()
elt: any;
#Input()
data: any[];
delete() {
var index = this.data.indexOf(this.elt);
this.data.splice(index, 1);
}
}
See this plunkr: https://plnkr.co/edit/o5O0Rr?p=preview.

Resources