I am a beginner in Angular and Node JS. I am trying a simple navigation bar change based on ngIf condition. However, it doesn't seem to work.
I have already tried it using static member variables.
Also, tried creating a method which changes the value of isUserAuthenticated in navbar.component and called the methods in homepage.component as well as dashboard.component.
I have also done console.log() and checked the value of isUserAuthenticated variable. It is being updated on both the homepage.component as well as dashboard.component. However, the NavBar always remains the same.
I have changed the value directly in navbar.component and then it works. So, I am wandering why it is not working if I change the value from other components.
navbar.component.html
<div *ngIf="!isUserAuthenticated">
<li class="nav-item">
<a class="nav-link" href="/"> EX FALSE </a>
</li>
</div>
<div *ngIf="isUserAuthenticated">
<li class="nav-item">
<a class="nav-link" href="/"> EX TRUE </a>
</li>
</div>
navbar.component.ts
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.css']
})
export class NavbarComponent implements OnInit {
isUserAuthenticated = true;
constructor() { }
ngOnInit() { }
public authenticate() {
this.isUserAuthenticated = false;
return this.isUserAuthenticated;
}
public deauthenticate() {
this.isUserAuthenticated = true;
return this.isUserAuthenticated;
}
}
homepage.component.ts
import { Component, OnInit } from '#angular/core';
import { NavbarComponent } from '../navbar/navbar.component';
#Component({
selector: 'app-homepage',
templateUrl: './homepage.component.html',
styleUrls: ['./homepage.component.css']
})
export class HomepageComponent implements OnInit {
constructor( ) {
}
ngOnInit() {
console.log("here");
this.deauthenticate();
}
public deauthenticate()
{
const comp2 = new NavbarComponent();
comp2.deauthenticate();
console.log(comp2.deauthenticate());
}
}
dashboard.component.ts
import { Component, OnInit } from '#angular/core';
import { NavbarComponent } from '../navbar/navbar.component';
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit {
constructor( ) {
}
ngOnInit() {
this.authenticate();
}
public authenticate()
{
const comp2 = new NavbarComponent();
comp2.authenticate();
console.log(comp2.authenticate());
}
}
I want that dashboard component shows "EX TRUE" in NavBar and homepage component shows "EX FALSE" in NavBar.
As mentioned in comment you need to create service for authentication check this for full example
#Injectable()
export class AuthenticationService {
authenticated$: BehaviorSubject<boolean> = new BehaviorSubject(false);
public authenticate() {
this.authenticated$.next(true);
}
public deauthenticate() {
this.authenticated$.next(false);
}
}
you inject it this way to be able to use it in template
import { Component } from '#angular/core';
import { AuthenticationService } from '../authentication/authentication.service';
#Component({
selector: 'my-navbar',
templateUrl: './navbar.component.html',
styleUrls: [ './navbar.component.css' ]
})
export class NavbarComponent {
constructor(
public authenticationService: AuthenticationService,
) {
}
}
and then in template you can do this
Authenticated {{ authenticationService.authenticated$ | async }}
<div *ngIf="(authenticationService.authenticated$ | async) === true">
<li class="nav-item">
<a class="nav-link" href="/">EX TRUE</a>
</li>
</div>
<div *ngIf="(authenticationService.authenticated$ | async) === false">
<li class="nav-item">
<a class="nav-link" href="/">EX FALSE</a>
</li>
</div>
<button (click)="authenticationService.authenticate()">Authenticate</button>
<button (click)="authenticationService.deauthenticate()">Deauthenticate</button>
Although i would suggest using ngSwitch in this case like this:
<div>
<li class="nav-item" [ngSwitch]="authenticationService.authenticated$ | async">
<a class="nav-link" href="/" *ngSwitchCase="true">EX TRUE</a>
<a class="nav-link" href="/" *ngSwitchDefault>EX FALSE</a>
</li>
</div>
Also if you want separate state for some parts of your site you can do it like this:
#Component({
selector: 'my-homepage',
templateUrl: './homepage.component.html',
styleUrls: [ './homepage.component.css' ],
// this way you have a separate instance of AuthenticationService here anything that will use this service and is rendered under this component will use a localized version of this service
providers: [AuthenticationService],
})
export class HomepageComponent {
constructor(
public authenticationService: AuthenticationService,
) {
}
}
That is not how things are designed to work. For this scenario, you need to create a Service such as AuthService which will be shared across both component.
AuthEventSvc
export class AuthEventSvc{
private authEvent = new BehaviorSubject<boolean>(true);
constructor(){}
emitAuthStatus(state: boolean){
this.authEvent.next(state);
}
authListener(){
return this.authEvent.asObservable();
}
}
and then emit from HomeComponent
export class HomepageComponent implements OnInit {
constructor(private authEvent: AuthEventSvc ) {
}
ngOnInit() {
this.authEvent.emitAuthStatus(false);
}
}
and subscribe it in NavBarComponent
export class NavbarComponent implements OnInit {
isUserAuthenticated = true;
authSubscription : Subscription;
constructor(private authEvent: AuthEventSvc) { }
ngOnInit() {
this.authSubscription = this.authEvent.authListener().subscribe(state => {
this.isUserAuthenticated = state;
})
}
ngOnDestroy(){
this.authSubscription.unsubscribe(); // make sure to unsubscribe
}
}
You should also read about how change detection works and how NgZone is used in Angular to get more clarity as these topics require a long article for explanation. I am just giving you some breadcrumbs to help you understand better :)
Related
Previously, TypeORM repository could be extended and injected directly into services, e.g.:
import { User } from './entities/user.entity';
import { EntityRepository, Repository } from 'typeorm';
#EntityRepository(User)
export class UsersRepo extends Repository<User> {
// my custom repo methods
}
import { Injectable } from '#nestjs/common'
import { UsersRepo } from './users.repo';
#Injectable()
export class UsersService {
constructor(private readonly usersRepo: UsersRepo) {}
}
But since version 3.0.0 TypeORM does not support repository extending via inheritance.
How to achieve such behavior in NestJS 9 (which depends on TypeORM 3.+)? The only solution I came up with is to add custom methods to the service layer. But I would like to keep all ORM-related methods (query, aggregations, etc.) in the repository layer.
Let me tell you straight away: I have no idea whether this is a recommended solution, I don't know if the authors of TypeORM actually considered such approach at all. But what I just did a minute ago is this:
#Injectable()
export class UserRepository extends Repository<UserEntity> {
constructor(
#InjectRepository(UserEntity)
repository: Repository<UserEntity>
) {
super(repository.target, repository.manager, repository.queryRunner);
}
}
And the best part: it worked :D
I use:
"#nestjs/typeorm": "^9.0.0" just so you know.
I will keep checking if it doesn't break anything, but for now, seems like a good workaround.
hope helpful for you.
In my UserServices
constructor(
#InjectRepository(UserEntity)
private readonly repository: BaseRepository<UserEntity>,
) {}
UserModule
#Module({
imports: [TypeOrmModule.forFeature([UserEntity])],
exports: [UserService],
providers: [UserService],
})
export class UserModule {}
*note: BaseRepository from typeorm-transactional-cls-hooked
This is solved here (similar to the other answers here, but more complete):
How to do custom repository using TypeORM (MongoDB) in NestJS?
Not sure why they deprecated #EntityRepository because this is more complicated, but it works
Hope helpful for you:
import { DataSource, Repository } from 'typeorm';
import { EntityTarget } from 'typeorm/common/EntityTarget';
export class GenericRepository<T> extends Repository<T> {
constructor(target: EntityTarget<T>, dataSource: DataSource) {
super(target, dataSource.createEntityManager());
}
async someCommonMethod() {
return {};
}
}
import { DataSource } from 'typeorm';
import { User } from '../../entities/User';
import { Injectable } from '#nestjs/common';
import { GenericRepository } from '../common/generic.repository';
#Injectable()
export class UserRepository extends GenericRepository<User> {
constructor(dataSource: DataSource) {
super(User, dataSource);
}
}
import { Injectable } from '#nestjs/common';
import { User } from '../../entities/User';
import { InjectRepository } from '#nestjs/typeorm';
import { UsersRepository } from './users.repository';
#Injectable()
export class UsersService {
constructor(
#InjectRepository(User)
private readonly usersRepository: UsersRepository,
) {}
}
I'm trying to implement a piral angular component using templateUrl.
I'm able to make it work with "template", but when I change to templateUrl it doesn't work.
All the documentation and examples provided by piral uses template.
This is my component with template:
import { Component, Inject } from '#angular/core';
#Component({
template: `
<div class="tile">
<h3>Angular: {{ counter }}</h3>
<p>
{{ props.rows }} rows and {{ props.columns }} columns
<extension-component name="smiley"></extension-component>
</p>
<button (click)="increment()">Increment</button>
<button (click)="decrement()">Decrement</button>
</div>
`,
})
export class TileComponent {
public counter = 0;
constructor(#Inject('Props') public props: any) {}
increment() {
this.counter += 1;
}
decrement() {
this.counter -= 1;
}
}
This is my component with templateUrl:
import { Component, OnInit } from '#angular/core';
#Component({
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class HelloWorldComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}
I've tried adding selector to 'extension-component' but it doesn't work, I receive "Error: The selector "extension-component" did not match any elements"
Do you know if this is supported on Piral?
Can anyone point me to a working example?
I have following JSON response from my NestJS Controller:
{
"data": [{ ... users ... }]
}
To achieve this "envelop" thing, I use the interceptor:
import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
} from '#nestjs/common'
import { Observable } from 'rxjs'
import { map } from 'rxjs/operators'
import { plainToClass } from 'class-transformer'
import { ResponseObjectInterface } from './response-object.interface'
interface ClassType<T> {
new (): T
}
#Injectable()
export class TransformInterceptor<T>
implements NestInterceptor<Partial<T>, ResponseObjectInterface<T> | T> {
constructor(
private readonly classType: ClassType<T>,
private readonly envelope = true
) {}
intercept(
context: ExecutionContext,
next: CallHandler
): Observable<ResponseObjectInterface<T> | T> {
return next
.handle()
.pipe(
map(data =>
this.envelope
? { data: plainToClass(this.classType, data) }
: plainToClass(this.classType, data)
)
)
}
}
It works as expected.
Now I have to change it and add another root property on the response. This:
{
"data": { ... user ... },
"_signed": "jwt" --> String or NULL
}
I have other objects (products, subscriptions...etc). All of them have the same JSON signature. But they will have NULL in the _signed. It will be empty. Only user is signed.
I thought to have some logic in the the interceptor that will add the property, but I am not sure how to do it. What would be the best way of achieving this functionality?
I managed to resolve my issue without using Interceptor whatsoever.
I used concept of two DTO objects. One is generic, and another one is plain one.
To make story short:
import { IsNumber, IsString } from 'class-validator';
import { Exclude, Expose } from 'class-transformer';
import { ApiProperty } from '#nestjs/swagger';
#Exclude()
export class GenericResponse {
constructor(data) {
this.data = data
}
#Expose()
#IsNumber()
#ApiProperty()
data: any
public getData() {
return this.data
}
#Expose()
#IsString()
#ApiProperty()
private _sign: string;
public setSignedPayload(signedPayload: string) {
this._sign = signedPayload
}
public getSignedPayload() {
return this._sign
}
}
And when I land in userService, I set the Data, also I set the jwt.
If I end somewhere else, I can choose whether to set the jwt or not.
How to know property of table dtOptions?
I do not understand what would be happening or what is missing, If I get to list and draw the table and IF it loads the data the only drawback is that I get unknown property as shown in the capture
at app.module.ts
import { DataTablesModule } from 'angular-datatables';
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
HttpClientModule,
DataTablesModule
],
In my user.component.ts
export class UserComponent implements OnInit {dtOptions: DataTables.Settings = {}; ....}
ngOnInit(): void {
this.getUsers();
this.dtOptions = {
pagingType:'full_numbers',
pageLength:10,
processing:true,
language:{
url:'//cdn.datatables.net/plug-ins/1.10.21/i18n/Spanish.json'
}
}
}
But in my HTML component it marks me as unknown property
Try this.
import { Subject } from 'rxjs';
export class AngularWayComponent implements OnDestroy, OnInit {
dtOptions: DataTables.Settings = {};
dtTrigger: Subject = new Subject();
constructor(private http: Http) { }
import { Component, OnInit, OnDestroy, ViewChild, AfterViewInit, ChangeDetectorRef } from "#angular/core";
import { UIService } from "./shared/ui.service";
import { Subscription } from "rxjs";
import { RadSideDrawerComponent } from "nativescript-ui-sidedrawer/angular";
import { RadSideDrawer } from "nativescript-ui-sidedrawer";
//These are my imports
#Component({
selector: "ns-app",
templateUrl: "./app.component.html"
})
export class AppComponent implements OnInit, OnDestroy, AfterViewInit {
#ViewChild(RadSideDrawerComponent, { static: false }) drawerComponent: RadSideDrawerComponent;
enteredChallenge: string[] = [];
private drawerSub = Subscription; //I have put subscription here
private drawer: RadSideDrawer;
constructor (private uiService: UIService, private changeDetectionRef: ChangeDetectorRef) {}
onChallengeInput(enterText: string){
this.enteredChallenge.push(enterText);
}
ngOnInit(){
this.drawerSub = this.uiService.drawerState.subscribe(
() => {
if(this.drawer){
this.drawerComponent.sideDrawer.toggleDrawerState();
}
}
);
}
ngAfterViewInit(){
this.drawer = this.drawerComponent.sideDrawer;
this.changeDetectionRef.detectChanges();
}
ngOnDestroy(){
if(this.drawerSub){
this.drawerSub.unsubscribe();
}
}
}
I have 2 errors
1 -> Property 'unsubscribe' does not exist on type 'typeof Subscription'.
2 -> Type 'Subscription' is missing the following properties from type 'typeof Subscription': prototype, EMPTY
I have included Subscription and the stuff I need but I don't understand why I still get this error. Can someone help me out?
I also made this simple mistake and couldn't spot the typo.
The line:
private drawerSub = Subscription;
Should be:
private drawerSub: Subscription;