i,ve been pulling hair with what I tought was going to be a simple code. I admit that i am quite new to typescript and learning as I go but more familiar with javascript.
I am basically creating a SPA (Single Page Application) using AG-GRID as my maine component. I have a service which pulls data from a REST connection (currently using JSON server to mimick that) and will share that data across multiple components. AG-GRID seems to be the only component refusing to work correctly at the moment. I am getting the error below.
Ive been scavaging the internet for solution for a few weeks now but cant find an exmaple that matches my situation. Would anyone here know what to do with the error below?
Console Error:
error TS2345: Argument of type '(data: Incident_Model) => Incident_Model' is not assignable to parameter of type '(value: Incident_Model[]) => void'.
Types of parameters 'data' and 'value' are incompatible.
Type 'Incident_Model[]' is not assignable to type 'Incident_Model'.
Property 'id' is missing in type 'Incident_Model[]'.
Angular interface:
export class Incident_Model {
id: number;
Incident: string;
status: string;
}
Angular service:
import { Injectable } from '#angular/core';
import { environment } from '../../environments/environment';
import { HttpClient } from "#angular/common/http";
import { Observable } from 'rxjs/Observable';
import { Incident_Model } from './incident_model';
const BackEnd_URL = environment.BackEnd_URL;
#Injectable()
export class BackEndService {
constructor(private http: HttpClient ) { }
getAllIncidents(): Observable<Incident_Model[]> {
return this.http.get<Incident_Model[]>(BackEnd_URL + '/Incidents');
}
}
Angular Component:
ngOnInit() {this.backendservice.getAllIncidents().subscribe( data => this.gridOptions.api.setRowData = data )}
Updated with code in comment below - 11h37 - 2018-02-07:
Here is the full component code just in case someone can spot something im missing:
import { Component, OnInit } from '#angular/core';
import { GridOptions } from "ag-grid";
import { BackEndService } from '../../Shared/back-end.service';
import { Incident_Model } from '../../Shared/incident_model';
#Component({
selector: 'app-archive',
templateUrl: './archive.component.html',
styleUrls: ['./archive.component.css']
})
export class ArchiveComponent implements OnInit {
private gridOptions: GridOptions;
constructor(private backendservice: BackEndService) {
var gridSize = 8;
var rowHeight = gridSize * 6;
var headerHeight = gridSize * 7;
this.gridOptions = <GridOptions>{
enableFilter: true,
enableColResize: true,
enableSorting: true,
pagination: true,
paginationPageSize:25,
animateRows: true,
headerHeight: headerHeight,
rowHeight:rowHeight
};
this.gridOptions.columnDefs = [
{
headerName: "Headname here",
children:[
{
headerName: "id",
field: "id",
width: 165,
filterParams: { applyButton: true, clearButton:true }
},
{
headerName: "Incident",
field: "Incident",
width: 450,
filterParams: { applyButton: true, clearButton:true }
},
{
headerName: "status",
field: "status",
width: 110,
filterParams: { applyButton: true, clearButton:true }
}
];
}
ngOnInit() {this.backendservice.getAllIncidents().subscribe(data => this.gridOptions.api.setRowData(data)) }
}
For one, data for should be passed as a parameter instead of an assignement:
this.backendservice.getAllIncidents().subscribe(data => this.gridOptions.api.setRowData(data));
Related
I created a server-side rendered Vue.js blog using Nuxt.js with Typescript and Ghost but I'm having some issues to update html metatag using data from asyncData().
From Nuxt.js documentation I know that asyncData() is called every time before loading page components and merges with component data.
I'm getting this error:
Property 'title' does not exist on type '{ asyncData({ app, params }: Context): Promise<{ title: string | undefined; excerpt: string | undefined; feature_image: Nullable | undefined; html: Nullable | undefined; }>; head(): any; }'.
This is my code:
<script lang="ts">
import { Context } from '#nuxt/types'
import { PostOrPage } from 'tryghost__content-api'
export default {
async asyncData ({ app, params }: Context) {
const post: PostOrPage = await app.$ghost.posts.read(
{
slug: params.slug
},
{ include: 'tags' }
)
return {
title: post.title,
excerpt: post.excerpt,
feature_image: post.feature_image,
html: post.html
}
},
head () {
return {
title: this.title,
meta: [
{
hid: 'description',
name: 'description',
content: this.excerpt
}
]
}
}
}
</script>
I already tried some solutions like using data() to set a default value for each item but nothing. Do you have any suggestion?
Without a typescript plugin like nuxt-property-decorator you won't have Typescript support for nuxt (either way, type checking and autocomplete still won't work).
That's why asyncData & fetch should be in Component options.
#Component({
asyncData (ctx) {
...
}
})
export default class YourClass extends Vue {
...
}
instead of
#Component
export default class YourClass extends Vue {
asyncData (ctx) {
...
}
}
If you still want to use asyncData() inside of your component class instead of setting the option, see this working example using the npm module nuxt-property-decorator.
Here is the working code after implementing the suggestion from #nonNumericalFloat :
import { Component, Vue } from 'nuxt-property-decorator'
import { Context } from '#nuxt/types'
import { PostOrPage } from 'tryghost__content-api'
import Title from '~/components/Title.vue'
#Component({
components: {
Title
}
})
export default class Page extends Vue {
post!: PostOrPage
async asyncData ({ app, params }: Context) {
const post: PostOrPage = await app.$ghost.posts.read(
{
slug: params.slug
},
{ include: 'tags' }
)
return {
post
}
}
head () {
return {
title: this.post.title,
meta: [
{
hid: 'description',
name: 'description',
content: this.post.excerpt
}
]
}
}
}
I have created a global snackBarService in my angular application. I want to customise the panelClass based on the type of message (error, success, warning etc.). The approach I took is to have a global config in the constructor, which helps to define global styles/configurations for the snack bar and will add custom classes to change the background colours based on the message type.
SnackBarService.ts
import { Injectable, NgZone } from "#angular/core";
import { MatSnackBar, MatSnackBarConfig } from "#angular/material";
#Injectable({
providedIn: "root",
})
export class SnackbarService {
private config: MatSnackBarConfig;
constructor(private snackbar: MatSnackBar, private zone: NgZone) {
this.config = new MatSnackBarConfig();
this.config.panelClass = ["snackbar-container"];
this.config.verticalPosition = "top";
this.config.horizontalPosition = "right";
this.config.duration = 4000;
}
error(message: string) {
this.config.panelClass = ["snackbar-container", "error"];
this.show(message);
}
success(message: string) {
this.config.panelClass = ["snackbar-container", "success"];
this.show(message);
}
warning(message: string) {
this.config.panelClass = ["snackbar-container", "warning"];
this.show(message);
}
private show(message: string, config?: MatSnackBarConfig) {
config = config || this.config;
this.zone.run(() => {
this.snackbar.open(message, "x", config);
});
}
}
app.scss
.snackbar-container {
margin-top: 70px !important;
color: beige;
&.error {
background-color: #c62828 !important;
}
&.success {
background-color: #2e7d32 !important;
}
&.warning {
background-color: #ff8f00 !important;
}
}
And from the component I will be using the service like this
this.snackbarService.success("This message is from snackbar!!!");
The above code works perfectly.
But,
Since the panelClass does not have a .push method, I can't add dynamic classes, and because of this, I need to duplicate the global class every time like this this.config.panelClass = ["snackbar-container", "error"];
error(message: string) {
this.config.panelClass.push("error"); // this throws error in typescript
this.show(message);
}
Is there any better way to solve this problem?
Angular Material actually provides you a native way for setting a default config, so you don't need to instantiate the MatSnackBarConfig and then set its values. In the module you import the MatSnackBarModule (App/Shared/Material module), add the following:
import { MatSnackBarModule, MatSnackBarConfig, MAT_SNACK_BAR_DEFAULT_OPTIONS } from '#angular/material/snack-bar';
const matSnackbarDefaultConfig: MatSnackBarConfig = {
verticalPosition: 'top',
horizontalPosition: 'right',
duration: 4000,
};
#NgModule({
// ...
providers: [
{
provide: MAT_SNACK_BAR_DEFAULT_OPTIONS,
useValue: matSnackbarDefaultConfig,
},
],
})
export class MaterialModule { }
Then, you can use your service like this (I added a bit more of typing to it, feel free to remove them if you dont' like it and don't use strictNullChecks):
import { Injectable, NgZone } from '#angular/core';
import { MatSnackBar, MatSnackBarConfig } from '#angular/material/snack-bar';
// I actually recommend that you put this in a utils/helpers folder so you can use reuse it whenever needed
export const coerceToArray = <T>(value: T | T[]): T[] => (
Array.isArray(value)
? value
: [value]
);
#Injectable({
providedIn: 'root',
})
export class SnackbarService {
constructor(private snackbar: MatSnackBar, private zone: NgZone) { }
error(message: string): void {
this.show(message, { panelClass: ['snackbar-container', 'error'] });
}
success(message: string): void {
this.show(message, { panelClass: ['snackbar-container', 'success'] });
}
warning(message: string): void {
this.show(message, { panelClass: ['snackbar-container', 'warning'] });
}
private show(message: string, customConfig: MatSnackBarConfig = {}): void {
const customClasses = coerceToArray(customConfig.panelClass)
.filter((v) => typeof v === 'string') as string[];
this.zone.run(() => {
this.snackbar.open(
message,
'x',
{ ...customConfig, panelClass: ['snackbar-container', ...customClasses] },
);
});
}
}
Also, since your public methods don't accept other configs to passes (eg. duration), you can reduce your service to this:
import { Injectable, NgZone } from '#angular/core';
import { MatSnackBar } from '#angular/material/snack-bar';
// Just add the new required types here and TypeScript will require the public consumer to pass a valid type
export type SnackBarType = 'error' | 'success' | 'warning';
#Injectable({
providedIn: 'root',
})
export class SnackbarService {
constructor(private snackbar: MatSnackBar, private zone: NgZone) { }
show(message: string, type: SnackBarType): void {
this.zone.run(() => {
this.snackbar.open(
message,
'x',
{ panelClass: ['snackbar-container', type] },
);
});
}
}
You could do this:
(this.config.panelClass as string[]).push('error');
but you will be adding classes without removing the ones that are there already. You would still need to reset the array with the initial class every time:
this.config.panelClass = ['snackbar-container']
I am using Angular 8
where I am facing error - -> ERROR in customer component **Cannot find module 'async_hooks'.**
ERROR in src/app/customer/customer.component.ts:7:27 - error TS2307: Cannot find module 'async_hooks'.
7 import { currentId } from 'async_hooks';
I tried to search on google about this error, But suggestions show the error is more related to Node
Well I tried to import { currentId } from 'async_hooks'; in my module but still showing same error
Just wanted to inform the I am using Angular material table
https://material.angular.io/components/table/overview
I am sharing my customer.component.ts have a look on it
import { Component, OnInit, ViewChild } from '#angular/core';
import { CustomerService } from '../_service/customer/customer.service';
import {MatTableDataSource} from '#angular/material/table';
import {MatPaginator} from '#angular/material/paginator';
import { MatSort } from '#angular/material';
import { trigger, state, transition, style, animate } from '#angular/animations';
import { currentId } from 'async_hooks';
#Component({
selector: 'app-customer',
templateUrl: './customer.component.html',
styleUrls: ['./customer.component.scss'],
animations: [
trigger('detailExpand', [
state('collapsed', style({height: '0px', minHeight: '0'})),
state('expanded', style({height: '*'})),
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
]),
],
})
export class CustomerComponent implements OnInit {
columnsToDisplay: string[] = ['customerName', 'customerPhone', 'customerEmail', 'created_at'];
dataSource : any;
expandedElement : any;
addCustomer : boolean = false;
ProposalByCustomer : any;
constructor(public rest : CustomerService) { }
ngOnInit(){
this.getCustomer();
}
getCustomer() {
this.rest.getCustomers(localStorage.getItem('currentUser')).subscribe(result => {
console.log(result);
if(result['status'] == 1){
this.dataSource = result['value'];
}
});
}
applyFilter(filterValue: string) {
this.dataSource.filter = filterValue.trim().toLowerCase();
if (this.dataSource.paginator) {
this.dataSource.paginator.firstPage();
}
}
getProposalByCustomer(customer){
console.log(customer);
let token = localStorage.getItem('currentUser');
console.log(token);
let data = {customerId : customer.customerId};
console.log(data);
this.rest.getProposalByCustomer(data , token).subscribe(result => {
console.log(result);
if(result['status'] == 1){
this.ProposalByCustomer = result['data'];
}
})
}
addCustmr() {
this.addCustomer = !this.addCustomer;
}
}
I am using AngularJS for web app and in that I am trying to read data from APIs. Thus i have made few Models in accordance with the API's result set. Among many Models, Lets talk about a single Model TYPE
//This is the JSON API is returning
{
"records":[
{
"ID":"1",
"TYPE":"mythological"
}
],
"pagination":{
"count":"1",
"page":1,
"limit":10,
"totalpages":1
}
}
Now I have made the following Model for TYPE
//type.ts
export class Type {
"ID":string;
"TYPE":string;
}
After fetching the data from API i am successfully storing it and running through my code using following TYPE component ts.
//gallery.component.ts
import { Component, OnInit } from '#angular/core';
import { DataService } from 'src/app/services/data.service';
import { Type } from 'src/app/models/type';
#Component({
selector: 'app-gallery',
templateUrl: './gallery.component.html',
styleUrls: ['./gallery.component.scss']
})
export class GalleryComponent implements OnInit {
types: Type;
constructor(private data: DataService) { }
ngOnInit() {
}
clickfunction(){
this.data.getData().subscribe(data=>{
this.types=data.records;
console.log(this.types);
});
}
}
ALso, i am fetching data from this service
//data.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class DataService {
dataUrl:string = 'http://localhost/api-slim/public/index.php/api/info/type';
constructor(private http: HttpClient) { }
getData() {
return this.http.get(this.dataUrl);
}
}
Although the application is running its obviously giving me the following error, which i need to radicate.
Date: 2019-09-26T19:42:06.903Z - Hash: a1b41d5889df87ba0aa3
5 unchanged chunks
Time: 780ms
ℹ 「wdm」: Compiled successfully.
ERROR in src/app/components/gallery/gallery.component.ts(23,21): error TS2339: Property 'records' does not exist on type 'Object'.
NOW
The pagination data that the API is providing is common in each of the API response, but as you can see none of my models are consuming it. What would be the best way to store and use that pagination in each of my model. I have tried to made a temporary demo class in gallery.component.ts as follows,
export class TEMP {
records: TYPE[];
pagination: [];
}
But it's ugly. Is there any efficient fix?
Your model class doesn't really reflect the API response.
A model is like a custom data structure that you can use like a data type like this:
export TEMP { //consider renaming this to something more meaningful
records: Array<Type>;
pagination: Pagination;
}
export class Type {
ID: string;
TYPE: string;
}
export Pagination{
count: string;
page: number;
limit: number;
totalpages: number;
}
I'm engaging with an Angular project. I using ng2-smart-table as a table for my project. as well as some one has connected it for firebase. but i can't understand how its works by look at the code. The affixed code as follows.(I added this ng2-smart-table for patients components of my project)
patients.components.ts
import { Component, OnInit } from '#angular/core';
import { PatientsService } from './patients.service';
import { Patients } from './patients.model';
#Component({
selector: 'ngx-patients',
styles: [],
template: `
<ng2-smart-table
(createConfirm)="addData($event)"
[settings]="settings"
[source]="list"
>
</ng2-smart-table>
`
})
export class PatientsComponent implements OnInit {
list: Patients[] = [];
constructor(private service: PatientsService) {}
ngOnInit() {
this.service.getPatients().subscribe(actionArray => {
let a = actionArray.payload.get('data');
if (a) {
this.list = a;
}
});
}
settings = {
add: {
addButtonContent: '<i class="nb-plus"></i>',
createButtonContent: '<i class="nb-checkmark"></i>',
cancelButtonContent: '<i class="nb-close"></i>',
confirmCreate: true
},
edit: {
editButtonContent: '<i class="nb-edit"></i>',
saveButtonContent: '<i class="nb-checkmark"></i>',
cancelButtonContent: '<i class="nb-close"></i>'
},
delete: {
deleteButtonContent: '<i class="nb-trash"></i>',
confirmDelete: true
},
columns: {
id: {
title: 'ID'
},
name: {
title: 'Full Name'
},
username: {
title: 'User Name'
},
email: {
title: 'Email'
}
}
};
addData(event) {
this.list.push(event.newData);
console.log(this.list);
this.service.addPatient({ data: this.list }).subscribe(next => {
event.confirm.reject();
});
}
}
**patients.service.ts**
import { Injectable } from '#angular/core';
import { AngularFirestore } from '#angular/fire/firestore';
import { Patients } from './patients.model';
import { from } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class PatientsService {
//patients
patients : Patients;
constructor(private firestore: AngularFirestore) { }
/**
* this is for the get informations about patients
*/
getPatients(){
return this.firestore.collection('patients').doc('patientData').snapshotChanges();
}
addPatient(object){
return from(this.firestore.collection('patients').doc('patientData').set(object))
}
}
patients.model.ts
export class Patients {
id: string;
name: string;
username: string;
email: string;
}
what happening by follow keywords
subscribe
push
payload
can anybody help to me.
Angular is built upon a library called RxJs, reactive extensions for JavaScript. Reactive programming is based around observables. This is a concept you really need to learn before you start Angular development. Observables are like arrays of data where the values comes in over time. Subscribing to the observable runs the subscription function each time the observable emits a value down the stream.
This is a concept that cannot be covered in a single StackOverflow answer but some good places to start are.
https://www.learnrxjs.io/
http://reactivex.io/
https://rxmarbles.com/