Angular4: cannot read the property of undefined - javascript

I am trying to learn angular4 with the tutorial they provided in website
Here is the code
hero.ts
export class Hero{
constructor(
public id: number,public name: string
){}
}
in component.ts
import { Component } from '#angular/core';
import {Hero } from './hero';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title : string;
hero : string;
selectedHero: Hero;
heroes = [
new Hero(1, 'Windstorm'),
new Hero(13, 'Bombasto'),
new Hero(15, 'Magneta'),
new Hero(20, 'Tornado')
]
myHero = this.heroes[0];
constructor(){
this.title = 'Tour of heros';
}
onSelect(hero: Hero): void {
this.selectedHero =hero;
}
}
html
<ul>
<li *ngFor="let hero of heroes" (click)="onSelect(hero)">
{{ hero.name }}
</li>
</ul>
<p>{{selectedHero.name}}</p>
when click on each li i would like to display details in selected object but i got the following error
selectedHero.name is undefined

Check in the template if selectedHero is set before access any of its property
<p *ngIf="selectedHero">{{selectedHero.name}}</p>
or create an empty instance in the component (updated answer)
selectedHero: Hero = new Hero(12, 'somename');

Related

How to set default value in RxJs with BehaviorSubject

I wonder how to set default value in RxJs with BehaviorSubject, so I would like to have default value 15 images. From my interface I would like take only 15 urls, and how to subscibe them. I would be very grateful if someone could explain to me how to make it work.
app component
import { Component, OnInit } from '#angular/core';
import { BehaviorSubject } from 'rxjs';
import { DogInfo } from './interface/dogInfo';
import { HttpService } from './service/http.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
constructor(private httpService: HttpService) { }
items$: any = new BehaviorSubject<DogInfo[]>();
ngOnInit() {
this.items$.subscribe((item: any) => this.httpService.fetchDogsFromApi());
}
}
interface
export interface DogInfo{
id: number;
name?: string;
breadGroup?: string;
lifeSpan?: string;
breadFor?: string;
temperament?: string[];
url: string;
}
You can use like below code:
items$: any = new BehaviorSubject<DogInfo[]>([{id: 0, url: 'your-url'}]);
Probably there is a better way, you could use take and grab the first 15 items from dogs, and set that value to your custom Subject as:
items$ = new BehaviorSubject<DogInfo[]>([]); // initialize as an empty array
private dogsArray: DogInfo[] = [];
constructor(private http: HttpService) {}
ngOnInit(): void {
this.http.fetchDogsFromApi().pipe(
take(15),
tap((dog) => this.dogsArray.push(dog))
).subscribe({
// after the 15 dogs are taken, it will emit that data to the template
complete: () => this.items$.next(this.dogsArray)
});
}
HTML
<ng-container *ngIf="(items$ | async) as dogs">
<div *ngFor="let dog of dogs; let i = index">
<p>Dog #: {{ i }}</p>
<p>Name: {{ dog.name }}</p>
<p>...</p>
</div>
</ng-container>

How to transfer variables from a ts fie to another, angular

