ReferenceError: window is not defined Angular Universal - node.js

I'm using Angular 10 and trying to implement SSR in my project.
When I run the npm run serve:ssr I'm getting the below error
ReferenceError: window is not defined
When I googled, they suggested to add domino
So below is my server.ts
....
const scripts = fs.readFileSync('dist/asfc-web/browser/index.html').toString();
const window = domino.createWindow(scripts);
global['window'] = window;
global['document'] = window.document;
....
still getting the same error, Please guide me how to resolve this issue.

It's simple fix,
I've imported the AppServerModule after the global['window'] and it worked
global['window'] = window;
global['document'] = window.document;
import { AppServerModule } from '../../projects/asfc-web/src/main.server';

you can use Renderer2 listen for this.
import { Renderer2 } from '#angular/core';
constructor(private renderer2: Renderer2) {
...
}
this.renderer2.listen('window', 'load', event => {
this.innerWidth = event.currentTarget.innerWidth;
console.log(this.innerWidth);
});

You can create new service
import {Injectable} from '#angular/core';
function _window(): any {
return window;
}
#Injectable({
providedIn: 'root'
})
export class WindowRef {
get nativeWindow(): any {
return _window();
}
}
add in constructor where you want to use:
constructor(
private windowRef: WindowRef
) {
}
and use like this:
this.windowRef.nativeWindow.scrollTo({
top: 0,
behavior: 'smooth'
});
or you can check platform:
constructor(
#Inject(PLATFORM_ID) private platformId: any,
private windowRef: WindowRef
) {
}
if (isPlatformBrowser(this.platformId)) {
this.windowRef.nativeWindow.scrollTo({
top: 0,
behavior: 'smooth'
});
}

Related

NestJS / TypeORM: Custom repository method is not accessible in service

New to NestJS and TypeORM, and the similar questions on SO didn't solve my problem.
I have a custom TypeORM repository in NestJS using it in service, but it fails with error:
TypeError: this.tenantRepository.createTenant is not a function.
tenants.module.ts:
import { TenantRepository } from './tenant.repository';
#Module({
imports: [
TypeOrmModule.forFeature([TenantRepository]),
],
controllers: [TenantsController],
providers: [TenantsService],
})
export class TenantsModule { }
tenant.repository.ts:
// ...
import { TenantEntity } from './entities/tenant.entity';
#EntityRepository(TenantEntity)
export class TenantRepository extends Repository<TenantEntity>{
async createTenant(createTenantDto: CreateTenantDto): Promise<TenantEntity> {
const { name, email } = createTenantDto;
const newTenant = new TenantEntity()
newTenant.name = name;
newTenant.email = email;
await newTenant.save()
return newTenant;
}
}
And here's where the error is triggered (tenants.service.ts)
// ...
import { TenantEntity } from './entities/tenant.entity';
import { TenantRepository } from './tenant.repository';
#Injectable()
export class TenantsService {
constructor(
#InjectRepository(TenantRepository)
private tenantRepository: TenantRepository
) { }
async createTenant(createTenantDto: CreateTenantDto): Promise<TenantEntity> {
return await this.tenantRepository.createTenant(createTenantDto); // <-- ERROR
}
}
I can inject entity in service and use it for simple CRUD, but I want to separate concerns and use the repository pattern.
This is a POST endpoint and the error is only after submission from Swagger.
Also, VS Code autocomplete is suggesting createTenant after typing this.tenantRepository
Where am I going wrong?
EntityRepository decorator was deprecated, and as far as I know, you need to define a custom class that extends Repository and decorate it with #Injectable. Hence, you need to have some changes as follows:
tenant.repository.ts:
import { Injectable } from '#nestjs/common';
import { DataSource, Repository } from 'typeorm';
#Injectable()
export class TenantRepository extends Repository<TenantEntity>{
constructor(private dataSource: DataSource) {
super(TenantEntity, dataSource.createEntityManager());
}
async createTenant(createTenantDto: CreateTenantDto): Promise<TenantEntity> {
const { name, email } = createTenantDto;
const newTenant = this.create({ name, email });
await this.save(newTenant);
return newTenant;
}
}
tenants.module.ts:
import { TenantRepository } from './tenant.repository';
#Module({
imports: [
TypeOrmModule.forFeature([TenantRepository]),
],
controllers: [TenantsController],
providers: [TenantsService, TenantRepository],
})
export class TenantsModule { }
tenants.service.ts:
import { TenantEntity } from './entities/tenant.entity';
import { TenantRepository } from './tenant.repository';
#Injectable()
export class TenantsService {
constructor(
private tenantRepository: TenantRepository
) { }
async createTenant(createTenantDto: CreateTenantDto): Promise<TenantEntity> {
return await this.tenantRepository.createTenant(createTenantDto);
}
}
You also have access to built-in typeorm methods like save, create, find, etc. since the custom repository is derived from Repository class.

