Cannot find namespace error for model in Angular2/TypeScript - javascript

The FeaturedCategories model
export class FeaturedCategories {
categories: Array<{ id: number, title: string, graphic: string, categorycards: Array<{}> }>;
}
Also tried this:
export class FeaturedCategories {
id: number;
title: string;
graphic: string;
categorycards: Object[];
}
The Component
import { Component, ChangeDetectionStrategy, ViewEncapsulation } from '#angular/core';
import { ApiService } from '../shared/services/api.service';
import { FeaturedCategories } from '../shared/models/home/featuredcategories';
#Component({
changeDetection: ChangeDetectionStrategy.Default,
encapsulation: ViewEncapsulation.Emulated,
selector: 'home',
styleUrls: [ './home.component.css' ],
templateUrl: './home.component.html'
})
export class HomeComponent {
testFeaturedCategories: Array<FeaturedCategories>;
constructor(private api: ApiService) {
// we need the data synchronously for the client to set the server response
// we create another method so we have more control for testing
this.universalInit();
}
universalInit() {
console.log('universalInit...')
this.api.getFeatured()
.subscribe(categories => {
console.log('categories', categories);
this.testFeaturedCategories = categories
});
}
}
This will work: testFeaturedCategories: Array<{}>;
However I'm trying to use TypeScript to let my App know what type of model to expect.
This causes the error above:
testFeaturedCategories: FeaturedCategories.categories;
And if I just try this: testFeaturedCategories: FeaturedCategories;
I get a type [{}] is not assignable error.
UPDATE
So I noticed that when I commented out all the keys in my FeaturedCategories model finally the error goes away and
featuredCategories: FeaturedCategories[]; will work.
However now this is just an empty object without keys to expect :(
export class FeaturedCategories {
// id: number;
// title: string;
// graphic: string;
// categorycards: Object[];
}

this is working fine for me.
export class MyComponent {
categories: FeaturedCategories[] = [{
id: 1,
title: "",
graphic: "",
categorycards: [{}]
}];
}
export class FeaturedCategories{
id: number;
title: string;
graphic: string;
categorycards: Object[];
}

My problem was trying to type my Array, instead of just using the Typed objects that exist in the larger Array.
Also had a problem in my service, originally I had this:
/**
* Get featured categories data for homepage
* /wiki
*/
getFeatured(): Observable<[{}]> {
return this.http.get(`${this.getFeaturedUrl}/home`)
// .do(res => console.log('getFeatured res', res.json()))
.map(res => res.json())
.catch(this.handleError);
}
I did not need or could even use a type for my larger Categories array, what I needed was a smaller type for the exact Objects that exist in that larger Array:
export class FeaturedCategory {
id?: number;
type: string;
title: string;
graphic?: string;
video?: string;
categorycards: Array<{}>;
}
So now with the correct Type of Objects inside my Array I added it to the service:
getFeatured(): Observable<[FeaturedCategory]> {
return this.http.get(`${this.getFeaturedUrl}/home`)
.map(res => res.json())
.catch(this.handleError);
}
Now back in my Component I imported the single Typed Object
import { FeaturedCategory } from '../shared/models/home/featuredcategory';
Then typed the variable:
featuredCategories: Array<FeaturedCategory>;
And finally in ngOnInit
ngOnInit() {
this.api.getFeatured()
.subscribe(categories => {
console.log('categories', categories);
this.featuredCategories = categories;
});
}
No more errors :)

Related

NestJS/TypeORM: Cannot read property 'createQueryBuilder' of undefined