I defined a property here in my function
evs: string
...
openArticle(url){
this.evs = url
console.log(this.evs)
this.navCtrl.navigateForward('/url-page')
}
And I a trying to pass the value of 'this.evs' to another ts file and use its value but I do not know how to do this. I tried exporting it like this.
export const webpage = this.evs
but this.evs has no value until someone performs the openArticle function ad so I keep getting the error. "Cannot read property 'evs' of undefined"
What i need to do is tranfer the variable to the 'url-page' page and use the value of this.evs only after the openArticle function has bee called. How do I go about this?
As per my understanding you are trying to share data between two components.
So choose one of them as per your requirements.
Parent to Child: Sharing Data via Input().
Child to Parent: Sharing Data via Output() and EventEmitter.
Unrelated Components: Sharing Data with a Service.
This link will be helpful.
If the components have a parent/child relationship, You can share data between them via #Inpput() and #Output() decorators.
Sharing data from Parent to Child using #Input() :
<h3>Parent Component</h3>
<label>Parent Component</label>c
<input type="number" [(ngModel)]='parentValue'/>
<p>Value of child component is: </p>
<app-child [value]='parentValue'></app-child>
And in the child component, the 'parentValue' can be received as :
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {
#Input() value: number;
constructor() { }
ngOnInit() {
}
}
Now, in the case of sending data from Child to Parent, we can use an #Output() event emitter. So the parent would have a function to receive the emitted data from child as :
parent-app.component.html
<app-child [value]="parentValue" (childEvent)="childEvent($event)"></app-child>
parent-app.component.ts
childEvent(event) {
console.log(event);
}
And, the child.component.ts would look like :
import { Component, OnInit, Input, Output, EventEmitter } from '#angular/core';
#Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {
#Input() PData: number;
#Output() childEvent = new EventEmitter();
constructor() { }
onChange(value) {
this.childEvent.emit(value);
}
ngOnInit() {
}
}
If the components do not have a parent/child relationship, a shared service can be used, say, SharedService which has a BehavioralSubject, that emits value from either component, and the other component can then catch the changed value.
Eg:
import { Injectable } from '#angular/core';
import { BehaviorSubject } from "rxjs/BehaviorSubject";
#Injectable()
export class SharedService {
comp1Val: string;
_comp1ValueBS = new BehaviorSubject<string>('');
comp2Val: string;
_comp2ValueBS = new BehaviorSubject<string>('');
constructor() {
this.comp1Val;
this.comp2Val;
this._comp1ValueBS.next(this.comp1Val);
this._comp2ValueBS.next(this.comp2Val);
}
updateComp1Val(val) {
this.comp1Val = val;
this._comp1ValueBS.next(this.comp1Val);
}
updateComp2Val(val) {
this.comp2Val = val;
this._comp2ValueBS.next(this.comp2Val);
}
And component1 as follows :
import { Injectable } from '#angular/core';
import { BehaviorSubject } from "rxjs/BehaviorSubject";
#Injectable()
export class SharedService {
comp1Val: string;
_comp1ValueBS = new BehaviorSubject<string>('');
comp2Val: string;
_comp2ValueBS = new BehaviorSubject<string>('');
constructor() {
this.comp1Val;
this.comp2Val;
this._comp1ValueBS.next(this.comp1Val);
this._comp2ValueBS.next(this.comp2Val);
}
updateComp1Val(val) {
this.comp1Val = val;
this._comp1ValueBS.next(this.comp1Val);
}
updateComp2Val(val) {
this.comp2Val = val;
this._comp2ValueBS.next(this.comp2Val);
}
Component 2 :
import { Component, AfterContentChecked } from '#angular/core';
import { SharedService } from "../../common/shared.service";
#Component({
selector: 'app-component2',
templateUrl: './component2.component.html',
styleUrls: ['./component2.component.css']
})
export class Component2Component implements AfterContentChecked {
comp1Val: string;
comp2Val: string;
constructor(private sharedService: SharedService) {
this.sharedService.comp2Val = "Component 2 initial value";
}
ngAfterContentChecked() {
this.comp1Val = this.sharedService.comp1Val;
}
addValue(str) {
this.sharedService.updateComp2Val(str);
}
}
You can find more on different types of subjects here

#Input decorator returning undefined in child class

I have two Components StudentsComponent and UnderGradsComponent. In the students component, I created a method to get me the names of students who are "undergrads" in a list. Then im sending this list ot the undergrads component. However, I am always getting that list as undefined inside the undergrads component.
Here is the code for my StudentsComponent
import { Component, OnInit } from "#angular/core";
#Component({
selector: "app-students",
templateUrl: "./students.component.html",
styleUrls: ["./students.component.css"]
})
export class StudentsComponent implements OnInit {
students = [
{ name: "Marwa", level: "undergrad" },
{ name: "Heba", level: "undergrad" },
{ name: "Amal", level: "postgrad" }
];
public undergradsList = this.undergrads();
constructor() {}
ngOnInit() {
this.undergrads();
console.log(this.undergrads);
}
undergrads() {
var Arrayres = new Array();
for (var i = 0; i < this.students.length; i++) {
if (this.students[i].level === "undergrad") {
Arrayres.push(this.students[i].name);
}
}
console.log(Arrayres);
return Arrayres;
}
}
Here is the html for the StudentsComponent
<app-under-grads *ngIf="undergradsList" [studentList]="undergradsList">
</app-under-grads>
Here is the code for the UndergradsComponent
import { Component, OnInit, Input } from "#angular/core";
#Component({
selector: "app-under-grads",
templateUrl: "./under-grads.component.html",
styleUrls: ["./under-grads.component.css"]
})
export class UnderGradsComponent implements OnInit {
#Input() public studentList;
constructor() {}
ngOnInit() {
console.log(this.studentList);
}
}
Finally here is the code for my HTML UnderGradsCompoenent
<h2>UnderGrads</h2>
<div>
<ul>
<li *ngFor="let x of studentList">{{ x }}</li>
</ul>
</div>