How can i asynchronouslycall this service function in another component? Angular 11

I have an async function getIdentByInfo and in the console i get the right output if i log it in this function. As soon as i call it in another component it doesnt work and i only get 'undefined'. I know it has something to do with beeing ssynchrone and Promises but i cant figure out how to solve my issue. I need the Model class filled with attributes coming from the http request in another component to send them to another service
import { EventEmitter, Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { IdentModel } from "../models/identmodel.model";
import { IdentteilComponent } from "../pages/identteil/identteil.component";
#Injectable({
providedIn: 'root',
})
export class InfoWebservice {
url = 'http://localhost:4201';
ident: IdentModel[];
constructor(private http: HttpClient) { }
// promise vom typ IdentModel zurückgeben
getIdentByInfo(id: string, vwk: string) {
this.http.get(this.url).toPromise().then(data => {
for (let i in data){
this.ident.push(data[i])
if ( this.ident[i].identNr == id && this.ident[i].vwk == vwk){
return this.ident[i];
}
}
});
}
}
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { InfoWebservice } from '../../webservices/info.webservice'
import { ImageWebservice } from '../../webservices/image.webservice'
import { IdentModel } from "../../models/identmodel.model";
#Component({
selector: 'app-identteil',
templateUrl: './identteil.component.html',
styleUrls: ['./identteil.component.scss']
})
export class IdentteilComponent implements OnInit {
ident = [];
identNr:string;
vwk:string;
imgFrontLink:string;
imgBackLink:string;
constructor(private router: Router, private service: InfoWebservice, private image: ImageWebservice) { }
getIdentNr() : string {
var split = this.router.url.split("/");
this.identNr = split[2];
return this.identNr;
}
//return type is STRING
getVwk() {
// output von window.location.host = repapp-maw.dbl.de
// var splitHost = window.location.host.split(".");
var splitHost = 'repapp-maw';
var splitV = splitHost.split("-");
this.vwk = splitV[1];
return this.vwk;
}
callInfoService = async () => {
return await this.service.getIdentByInfo(this.getIdentNr(), this.getVwk());
}
ngOnInit() {
console.log(this.callInfoService());
}
}
When you use angular, its always preferred not to use await/Promise. Angular has an in-built RX-JS library which has tonnes of super-awesome functionalities that you can use.
For Example, in your case, you can do something like this:
// Your Service File can make use of 'Behavior Subject'
// Please read more about it here: https://www.learnrxjs.io/learn-rxjs/subjects/behaviorsubject
import { EventEmitter, Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { IdentModel } from "../models/identmodel.model";
import { IdentteilComponent } from "../pages/identteil/identteil.component";
#Injectable({
providedIn: 'root',
})
export class InfoWebservice {
url = 'http://localhost:4201';
ident: IdentModel[];
initialIdentValues: IdentModel = [];
private identSource: BehaviorSubject<IdentModel[]> = new BehaviorSubject<IdentModel[]>(this.initialIdentValues);
public identValuesObs$: Observable<IdentModel[]> = this.identSource.asObservable();
// Create a method to set the values in component-1
setIdentValues(identValues: IdentModel[]) {
this.identSource.next(identValues);
}
// Create a method to return values in component-2 or any component
returnIdentValues() {
return this.identValuesObs$;
}
constructor(private http: HttpClient) { }
// Change your service call to this:
getIdentByInfo(id: string, vwk: string): Observable<any> {
return this.http.get(this.url);
}
}
Now in your component-1 where you want to set the values of this identvalues:
// Component-1
constructor(private infoWebService: InfoWebService){}
// Create a method where you get the values
someMethod() {
// Call the API method here and subscribe and then set the values
this.infoWebService.getIdentInfoById(id, vwk).subscribe((data: any) => {
// Your logic goes here ANDD
if (data) {
for (let i in data){
this.ident.push(data[i])
let localIdentsWithRequiredLogic = [];
if ( this.ident[i].identNr == id && this.ident[i].vwk == vwk){
localIdentsWithRequiredLogic.push(this.ident[i]);
}
// THIS IS IMPORTANT
this.infoWebService.setIdentValues(localIdentsWithRequiredLogic);
}
}
})
}
Then in component-2 or whatever component you want, you can retrieve it using the returnIdentValues method like this:
// In component-2
inSomeMethodWhereYouRequireIdentValues() {
this.infoWebService.returnIdentValues().subscribe(data => {
console.log(data) // this is data that you set in component one
})
}