Calling 'localhost:3000/contacts' (with or without parameters) at postman returns me this error and i don't know why. My backend is connected to a PostgreSQL db.
TypeError: Cannot read property 'createQueryBuilder' of undefined
at ContactsRepository.Repository.createQueryBuilder (...\Documents\Visual Studio Code Projects\funds-backend-nestjs\node_modules\typeorm\repository\Repository.js:17:29)
at ContactsRepository.getContacts (...\Documents\Visual Studio Code Projects\funds-backend-nestjs\dist\contacts\contacts.repository.js:17:34)
at ContactsService.getContacts (...\Documents\Visual Studio Code Projects\funds-backend-nestjs\dist\contacts\contacts.service.js:24:39)
at ContactsController.getContacts (...\Documents\Visual Studio Code Projects\funds-backend-nestjs\dist\contacts\contacts.controller.js:25:37)
at ...\Documents\Visual Studio Code Projects\funds-backend-nestjs\node_modules\#nestjs\core\router\router-execution-context.js:38:29
at processTicksAndRejections (internal/process/task_queues.js:93:5)
at async ...\Documents\Visual Studio Code Projects\funds-backend-nestjs\node_modules\#nestjs\core\router\router-execution-context.js:46:28
at async ...\Documents\Visual Studio Code Projects\funds-backend-nestjs\node_modules\#nestjs\core\router\router-proxy.js:9:17
My code looks like this:
#EntityRepository(Contact)
export class ContactsRepository extends Repository<Contact> {
async getContacts(filterDto: GetContactsFilterDto): Promise<Contact[]> {
const { name, search } = filterDto;
// const query = this.createQueryBuilder('contacts');
const query = await this.createQueryBuilder()
.select('contacts')
.from(Contact, 'contacts');
if (name) {
query.andWhere('contacts.name = :name', { name });
}
if (search) {
query.andWhere(
'(contacts.email LIKE :search OR contacts.telephone LIKE :search)',
{ search: `%${search}%` },
);
}
const contacts = await query.getMany();
return contacts;
}
import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
#Entity({ name: 'contacts' })
export class Contact extends BaseEntity {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column()
email: string;
#Column()
html_de: string;
#Column()
html_en: string;
#Column()
name: string;
#Column()
telephone: string;
}
export class ContactsController {
constructor(private contactsService: ContactsService) {}
#Get()
getContacts(
#Query(ValidationPipe) filterDto: GetContactsFilterDto,
): Promise<ContactDto[]> {
return this.contactsService.getContacts(filterDto);
}
#Injectable()
export class ContactsService {
constructor(
#InjectRepository(ContactsRepository)
private contactsRepository: ContactsRepository,
) {}
async getContacts(filterDto: GetContactsFilterDto): Promise<Contact[]> {
return this.contactsRepository.getContacts(filterDto);
}
import { Module } from '#nestjs/common';
import { TypeOrmModule } from '#nestjs/typeorm';
import { ContactsController } from './contacts.controller';
import { ContactsRepository } from './contacts.repository';
import { ContactsService } from './contacts.service';
#Module({
controllers: [ContactsController],
imports: [TypeOrmModule.forFeature([ContactsRepository])],
providers: [ContactsRepository, ContactsService],
exports: [ContactsRepository, ContactsService],
})
export class ContactsModule {}
Somebody know how i can fix this? Regards
ContactsRepository should only be used in the TypeOrmModule.forFeature() and not added to the providers or exports array. When it is added here, the injection token for ContactsRepository no longer points to the proper instance and Nest creates the class, but doesn't have it properly extend Repository as that code is all managed by TypeORM

How to join multiple documents in a Firestore?

I have a Firestore DB with the following structure:
users
[uid]
name: 'User one'
artists
[uid]
style: 'Pop teste'
user_uid: [uid]
in my service I have
constructor(private afu: AngularFireAuth, private afs: AngularFirestore, private storage: AngularFireStorage) {
this.usersCollection = afs.collection<User>('users');
this.users = this.usersCollection.valueChanges();
}
getUsers() {
return this.users = this.usersCollection.snapshotChanges()
.pipe(map(changes => {
return changes.map(action => {
const data = action.payload.doc.data() as User;
return data
});
}));
}
How can join between users and artists ?
Using combineLatest is a great way. Since the user_uid doesn't exist on the user, I added the idField to the user as user_uid. View the code first then read below for an explanation.
import { Component, OnInit } from '#angular/core';
import { AngularFirestore } from '#angular/fire/firestore';
import { Observable, combineLatest } from 'rxjs';
interface User {
name: string;
user_uid: string;
}
interface Artist {
style: string;
user_uid: string;
}
interface Joined {
user_uid: string;
name: string;
style: string;
}
#Component({
selector: 'test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.scss']
})
export class TestComponent implements OnInit {
users$: Observable<User[]>;
artists$: Observable<Artist[]>;
joined$: Observable<Joined[]>;
constructor(private afs: AngularFirestore){}
ngOnInit(){
this.users$ = this.afs.collection<User>('users').valueChanges({idField: 'user_uid'});
this.artists$ = this.afs.collection<Artist>('artists').valueChanges();
this.joined$ = combineLatest(this.users$, this.artists$, (users, artists) => {
const joinedAsMap: Map<string, Joined> = new Map(artists.map(oneArtist => [oneArtist.user_uid, { ...{name: null} , ...oneArtist}]));
users.forEach(one => joinedAsMap.set(one.user_uid , {...{name: one.name}, ...joinedAsMap.get(one.user_uid) } ));
const joined: Joined[] = Array.from(joinedAsMap.values());
return joined;
});
}
}
Make a joined interface
Get both observables
use combine latest
Build a map with uid as key and and artist as value. Set the name to null just so the types will work. Use the spread operator to merge some objects.
Loop through user and add in the user info to the value of each key
Build joined array from values of map
return the value
You can do this different ways but using es6 maps is a nice way to simplify some things. Also, didn't get a chance to test with a real database so you might need to verify. Also, this is all within the component for demonstration. You could do this in the service for sure.

