Angular 7 / Material DataTable not updating after any operation - node.js

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;
});

Related

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
})
}

ERROR TypeError: this.statutForm.value.poste.subscribe is not a function

i'm sorry there is a lot of questions about this error but mine is strange. The function worked and after some minutes it didn't work anymore. Without the line with "subscribe" the LocalStorage is working good. Thank you for your help, I spent a lot of time of this error .. :'(
import { Component, OnInit } from '#angular/core';
import { StatutService } from '../statut.service';
import { Statut } from '../statut';
import { FormControl, FormGroup } from '#angular/forms';
import { Router } from '#angular/router';
#Component({
selector: 'app-accueil-admin',
templateUrl: './accueil-admin.component.html',
styleUrls: ['./accueil-admin.component.scss']
})
export class AccueilAdminComponent implements OnInit {
statutForm!: FormGroup;
//isSubmitted = false;
constructor(private statutService: StatutService) { }
ngOnInit(): void {
this.statutForm = new FormGroup({
poste : new FormControl(''),
etat : new FormControl(''),
client : new FormControl(''),
});
}
recherche() {
//this.isSubmitted = true;
console.log('Statut saisi', this.statutForm.value);
let poste = this.statutForm.value.poste;
let etat = this.statutForm.value.etat;
let client = this.statutForm.value.client;
this.statutForm.value.poste.subscribe((data: Object) => {
// Tableau des clés et des valeurs de l'objet
let keys = Object.keys(data);
let values = Object.values(data);
for (let i = 0; i < keys.length; i++) {
if (keys[i] == 'poste') { poste = values[i]; }
if (keys[i] == 'etat') { etat = values[i]; }
if (keys[i] == 'client') { client = values[i]; }
}
let leStatut = new Statut (poste, etat, client);
this.statutService.addStatut(leStatut);
[enter image description here][1]});
}
this.statutForm.value.poste is not an observable, it's plain value of the field. If you want observable following the changes, you can use
this.statutForm.get('poste').valueChanges.subscribe(/* ... */)
or
this.statutForm.controls.poste.valueChanges.subscribe(/* ... */)

Angular 7/8 - How to get url parameters in app component

I have Single sign on in place but for testing I want to read the values from the url localhost:4200/?id=test&name=testing&email=testing#test.com and pass them to an API in app component.
there will be a flag on which basis I will reading from url instead of using single sign on function
if (url_enabled == true) {
getParamsFromUrl()
} else {
singleSignOn()
}
I tried ActivatedRoute but it doesn't seem to be working.
I have tried queryParams, params, url, queryParamsMap but none of these seems to be working. all I get is empty value.
inside app component
app.component.ts
getParamsFromUrl() {
this._router.events.subscribe((e) => {
if (e instanceof NavigationEnd) {
console.log(e.url)
}
})
}
this.route.queryParams.subscribe(params => {
console.log(params);
})
app.component.html
<router-outlet></router-outlet>
app-routing.module.ts
const routes: Routes = [
{path:'*/:id', component: AppComponent},
];
I have tried whatever I could found on stackoverflow or other blogs. Can somebody point out what am I missing here?
For this route:
You can try this way:
const routes: Routes = [
{path:'*/:id', component: AppComponent},
];
In AppComponent .ts file:
constructor(
private activatedRoute: ActivatedRoute,
) { }
ngOnInit() {
this.activatedRoute.params.subscribe(params => {
const id = params['id'];
console.log('Url Id: ',id);
}
OR
ngOnInit() {
this.activatedRoute.queryParams.subscribe(params => {
const id = +params.id;
if (id && id > 0) {
console.log(id);
}
});
}
first of all there is an url with queryParams like yours :
localhost:4200/?id=test&name=testing&email=testing#test.com
in this way tou get to the queryparams with ActivatedRoute object lik :
this.name = this.activatedRoute.snapshot.queryParamMap.get('name'); // this.name = 'testing'
Or :
this.activatedRoute.queryParams.subscribe(params => {
this.name= params['name'];
});
and the other way is
localhost:4200/test/testing/testing#test.com
you use for sync retrieval (one time) :
this.name = this.activatedRoute.snapshot.ParamMap.get('name');
Angular comes us with the ActivatedRoute object. We can access the URL parameter value in same way its done above with little difference. Data in this type can be accessed with two different ways. One is through route.snapshot.paramMap and the other is through route.paramMap.subscribe. The main difference between the two is that the subscription will continue to update as the parameter changes for that specific route.
ngOnInit() {
this.route.paramMap.subscribe(params => {
this.userType = params.get("userType")
})
}
You need to create a new component and update the routing configuration as follows:
First, create a new component: MainComponent:
import { Component } from '#angular/core';
#Component({
selector: 'main',
template: `<router-outlet></router-outlet>`,
})
export class MainComponent {
constructor() { }
}
Then, update your AppModule:
import { AppComponent } from './app.component';
import { MainComponent } from './main.component';
#NgModule({
imports: [
BrowserModule,
FormsModule,
RouterModule.forRoot([
{path: '', component: AppComponent}
])
],
declarations: [ MainComponent, AppComponent ],
bootstrap: [ MainComponent ]
})
export class AppModule { }
Finally, you'll need to update your index.html file(Make sure to load the brand new component instead of the AppComponent):
<main>loading</main>
Now you'll be able to read your parameters as requested in your AppComponent:
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute, Params } from '#angular/router';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
params: Params;
constructor(private route: ActivatedRoute){}
ngOnInit() {
this.route.queryParams.subscribe((params: Params) => {
this.params = params;
console.log('App params', params);
const id = params['id'];
console.log('id', id);
});
}
}
See a working example here: https://read-params-app-component.stackblitz.io/?id=test&name=testing&email=testing#test.com.
And find the source code here.
I hope it helps!
You can try like this
constructor(
private activatedRoute: ActivatedRoute
)
ngOnInit() {
this.activatedRoute.paramMap
.pipe(
tap(console.log(this.activatedRoute.snapshot.paramMap.get(
"id"
)))
).subscribe()
}
Let me know if you need any help
Using Transition from #uirouter/core makes it easy to get params from url.
import {Transition} from '#uirouter/core';
#Component()
export class MyComponent {
public myParam = this.transition.params().myParam;
public constructor(public transition: Transition) {}
}
I used jquery inside angular 8 and got the href using jquery $ variable after declaring it in app component.
import { query } from '#angular/animations';
declare var $: any;

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';