'object' does not contain such a member Angular 5

I am new to Angular and trying to make a small application.
I referred 'object' does not contain such a member
answer but I am not getting my solution from there.
profile.component.ts
import { Component, OnInit } from '#angular/core';
import { AuthService } from '../../services/auth.service';
import { Router } from '#angular/router';
#Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
user: Object;
constructor(private authService: AuthService, private roter: Router) {}
ngOnInit() {
this.authService.getProfile().subscribe(
profile => {
this.user = profile.user;
},
err => {
console.log(err);
return false;
}
);
}
}
profile.component.html
<div *ngIf="user">
<h2 class="page-header">
{{ user.name }}
</h2>
<ul class="list-group">
<li class="list-group-item">
Username: {{ user.username }}
</li>
<li class="list-group-item">
Email: {{ user.email }}
</li>
</ul>
</div>
Visual studio code is showing this
Error:
[Angular] Identifier 'username' is not defined. 'Object' does not contain such a member
property user of ProfileComponent
Either change
user: Object;
by
user: any;
In your profile.component.ts this will surely work,because initially you have declared it as object so while running the or building app typescript compilation fails due to accessed as user.username.
Either you change the type to any or create interface or type having required properties and assign this type to user
Ex:
profile.component.ts:
interface userObject {
username:string,
password:string
}
access as
export class ProfileComponent implements OnInit {
user : userObject;
}
you have defined user in ProfileComponent class as Object type.wich has no Typescript Model defined.Therefore Typescript is unaware of the structure of the User Object.
So you create a model like this.
interface User{
username : String;
password: ...
....
}
and then use it as type like user : User
The problem will be solved.
When you define an object it doesn't have firstName or lastName. So when accessing from ui it shows the error. So first initialize as given below. Then the issue will be solved.
let user = {firstName: "", lastName:""};
Code:
import { Component, OnInit } from '#angular/core';
import { AuthService } from '../../services/auth.service';
import { Router } from '#angular/router';
#Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
let user = {firstName: "", lastName:""};
constructor(private authService: AuthService, private roter: Router) {}
ngOnInit() {
this.authService.getProfile().subscribe(
profile => {
this.user = profile.user;
},
err => {
console.log(err);
return false;
}
);
}
}
Object refers to the inbuilt object constructor function, which obviously doesn't have the property username. Since you're setting the type of user to be Object and trying to access the property username that doesn't exist, it's showing error.
If you want to define your own types, refer this.

No $key inside a AngularFireDatabase.object

In my Angular app I am trying to update records on Firebase database. I am using AngularFireDatabase to first bind the list when then be used to update the particular records. But the problem is that there is no $key.
The app.component.html code is:
<ul>
<li *ngFor="let course of courses">
{{course}}
<button (click)="update(course)">Update</button>
</li>
</ul>
The app.component.ts is:
import { AngularFireDatabase } from 'angularfire2/database';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnDestroy {
courses: any[];
constructor(private db: AngularFireDatabase) {
this.subscription = db.list('/couses').valueChanges().subscribe(c => {
this.courses = c;
});
}
update(course) {
console.log(course.$key);
//gives key undefined
}
}
How to get key so that I can update a particular record?
The snapshot of firebase database is:
I solved the problem using .snapshotChanges() method.
The constructor code becomes:
constructor(private db: AngularFireDatabase) {
this.subscription = db.list('/couses').snapshotChanges().subscribe(c => {
this.courses = c;
});
The update() method:
update(course) {
this.db.list('/couses').set(course.key,"Updated");
}
So Now I am getting the key for doing update of the particular item.
I hope it help, if you have better solution then please have your answer.

Categories