convert returned Observables to custom class array in angular

Hello folks I will keep my question very simpler by showing code
I am using Json placeholder site for the fake rest Api
I have a user class Object
I want to convert returned Observable to the
custom class object array.
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs';
import { Users } from './users.model';
#Injectable({
providedIn: 'root'
})
export class UsersService {
private url = "https://jsonplaceholder.typicode.com";
constructor(private http:HttpClient) {
console.log(this.getUsers());
}
getUsers():Observable<Users[]>{
return this.http.get<Users[]>(`${this.url}/posts`);
}
}
The above is my service
export class Users {
email: string;
id: number;
name: string;
phone: string;
username: string;
}
above is my class I haven't included all properties
In my typescript file I have code like.
constructor(private _usersService:UsersService) {
}
ngOnInit(): void {
this._usersService.getUsers().subscribe(data=>this.users=data);
console.log(this.users);
}
Now the things I want is
how to convert returned observable in my custom class object?
I don't have all the fields so how is it possible to map only those fields which I want?
Hope my question is clear..!!
so this answer takes advantage of map() which is imported from rxjs.
before subscribing we are going to pipe a map() function into the observable stream and then map() each element from that array into a new object that fits our User interface
then we subscribe and the data we get then will be an array that fits our User interface
ngOnInit(): void {
this._usersService.getUsers()
.pipe(map(data => {
return data.map(item => {
const user: User = {
name: item.name,
email: item.email,
}
return user
})
}))
.subscribe(data=>this.users=data);
console.log(this.users);
}
You can do like below, in the User class have a constructor and return User while mapping
import { Component, VERSION, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { map } from 'rxjs/operators';
export class User {
email: string;
id: number;
name: string;
phone: string;
username: string;
constructor( user: User ) {
Object.assign( this, user );
}
}
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
name = 'Angular ' + VERSION.major;
constructor(private http: HttpClient){}
ngOnInit() {
this.http.get<User[]>("https://jsonplaceholder.typicode.com/users")
.pipe(
map( data => {
return data.map( ( user ) => {
return new User( {
email: user['email'],
id: user['id'],
name: user['name'],
phone: user['phone'],
username: user['username'],
} );
} );
} ),
)
.subscribe( (users : User[]) => console.log(users) );
}
}
Working stackblitz

How to push data and detect changes in angular 2 + version?

