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.
Related
I know this is an extremely simple question but I have yet to find a resource solution that will work or explain in a way that makes complete sense. I'm trying to get back into Angular after many years and never used TypeScript before. Currently struggling a lot with errors and what TypeScript is actually expecting me to do.
I have an app that connects to the Open Brewery DB. I'm trying to make a details page that fetches data based on an :id URL param.
app.com/breweries, give me a list of breweries
app.com/breweries/:id, give me specific details on that brewery
I have a list component that grabs a list of Breweries. So whatever comes back gets displayed in a list.
http.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { IBrewery } from './brewery/brewery';
#Injectable({
providedIn: 'root'
})
export class HttpService {
constructor(private http: HttpClient) { }
getBreweries() {
return this.http.get('https://api.openbrewerydb.org/breweries');
}
getBrewery(id) {
return this.http.get<IBrewery[]>(`https://api.openbrewerydb.org/breweries/${id}`)
}
}
list.component.ts
import { Component, OnInit } from '#angular/core';
import { HttpService } from '../http.service';
#Component({
selector: 'app-list',
templateUrl: './list.component.html',
styleUrls: ['./list.component.scss']
})
export class ListComponent implements OnInit {
breweries: Object;
constructor(private _http: HttpService) { }
ngOnInit(): void {
this._http.getBreweries().subscribe(data => {
this.breweries = data;
});
}
}
list.component.html
<h1>Breweries</h1>
<ul *ngIf="breweries">
<li *ngFor="let brewery of breweries">
<p class="name">{{ brewery.name }}</p>
<p class="country">{{ brewery.country}}</p>
Visit Website
</li>
</ul>
So all this works no errors everything seems fine...then comes the profile and where things break down.
brewery.component.ts
import { Component, OnInit } from '#angular/core';
import {ActivatedRoute} from '#angular/router';
import { HttpService } from '../http.service';
#Component({
selector: 'app-brewery',
templateUrl: './brewery.component.html',
styleUrls: ['./brewery.component.scss']
})
export class BreweryComponent implements OnInit {
brewery: object = {};
breweryId: string;
constructor(private _http: HttpService, private activatedRoute: ActivatedRoute) { }
ngOnInit(): void {
this.breweryId = this.activatedRoute.snapshot.params.id;
this._http.getBrewery(this.breweryId).subscribe(data => {
this.brewery = data;
})
}
}
brewery.component.html
<ul *ngIf="brewery">
<li>
{{brewery.name}}
</li>
<li>
{{brewery.city}}, {{brewery.state}}
</li>
</ul>
brewery.ts
export interface IBrewery {
name: string,
city: string,
state: string
};
The errors I'm getting are:
- ERROR in src/app/brewery/brewery.component.html:7:13 - error TS2339: Property 'name' does not exist on type 'object'.
- Error occurs in the template of component BreweryComponent.
src/app/brewery/brewery.component.html:10:13 - error TS2339: Property 'city' does not exist on type 'object'.
- Error occurs in the template of component BreweryComponent.
src/app/brewery/brewery.component.html:10:31 - error TS2339: Property 'state' does not exist on type 'object'.
So the problem I believe is that brewery needs to have assigned properties and types associated to those properties before I can declare them in the component template. If that is true, for the life of me I cannot figure out how or where I'm supposed to take the IBrewery and properly use it. I've seen examples where it gets used in the service as well as the mycomponent.component.ts file. In either instance it's about as clear as mud on how to fix the problem.
Short Answer: use Safe Navigation Operator
Update your html as below.
<ul *ngIf="brewery">
<li>
{{brewery?.name}}
</li>
<li>
{{brewery?.city}}, {{brewery?.state}}
</li>
</ul>
Better approach: use a loading spinner.
<div *ngIf="loading">
some loading spinner
</div>
<div *ngIf="!loading">
<li>
{{brewery?.name}}
</li>
<li>
{{brewery?.city}}, {{brewery?.state}}
</li>
</ul>
export class BreweryComponent implements OnInit {
brewery; // be default type will be any.
breweryId: string;
loading = false; // loading spinner.
constructor(private _http: HttpService,
private activatedRoute: ActivatedRoute) { }
ngOnInit(): void {
this.breweryId = this.activatedRoute.snapshot.params.id;
this.get();
}
get() {
this.loading = true;
this._http.getBrewery(this.breweryId)
.subscribe(data => {
this.brewery = data;
this.loading = false; // loading spinner hidden.
}, (error) => {
// handle error;
});
}
}
First of all, you should get the correct typing in your service. It should look like this:
getBreweries() {
return this.http.get<IBrewery[]>('https://api.openbrewerydb.org/breweries');
}
getBrewery(id) {
return this.http.get<IBrewery>(`https://api.openbrewerydb.org/breweries/${id}`)
}
As you can see, I added the expected type to getBreweries and changed the expected type in getBrewery(id). I'm not sure why it was set to IBrewery[] before, since you told us it should only give one specific detail of a brewery.
Now, when you subscribe to these, the parameter inside the subscibe function will be inferred to be the types you have set in the get type parameter. Therefore, it's a good idea to set the type of the component instance variable to that type too, like this:
export class ListComponent implements OnInit {
breweries: IBrewery[];
...
}
and
export class BreweryComponent implements OnInit {
brewery: IBrewery;
...
}
In general, you don't want to use the type object or Object, because it tells you nothing about the structure of the type. If you don't know the exact structure of your type or are too lazy to create an interface, you should use any.
And btw, the reason why the ListComponent worked to begin with was kinda lucky. the let x of y syntax is allowed for y of type object for some reason, and it seems like x is inferred to as any, so you could write whatever you wanted without getting an error. It's important to understand that typescript won't change anything in runtime, so the runtime types will be whatever they are no matter what your typescript types say.
export interface Iresumedata {
shortIntro: string,
fullIntro: string,
mob: number,
email: string,
profile: any
}
import {
Component,
OnInit
} from '#angular/core';
import {
ResumedataService
} from "../../services/resumedata.service";
#Component({
selector: 'app-experience',
templateUrl: './experience.component.html',
styleUrls: ['./experience.component.scss']
})
export class ExperienceComponent implements OnInit {
experiencedata: any = [];
constructor(private resumeservice: ResumedataService) {}
ngOnInit() {
this.resumeservice.getresumedata().subscribe(data => (this.experiencedata = data.experience));
}
}
I am trying to fetch data through service and successfully getting it, but the thing is whenever I am passing property such as experience or profile based on JSON object, its continuously throwing error like.
Property 'experience' does not exist on type 'Iresumedata[]'
where Iresumedata is my interface, guys how can I remove this error? Kindly take a look, what exactly should I do?
Please follow these step.
Your interface structure should be like
export interface Iresumedata {
shortIntro: string,
fullIntro: string,
mob: number,
email: string,
profile ?: any,
experience ?:any,
}
Import Iresumedata into your dashboard component
Use it like
this.resumeservice.getresumedata().subscribe(data:Iresumedata=>{ (this.experiencedata = data.experience)});
I am trying to fetch my user's username from Firebase Firestore Database using Ionic and AngularFire. I am using the valueChanges() method to get the observable, then trying to interpret the observable with an async pipe. However, when I run the code, I get the following error:
error
However, when I log the observable, it appears as shown:
observable
profile.page.ts:
import { Component, OnInit } from '#angular/core';
import { AngularFireAuth } from '#angular/fire/auth';
import { Router } from '#angular/router';
import { UserService } from '../user.service'
import { AngularFirestore, AngularFirestoreCollection } from '#angular/fire/firestore'
import { Observable } from 'rxjs';
#Component({
selector: 'app-profile',
templateUrl: './profile.page.html',
styleUrls: ['./profile.page.scss'],
})
export class ProfilePage implements OnInit {
constructor(public afAuth: AngularFireAuth, public router: Router, public user: UserService, public db: AngularFirestore) {
}
ngOnInit() {
}
logout() { this.afAuth.auth.signOut(); this.router.navigate(['/login']);}
}
profile.page.html:
<ion-content>
<ion-grid>
<ion-row justify-content-center align-items-center style="height: 50%">
<ion-button color="danger" size="small" shape="round" (click)="logout()">Logout</ion-button>
<p *ngFor="let users of (username | async)">{{ users.username }}</p>
</ion-row>
</ion-grid>
</ion-content>
Thanks in advance for any help.
You have that error because your username data is not an array so I would suggest you change your code like this. Make your username become an array then push it into array
username: string[] = [];
this.username = this.username.push(users.valueChanges());
Hi are you sure that users is an array?
Maybe a simple console.log(users) can give a better look of the data type you are receiving.
You should try to push/unshift to an array the mapped results from your service with a for of and return the array something like this for example:
private itemsCollection: AngularFirestoreCollection<User>
this.itemsCollection = this.afs.collection<User>('user', ref => ref.orderBy('name','desc').limit(5));
return this.itemsCollection.valueChanges().pipe(map( (users: User[]) =>{
let users = [];
for (const user of users) {
this.users.unshift(user);
}
return users
}))
afs is type AngularFirestore
I am having an issue I do not understand at all. I am fairly new angular so it may be something small but never the less.
When I try to build my project to publish it to a github page, the HTML components are failing on the build as the properties from the component do not exist. All of the errors relate to the HTML components not being away of the object properties. (Which are provided via an API service anyway!)
I have attempted to provide the minimum required code to illustrate the problem.
Error Dump:
ERROR in src\app\users\users.component.html(4,20): : Property 'queryString' does not exist on type 'UsersComponent'.
src\app\users\users.component.html(9,7): : Property 'queryString' does not exist on type 'UsersComponent'.
src\app\users\users.component.html(4,20): : Property 'queryString' does not exist on type 'UsersComponent'.
src\app\details\details.component.html(1,5): : Property 'name' does not exist on type 'Object'.
src\app\details\details.component.html(4,32): : Property 'RunnerName' does not exist on type 'Object'.
src\app\details\details.component.html(5,29): : Property 'LastTime' does not exist on type 'Object'.
src\app\details\details.component.html(6,29): : Property 'LastDistance' does not exist on type 'Object'.
src\app\details\details.component.html(7,29): : Property 'date' does not exist on type 'Object'.
user.component.html
<h1>Runners</h1>
<div>
<input type="text" [(ngModel)]="queryString" placeholder = "Search Runner Name">
</div>
<ul>
<li *ngFor = "let user of users | filterdata: queryString : 'RunnerName' ; let i = index">
<a routerLink = "/details/{{ user.RunnerId }}">{{ user.RunnerName }}</a>
<ul>
<li><strong>Runner ID: {{ user.RunnerId }}</strong></li>
</ul>
</li>
</ul>
user.component.ts
import { Component, OnInit } from '#angular/core';
//Importing my users service, up one level in project structure from here.
import { DataService } from '../data.service';
//RXJS will hold the data which is returned from the API...
//RESEARCH RXJS
import { Observable } from 'rxjs';
import { FormsModule } from '#angular/forms';
import { Pipe, PipeTransform } from '#angular/core';
#Component({
selector: 'app-users',
templateUrl: './users.component.html',
styleUrls: ['./users.component.scss']
})
//Export class implenets OnInit.
export class UsersComponent implements OnInit {
//Prop which holds returned API data
//of type obect.
users: Object;
//Creating instance of the service via dependancy injection.
constructor(private data: DataService) { }
//NG on init is one of the "lifecycle hooks" for angular components.
//Code in here will be executed when the component loads for ngOnInit.
ngOnInit() {
//Executing the method which is provided by the service.
//Adding data bind via subscribe.
this.data.getUsers().subscribe(
//returning the user data via single line return function
//passing the data value into the function.
(data) => {
//assinging the data to the user object.
this.users = data
//sorting the users object by runner ID.
//this.users.sort((a,b) => a.RunnerId - b.RunnerId);
}
);
}
}
data.service.ts
import { Injectable } from '#angular/core';
//Importing te angular HTTP Client
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
//Class which exports the service to the APP.
//We will import this class into the components when required.
export class DataService {
//Utilising the HTTP client import Class
//HTTP Client request expects JSON return data as default, their is no need to parse JSON anymore.
constructor(private http: HttpClient) {}
//Custom Method to return Users collection from the web API.
getUsers(){
//single line return statement.
return this.http.get('http://rundistance.azurewebsites.net/api/RunnerService')
}
//Function to return the detail of a single user, passing in the ID prop of currently selected target of objects master layer.
getUser(userId){
//single line return statement getting target object from API.
return this.http.get('http://rundistance.azurewebsites.net/api/RunnerService/'+userId)
}
//Returning posts from API.
getPosts(){
//single line return statement.
return this.http.get('https://jsonplaceholder.typicode.com/posts')
}
}
filterdata.pipe
import { Pipe, PipeTransform } from '#angular/core';
import { DataService } from './data.service';
#Pipe({
name: 'filterdata'
})
export class FilterdataPipe implements PipeTransform {
transform(items: any[], value: string, label:string): any[] {
if (!items) return [];
if (!value) return items;
if (value == '' || value == null) return [];
return items.filter(e => e[label].toLowerCase().indexOf(value) > -1 );
}
}
I am having a hard time using a async object in a html composition.
Here is my model:
export class Version {
isGood: boolean;
constructor(isGood: boolean) {
this.isGood= isGood;
}
}
This model is called by a component as follows:
#Injectable()
export class MyComponent {
public version: Version;
constructor(private _myService: VersionService) {}
getVersion(): void {
// async service that gets the versions
this._myService.getVersion().subscribe(
data => this.version= data,
error=> console.log(error),
() => console.log("getting all items complete")
);
}
}
My template references to the version variable as follows:
<button (click)="getVersion()">Get Version</button>
<hr>
<p style="color:red">{{error}}</p>
<h1>Version</h1>
<p>{{version.isGood}}</p>
However, I get an exception:
Cannot read property 'isGood' of undefined
From scavenging the internet, I see that my problem is because the version object is null. If I do something like:
<p>{{version | json}}</p>
I can see the correct version
If I do something like
<p>{{version.isGood | async}}</p>
I see nothing
If I edit MyComponent, and set
public version: Version = new Version();
I can execute the .isGood property fetch, but it is always empty.
Is there a different way I am supposed to load a property if I am using it in an asynchronous manner?
Use the ? operator or use an *ngIf.
<p>{{version?.isGood}}</p>
<p *ngIf="version">{{version.isGood}}</p>
Try this:
<p>{{version?.isGood}}</p>
This tells Angular to protect against version.isGood being undefined or null until you click and fetch the data for version through your service.
First me correct you. #Injectable() makes a normal typescript class as injectable service where you can share data.
To make a component you need to use #Component decoratore.
The process of data sharing between component and within the application is to create a service and add that as provides in module. And then its singleton object will available everyshere.
//module
import {NgModule} from '#angular/core';
import {YourService} from "./services/your-service";
#NgModule({
imports: [
BrowserModule
],
declarations: [
AppComponent
],
providers: [
YouService
],
bootstrap: [AppComponent]
})
export class AppModule {
}
//this is your component
import {Component} from '#angular/core';
import {YourService} from "../../services/your-service";
#Component({
selector: 'component-app',
templateUrl: '../../views/app.component.html',
})
export class HeaderComponent {
constructor(public yourService: YourService) {
}
}
//your service
import {Injectable} from "#angular/core";
#Injectable()
export class YourService {
private _message: string = 'initial message';
private _style: string = 'success';
get message(): string {
return this._message;
}
set message(value: string) {
this._message += value;
}
get style(): string {
return this._style;
}
set style(value: string) {
this._style = value;
}
}
//finally your view
<div class="row">
<div [class]=""><h1>{{swapService.message}}</h1></div>
</div>
Observable Data services.
#Injectable()
export class MyComponent {
public version = new ReplaySubject<Version>();
constructor(private _myService: VersionService) {}
init(): void {
// async service that gets the versions
this._myService.getVersion().subscribe(
data => this.version.next(data),
error=> console.log(error),
() => console.log("getting all items complete")
);
}
getVersion(): void {
this.version.asObservable();
}
}
In the template
<button (click)="init()">Get Version</button>
<hr>
<p style="color:red">{{error}}</p>
<h1>Version</h1>
<p>{{(version |async)?.isGood}}</p>