Angular 7 / Material DataTable not updating after any operation

I'm building an Angular 7 application using #angular/material. When I load the application for the first time, the Datatable renders correctly, but when I call any function, example - delUser, after deleting a user from the database, it's meant to render the table immediately, but it doesn't until I refresh the whole page. I've tried everything, but to no avail.
Here's my code:
import { Component, OnInit, ViewChild, TemplateRef } from '#angular/core';
import { UserService } from 'src/app/services/user.service';
import { MatTableDataSource } from '#angular/material/table';
import { MatSort } from '#angular/material/sort';
import { MatPaginator } from '#angular/material/paginator';
#Component({
selector: 'app-users',
templateUrl: './users.component.html',
styleUrls: ['./users.component.css']
})
export class UsersComponent implements OnInit {
pgtitle:string = "Manage Users";
dataSource:any;
displayedColumns:string[] = ['userName','email','roleId','userType','Actions'];
#ViewChild(MatSort, {static: true}) sort: MatSort;
#ViewChild(MatPaginator) paginator: MatPaginator;
constructor(
private service:UserService
){}
ngOnInit(): void {
this.getAllUsers();
}
applyFilter(filterValue:String){
this.dataSource.filter = filterValue.trim().toLowerCase();
}
getAllUsers(){
this.service.getAllUsers().subscribe( result => {
this.dataSource = new MatTableDataSource(result);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
});
}
delUser(id){
this.service.deleteUser(id).subscribe(result => {
this.getAllUsers();
});
}
Maybe you can try this:
this.service.getAllUsers().subscribe( result => {
this.dataSource = null; //add this
this.dataSource = new MatTableDataSource(result);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
});

ag-grid in jhipster angular 4

i'm trying to use ag-grid in a jhipster project. After adding ag-grid to my project, I imported the module in app.module:
{AgGridModule} from 'ag-grid-angular';
i modified the component in order to use ag-grid:
import { Component, OnInit, OnDestroy } from '#angular/core';
import { ActivatedRoute, Router } from '#angular/router';
import { Subscription } from 'rxjs/Rx';
import { JhiEventManager, JhiParseLinks, JhiAlertService } from 'ng-jhipster';
import { Typapp } from './typapp.model';
import { TypappService } from './typapp.service';
import { ITEMS_PER_PAGE, Principal, ResponseWrapper } from '../../shared';
import {ColDef, ColumnApi, GridApi} from 'ag-grid';
#Component({
selector: 'jhi-typapp',
templateUrl: './typapp.component.html'
})
export class TypappComponent implements OnInit, OnDestroy {
typapps: Typapp[];
typs: Typapp[]
currentAccount: any;
eventSubscriber: Subscription;
/**
* Declarations AG-GRID
*/
// rowdata and column definitions
rowData: Typapp[];
columnDefs: ColDef[];
// gridApi and columnApi
api: GridApi;
columnApi: ColumnApi;
constructor(
private typappService: TypappService,
private jhiAlertService: JhiAlertService,
private eventManager: JhiEventManager,
private principal: Principal
) {
this.columnDefs = this.createColumnDefs();
}
loadAll() {
this.typappService.query().subscribe(
(res: ResponseWrapper) => {
this.typapps = res.json;
},
(res: ResponseWrapper) => this.onError(res.json)
);
}
ngOnInit() {
this.loadAll();
this.principal.identity().then((account) => {
this.currentAccount = account;
});
this.registerChangeInTypapps();
/**
* modif component aggrid
*/
this.typappService.findAll().subscribe(
(rowData) => {
this.rowData = rowData
},
(error) => {
console.log(error);
}
)
}
ngOnDestroy() {
this.eventManager.destroy(this.eventSubscriber);
}
trackId(index: number, item: Typapp) {
return item.id;
}
registerChangeInTypapps() {
this.eventSubscriber = this.eventManager.subscribe('typappListModification', (response) => this.loadAll());
}
private onError(error) {
this.jhiAlertService.error(error.message, null, null);
}
/**
* AG GRID fonctions
*/
// one grid initialisation, grap the APIs and auto resize the columns to fit the available space
onGridReady(params): void {
this.api = params.api;
this.columnApi = params.columnApi;
this.api.sizeColumnsToFit();
}
// create some simple column definitions
private createColumnDefs() {
return [
{field: 'id'},
{field: 'libTyp'},
]
}
}
there is the code of component.html
<h6> without AGRID</h6>
<div *ngFor="let rd of rowData">
<span>{{rd.id}}</span>
<span>{{rd.libTyp}}</span>
</div>
<br/>
<h6> with AGRID</h6>
<ag-grid-angular style="width: 100%; height: 800px;"
class="ag-theme-fresh"
(gridReady)="onGridReady($event)"
[columnDefs]="columnDefs"
[rowData]="rowData">
</ag-grid-angular>
and this is the result:
What i'm doing wrong? why there is no results when i use ag-grid?
Even in the console there is no error.
Thank you very much.
I had the same issue. Did you import ag-theme-fresh.css to vendor.css? This did the trick for me.
\src\main\webapp\content\css\vendor.css:
...
#import '~ag-grid/dist/styles/ag-theme-fresh.css';

Strange behavior with module.exports and async in React

Here's a very strange issue that has me puzzled. After creating a React app with create-react-app, I added these two files:
TestMod.js
const TestMod = {
doSomething() {
}
};
module.exports = TestMod;
Test.js
import React, { Component } from 'react';
import TestMod from './TestMod';
export default class Test extends Component {
render() {
TestMod.doSomething();
return <div>Testing</div>;
}
}
I included the Test component inside App, run npm start, and everything worked fine. Then I changed doSomething to be async, like this
TestMod.js
const TestMod = {
async doSomething() {
}
};
module.exports = TestMod;
Now I get a compilation error:
[1] ./src/Test.js
[1] 26:6-13 "export 'default' (imported as 'TestMod') was not found in './TestMod'
Why? I know how to make it work again:
TestMod.js
export const TestMod = {
async doSomething() {
}
};
Test.js
import React, { Component } from 'react';
import {TestMod} from './TestMod';
export default class Test extends Component {
render() {
TestMod.doSomething();
return <div>Testing</div>;
}
}
But what I'd like to understand is why making a function async causes module.exports to break on the React side. (By the way, it still works fine on the Node.js side).
Thanks,
Alvaro

Resources