In previous angular version we had $scope.apply to detect changes , So i below code i have data from detailService that is printed now i am pushing data to object its throwing error object property is undefined , what is correct approach in new angular version to push data to array and bind it to the dom ?
app.component.ts
import { Component, OnInit,Pipe, PipeTransform, EventEmitter, Output } from '#angular/core';
import { DetailService } from '../detail.service';
import { StreamService } from '../stream.service';
import { MatTableDataSource } from '#angular/material';
import {GtConfig} from '#angular-generic-table/core';
import { GenericTableComponent} from '#angular-generic-table/core';
import * as io from 'socket.io-client';
export interface Element {
ticketNum: number;
ticketOpened: number;
eventType: string;
riskIndex: string;
riskValue: number;
severity: string;
lastModifiedDate: number;
assetID: string;
}
#Component({
selector: 'app-detail',
templateUrl: './detail.component.html',
styleUrls: ['./detail.component.css'],
})
export class DetailComponent{
messageArray: any[];
message1:Object = {};
public secondConfigObject: GtConfig<any>;
constructor(private detailService: DetailService) {
this.secondConfigObject = {
settings: this.getBaseSettings(),
fields: this.getBaseFields(),
data: []
};
};
ngOnInit() {
this.detailService.currentMessage1.subscribe(message1 => {
console.log('eventINDetailComp',message1);
this.secondConfigObject.data.push(message1);
});
}
}
app.component.html
<div class="table-responsive">
<generic-table [gtClasses]="'table-hover'" #myCustomTable [gtSettings]="secondConfigObject.settings" [gtFields]="secondConfigObject.fields" [gtData]="secondConfigObject.data"></generic-table>
</div>
You should move the code from the constructor to the start of the ngOnInit() function so the data gets set once the page has been created, not during.
As for data binding, variables on the screen/html will automatically update when they are changed in the code behind

Angular2 - Share component controllers

I have two page components that use the same methods with the exception of using two different type classes. The two components are called Services and Users. Both components use templates that are very similar with the exception of the class property info it displays. It seems to be inefficient to repeat methods on both controllers, is there a way to combine/share controllers.
Services.ts
import { Component } from '#angular/core';
import { CORE_DIRECTIVES } from '#angular/common';
const template = require('./service.component.html');
const style = require('./service.component.css');
interface Service {
id: number;
name: string;
summary: string;
path: string;
};
#Component({
selector: 'admin-services',
directives: [ CORE_DIRECTIVES],
template: template,
styles: [ style ]
})
export class ServiceComponent {
services = Services;
selectedService:Service ;
constructor() {
}
onselect(service:Service){
this.selectedService = service ;
}
onEdit(service:Service){
console.log("Edit: "+service);
}
onDelete(service:Service){
console.log("Delete: "+service);
}
onView(service:Service){
console.log("View: "+service);
}
onAdd(){
this.selectedService = <Service>{};
}
}
User.ts
import { Component } from '#angular/core';
import { CORE_DIRECTIVES } from '#angular/common';
const template = require('./users.component.html');
const style = require('./users.component.css');
interface User {
id: number;
image: string;
name: string;
email: string;
role: string;
};
#Component({
selector: 'admin-users',
directives: [ CORE_DIRECTIVES],
template: template,
styles: [ style ]
})
export class UsersComponent {
users = Users;
selectedUser:User ;
constructor() {
}
onselect(user:User){
this.selectedUser = user ;
}
onEdit(user:User){
console.log("Edit: "+user);
}
onDelete(user:User){
console.log("Delete: "+user);
}
onView(user:User){
console.log("View: "+user);
}
onAdd(){
this.selectedUser = <User>{};
}
}
Yep, this is where Angular's component-driven design and Typescripts's class-driven design really shine:
Having defined a ServicesComponent as you have above, you can simply extend that class and attach different component metadata to it:
#Component({
selector: 'admin-users',
directives: [ CORE_DIRECTIVES],
template: template,
styles: [ style ]
})
export class UsersComponent extends ServicesComponent {
constructor(){
super();
}
//override whatever methods/fields in the parent class you need to (and only those)
}
I believe you can create a service with a single set of methods and pass in an object. Then cast the object to the desired class and use it in the method.

Categories

Resources