angular 2 testing kendo-autocomplete

I'm trying to test a component that has kendo-autocomplete control. When the test is ruining the popup with the result doesn't show at all.
What do I need to do?
Below you have the code if you need any other information please let me know.
Component
import { Component, OnInit, Input, Output, Inject } from '#angular/core';
import { IFieldLookUpService } from 'app/services/ifield-look-up.service';
import { FieldLookUpValueResults } from 'app/models/field-look-up-result';
#Component({
selector: 'field-lookup',
templateUrl: './field-lookup.component.html',
styleUrls: ['./field-lookup.component.css']
})
export class FieldLookupComponent implements OnInit {
#Input() fieldId: number;
#Input() fieldName: string;
#Output() selectedValue: string;
private source: FieldLookUpValueResults;
public fieldLookUpValues: FieldLookUpValueResults;
constructor(#Inject('IFieldLookUpService') private fieldLookUpService: IFieldLookUpService) { }
ngOnInit() {
this.loadData();
}
handleFilter(value) {
this.fieldLookUpValues.results = this.source.results.filter((s) => s.text.toLowerCase().indexOf(value.toLowerCase()) !== -1);
}
private loadData() {
this.fieldLookUpService.getLookUpValues(this.fieldId, this.fieldName)
.subscribe(data => { this.source = data;
this.fieldLookUpValues = new FieldLookUpValueResults(this.source.header, null);
})
}
}
Component.html
<div *ngIf="fieldLookUpValues">
<kendo-autocomplete [data]="fieldLookUpValues.results" [valueField]="'text'" [suggest]="true" [value]="selectedValue" [filterable]="true" (filterChange)="handleFilter($event)">
<ng-template kendoAutoCompleteHeaderTemplate>
<strong>{{fieldLookUpValues.header}}</strong>
</ng-template>
</kendo-autocomplete>
</div>
spec
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { DebugElement } from '#angular/core';
import { By } from '#angular/platform-browser';
import { FieldLookupComponent } from './field-lookup.component';
import { FieldLookUpValueResults, FieldLookUpValue } from 'app/models/field-look-up-result';
import { IFieldLookUpService } from 'app/services/ifield-look-up.service';
import { Observable } from 'rxjs/Observable';
import { DropDownsModule } from '#progress/kendo-angular-dropdowns';
fdescribe('FieldLookupComponent', () => {
let component: FieldLookupComponent;
let fixture: ComponentFixture<FieldLookupComponent>;
let debugEl: DebugElement;
let mockFieldLookUpService;
let inputElement;
beforeEach(async(() => {
mockFieldLookUpService = jasmine.createSpyObj('mockFieldLookUpService', ['getLookUpValues']);
let mockData = new FieldLookUpValueResults('LookUp Values Result Header',
[
new FieldLookUpValue('LookUp Value 1', '1'),
new FieldLookUpValue('LookUp Value 2', '2'),
]);
mockFieldLookUpService.getLookUpValues.and.returnValue(Observable.of(mockData));
TestBed.configureTestingModule({
declarations: [ FieldLookupComponent ],
imports: [
DropDownsModule
],
providers: [
{ provide: 'IFieldLookUpService', useFactory: () => mockFieldLookUpService },
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(FieldLookupComponent);
component = fixture.componentInstance;
debugEl = fixture.debugElement;
fixture.detectChanges();
inputElement = debugEl.query(By.css('input')).nativeElement;
console.log(component);
});
fit('should be created', () => {
expect(component).toBeTruthy();
});
fit('should have the autocomplete input', () => {
expect(inputElement).toBeTruthy();
});
fdescribe('when character L is set in autocompelte box', () => {
let list: DebugElement;
let listItems: DebugElement[];
beforeEach(() => {
inputElement.value = 'L';
fixture.detectChanges();
list = debugEl.query(By.css('ul')).nativeElement;
listItems = list.queryAll(By.css('li'));
})
fit('should have the kend pop-up shown', () => {
expect(list).toBeTruthy();
});
});
});
I set the value 'L' to the autocomplete input and then I should see the popup but they are null (the list and ListItems)
inputElement.value = 'L';
fixture.detectChanges();
list = debugEl.query(By.css('ul')).nativeElement;
listItems = list.queryAll(By.css('li'));
The Popup component used in the AutoComplete (applicable to other Kendo components with Popup) is appended at the root component by default. In other words, the Popup is not part of the component tree.
For those interested in why this is so, read this Github issue
With those details in mind, you will need to use the AutoComplete instance and retrieve the Popup element from its popupRef property.
{{ autocomplete?.popupRef?.popupElement.nodeName }}
Here is a plunker that demonstrates this approach:
http://plnkr.co/edit/bQTmfBUT7r5z6wjt5MtL?p=preview
Please note that you will need to wait a tick in the tests in order to get the popupRef correctly.
P.S. IMHO, testing the rendered UL list is unneeded. The vendor providing the AutoComplete component has already tested the output items based on the passed [data] value. Considering this fact, I would just test the autocomplete.data property, which should be sufficient.
You can always add functional tests on top of that to ensure that the application you are building is working as a whole.

Resources