suppose i've the following kendo grid
<kendo-grid-column field="full_name" title="Contact Name" [width]="220">
<ng-template kendoGridCellTemplate let-dataItem>
<div
class="customer-photo"
[ngStyle]="{ 'background-image': photoURL(dataItem) }"
></div>
<div class="customer-name">{{ dataItem.full_name }}</div>
</ng-template>
</kendo-grid-column>
<kendo-grid-column field="job_title" title="Job Title" [width]="220">
</kendo-grid-column>
<kendo-grid-column
field="country"
title="Country"
[width]="100"
[class]="{ 'text-center': true }"
[resizable]="false"
>
<ng-template kendoGridCellTemplate let-dataItem>
<img class="flag" [src]="flagURL(dataItem)" width="30" />
</ng-template>
</kendo-grid-column>
what i want to do is to get an array of grid columns with column title & field name
eg: [{field:"full_name",title:"Contact Name"},
{field:"job_title",title:"Job Title"}];
how to do this in Kendo Grid for angular?
You can access the grid using ViewChild and then access its columns field:
import { Component, ViewChild, AfterViewInit } from '#angular/core';
import { GridComponent } from "#progress/kendo-angular-grid";
#Component({
selector: 'my-app',
template: `
<kendo-grid #grid [data]="gridData">
<kendo-grid-column field="Id" title="ID">
</kendo-grid-column>
<kendo-grid-column field="CompanyName" title="Company Name">
</kendo-grid-column>
</kendo-grid>
`
})
export class AppComponent implements AfterViewInit {
#ViewChild("grid") grid: GridComponent;
public readonly gridData = [{
'Id': 'ALFKI',
'CompanyName': 'Alfreds Futterkiste',
'ContactName': 'Maria Anders',
'ContactTitle': 'Sales Representative',
'City': 'Berlin'
}, {
'Id': 'ANATR',
'CompanyName': 'Ana Trujillo Emparedados y helados',
'ContactName': 'Ana Trujillo',
'ContactTitle': 'Owner',
'City': 'México D.F.'
}, {
'Id': 'ANTON',
'CompanyName': 'Antonio Moreno Taquería',
'ContactName': 'Antonio Moreno',
'ContactTitle': 'Owner',
'City': 'México D.F.'
}];
ngAfterViewInit() {
const columns = this.grid.columns.map((column) => {
return {
field: column.field,
title: column.title
};
});
console.log(columns);
}
}
Note: this.grid.columns gives you an object of type QueryList<ColumnBase>. The ColumnBase class doesn't contain the field field in its definition, however, it does appear on the object. I guess that this.grid.columns actually returns an object of type QueryList<ColumnComponent>. ColumnComponent derives from ColumnBase and does contain the field field.
For me, to get the column.filed, the above code didn't work. But when I use fieldName: column["field"], it worked for me.
I have array from local json file test.json
{"collection":[{"scriptId":"28936862","startDate":"2020-03-31T15:54:45.658992","endDate":"2020-03-31T15:57:33.573312","createDate":"31.03.2020 15:54:45"}}]
So this is my app.component.ts
import { Component } from '#angular/core';
import tasksData from '../assets/test.json';
interface Task {
scriptId: String;
}
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
tasks: Task[] = tasksData;
}
This is my app.component.html
<div class="container">
<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let task of tasks">
<td>{{ task.scriptId }}</td>
</tr>
</tbody>
</table>
The code above i took from here. In the example array is simple. But my array starts with "collection", and the code doesn't work.
My IDE gives an error on this line tasks: Task[] = tasksData;
How can I change the code for my json array?
Thank you in advance
Define tasks property like this :
tasks: Task[] = tasksData.collection;
and your interface should be like :
interface Task {
scriptId: string;
startDate: string;
endDate: string;
createDate: string;
}
I am new to angular and developing my very first application using angular 4 and typescript
I want to use Cascading drop-down in table using angular4
Currently, I have been working on it but when I change drop down from the first row it is a binding second level dropdown for all row.
I want to bind the second level drop down of the row from the first level drop down is changed.
I have some idea on my mind to achieve this but I guess It might be a patch so I am very curious to know any proper way of angular to achieve this.
ts file code
import { Component, OnInit, EventEmitter } from '#angular/core';
import { Category } from '../model/Category';
import { SubCategory } from '../model/subCategory';
import { Partner } from '../model/partner';
import { GetdataService } from '../../../../Server/api/Getdata.service';
import { Router } from '#angular/router';
#Component({
templateUrl: 'UploadFile.component.html'
})
export class UploadFileComponent implements OnInit {
AllCategoryList: Category[] = [];
AllSubCategoryList: SubCategory[] = [];
constructor(private _datatask: GetdataService, private _router: Router) { }
onChangeCategory(deviceValue) {
if (deviceValue > 0) {
this._datatask.getAllSubCategory(deviceValue).subscribe(
(data: SubCategory[]) => {
this.AllSubCategoryList = data;
}
);
console.log("from component: " + deviceValue);
}
else
{
//clear dropdown...
this.AllSubCategoryList= [];
}
}
ngOnInit() {
this._datatask.getAllCategory().subscribe(
(data: Category[]) => {
this.AllCategoryList = data;
}
);
this._datatask.getAllPartner().subscribe(
(data: Partner[]) => {
this.AllPartnerList = data;
}
);
}
}
HTML file
<div>
<table width="100%" border="1">
<thead>
<th>Category</th>
<th>SubCategory</th>
<th>Partner</th>
</thead>
<tbody *ngFor="let transaction of transactions">
<tr>
<td>
<select style="Width:100px;" (change)="onChangeCategory($event.target.value)" >
<option value=0>--Select--</option>
<option value="{{item.ID}}" *ngFor="let item of AllCategoryList" [ngValue]="item.ID" >{{item.Category}}</option>
</select>
</td>
<td>
<select style="Width:100px;">
<option value=0>--Select--</option>
<option *ngFor="let item of AllSubCategoryList" [ngValue]="item.ID" >{{item.SubCategory}}</option>
</select>
</td>
<td>
<select style="Width:100px;">
<option value=0>--Select--</option>
<option *ngFor="let item of AllPartnerList" [ngValue]="item.ID" >{{item.PartnerName}}</option>
</select>
</td>
</tr>
</tbody>
</table>
</div>
any help will be highly appreciated.
The problem is you needed an array of states... (in the plunker you listed in the comments below).
You can probably apply same to your code in original question.
list-component.ts tweaks
export class CountryListComponent {
states: State[] = [[] as State[],[] as State[],[] as State[]]
onSelect(value,index) {
this.states[index] = this._dataService.getStates().
filter((item)=> item.countryid == value);
}
}
list-component.html tweak
Updated: after this exchange with #GünterZöchbauer :
Use (ngModelChange) over (change)
<select [(ngModel)]="selectedCountry[number].id"
(ngModelChange)="onSelect($event, number)">
Fixed Plunker
I am also faced this problem and finally got a solution using custom pipe.
make a filter in external file like - mycustomfilter.ts
mycustomfilter.ts
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'myCustomFilter',
pure: false
})
export class myCustomFilterPipe implements PipeTransform {
transform(items: any[], field : string, value): any[] {
if (!items) return [];
if (!value || value.length === 0) return items;
return items.filter(it =>
it[field] === value);
}
}
declarations in app module
#NgModule({
imports: [ BrowserModule, FormsModule ],
declarations: [ App, myCustomFilterPipe],
bootstrap: [ App ]
})
item-order.component.ts
categoryList=[{id:1,name:'Office Stationery'},
{id:2,name:'Grocery'}
];
itemList=[
{id:1,name:'Pen',categoryID:1},
{id:2,name:'A4 Peper',categoryID:1},
{id:3,name:'Oil',categoryID:2},
{id:4,name:'Sugar',categoryID:2}
];
item-order.component.html
<tr *ngFor="let order of o.controls; let i = index" [formGroup]="order" class="form-row">
<td>
<select class="form-control" formControlName="ItemCategoryID">
<option value="">Select</option>
<option *ngFor="let s of categoryList" [ngValue]="s.id">{{s.name}}</option>
</select>
</td>
<td>
<select class="form-control" formControlName="ItemID">
<option value="">Select</option>
<option *ngFor="let s of itemList | myCustomFilter : 'categoryID' : order.value.ItemCategoryID" [ngValue]="s.id">{{s.name}}</option>
</select>
</td>
</tr>
I am trying to pop up a modal in angular 2 that will display a list of people. The source of the list is a JSON file. I think the data is not being properly bound to the table in the modal. I am new to angular 2 and am not sure what I am missing.
Service to read JSON file:
returns-json-array-service.ts
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Observable } from 'rxjs';
#Injectable()
export class ReturnsJsonArrayService {
constructor(private http: Http) {}
getPeople(): Observable<any> {
return this.http.request('./people.json')
.do( res => console.log('HTTP response:', res))
.map(res => res.json().payload)
.do(console.log);
//.map(res => res.json());
/*return this.http.get('./people.json')
.map((res:Response) => res.json())
.catch((error:any) => Observable.throw(error.json().error || 'Server error'));*/
}
}
SAmple json file: people.json
{
"id": "1",
"name": "David Martinez Ros",
"email": "info#davidmartinezros.com",
"age": "33"
},
{
"id": "2",
"name": "Paco Roberto Corto",
"email": "paco.roberto.corto#gmail.com",
"age": "51"
},
{
"id": "3",
"name": "Silvia Elegante i Latina",
"email": "silvia.elegante.latina#gmail.com",
"age": "30"
}
]
modal-component.ts
import {Component, Input} from '#angular/core';
import {NgbModal, NgbActiveModal} from '#ng-bootstrap/ng-bootstrap';
import { Observable } from 'rxjs';
import { ReturnsJsonArrayService } from './returns-json-array.service';
#Component({
selector: 'ngbd-modal-content',
providers: [ReturnsJsonArrayService],
template: `
<div class="modal-header">
<h4 class="modal-title">Hi there!</h4>
<button type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross click')">
<span aria-hidden="true">×</span>
</button>
<div class="modal-body" *ngFor="let person of peopleData | async" >
<p>One fine body…</p>
<table border=1>
<tr>
<td>
<h3>Id: {{ person.id }}</h3>
</td>
<td>
<h3>name: {{ person.name }}</h3>
</td>
<td>
<h3>email: {{ person.email }}</h3>
</td>
<td>
<h3>age: {{ person.age }}</h3>
</td>
<td>
</tr>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" (click)="activeModal.close('Close click')">Submit</button>
</div>
`
})
export class NgbdModalContent {
#Input() name;
#Input() peopleData: Observable<Array<any>>;
constructor(public activeModal: NgbActiveModal,private peopleService: ReturnsJsonArrayService) {
this.peopleData = this.peopleService.getPeople();
console.log("AppComponent.data:" + this.peopleData);
}
}
#Component({
selector: 'ngbd-modal-component',
templateUrl: './modal-component.html'
})
export class NgbdModalComponent {
constructor(private modalService: NgbModal) {}
open() {
const modalRef = this.modalService.open(NgbdModalContent);
modalRef.componentInstance.name = 'Barb' ;
console.log("Peopledatra on open():" + modalRef.componentInstance.peopleData);
}
}
modal-component.html
<button class="btn btn-primary" (click)="open()">Assign</button>
this.peopleService.getPeople() returns an observable which is cold to activate it and make it hot you must add a subscribe this.peopleService.getPeople().subscribe() the subscribe will take a success method as the first argument like so:
this.peopleService.getPerople().subscribe(
(json) => {
// do something here with the json
}
)
Once the json is returned you can set it to a property within your components scope like so:
this.peopleService.getPerople().subscribe(
(json) => {
this.json = json;
}
)
That property will then be accessible with in the components template.
I want to override the template of the DataTable component of primeng and this is how my code looks like:
my-datatable.component.ts
import { Component, OnInit, ElementRef, Renderer2, ChangeDetectorRef } from '#angular/core';
import { DataTable, DomHandler } from 'primeng/primeng';
import { ObjectUtils } from '../../../../node_modules/primeng/components/utils/ObjectUtils'
import { ColumnHeaders } from '../../../../node_modules/primeng/components/datatable/datatable'
#Component({
selector: 'my-datatable',
templateUrl: './my-datatable.component.html',
styleUrls: ['./my-datatable.component.scss']
})
export class MyDatatableComponent extends DataTable {
constructor(el: ElementRef, domHandler: DomHandler, renderer: Renderer2, changeDetector: ChangeDetectorRef, objectUtils: ObjectUtils) {
super(el, domHandler, renderer, changeDetector, objectUtils);
console.log('MyDatatableComponent');
}
}
my-datatable.component.html, this file has the same template as of the base component. Idea was to first run and then make modifications
<div [ngStyle]="style" [class]="styleClass" [style.width]="containerWidth" [ngClass]="{'ui-datatable ui-widget':true,'ui-datatable-reflow':responsive,'ui-datatable-stacked':stacked,'ui-datatable-resizable':resizableColumns,'ui-datatable-scrollable':scrollable}">
<div class="ui-datatable-loading ui-widget-overlay" *ngIf="loading"></div>
<div class="ui-datatable-loading-content" *ngIf="loading">
<i class="fa fa-circle-o-notch fa-spin fa-2x"></i>
</div>
<div class="ui-datatable-header ui-widget-header" *ngIf="header">
<ng-content select="p-header"></ng-content>
</div>
<p-paginator [rows]="rows" [first]="first" [totalRecords]="totalRecords" [pageLinkSize]="pageLinks" styleClass="ui-paginator-bottom" (onPageChange)="paginate($event)" [rowsPerPageOptions]="rowsPerPageOptions" *ngIf="paginator && paginatorPosition!='bottom' || paginatorPosition =='both'"></p-paginator>
<div class="ui-datatable-tablewrapper" *ngIf="!scrollable">
<table [class]="tableStyleClass" [ngStyle]="tableStyle">
<thead class="ui-datatable-thead">
<tr *ngIf="!headerColumnGroup" class="ui-state-default" [pColumnHeaders]="columns"></tr>
<ng-template [ngIf]="headerColumnGroup">
<tr *ngFor="let headerRow of headerColumnGroup.rows" class="ui-state-default" [pColumnHeaders]="headerRow.columns"></tr>
</ng-template>
</thead>
<tfoot *ngIf="hasFooter()" class="ui-datatable-tfoot">
<tr *ngIf="!footerColumnGroup" class="ui-state-default" [pColumnFooters]="columns"></tr>
<ng-template [ngIf]="footerColumnGroup">
<tr *ngFor="let footerRow of footerColumnGroup.rows" class="ui-state-default" [pColumnFooters]="footerRow.columns"></tr>
</ng-template>
</tfoot>
<tbody [ngClass]="{'ui-datatable-data ui-widget-content': true, 'ui-datatable-hoverable-rows': (rowHover||selectionMode)}" [pTableBody]="columns"></tbody>
</table>
</div>
<ng-template [ngIf]="scrollable">
<div class="ui-datatable-scrollable-wrapper ui-helper-clearfix" [ngClass]="{'max-height':scrollHeight}">
<div *ngIf="frozenColumns" [pScrollableView]="frozenColumns" frozen="true" [ngStyle]="{'width':this.frozenWidth}" class="ui-datatable-scrollable-view ui-datatable-frozen-view"></div>
<div [pScrollableView]="scrollableColumns" [ngStyle]="{'width':this.unfrozenWidth, 'left': this.frozenWidth}" class="ui-datatable-scrollable-view" [virtualScroll]="virtualScroll" (onVirtualScroll)="onVirtualScroll($event)" [ngClass]="{'ui-datatable-unfrozen-view': frozenColumns}"></div>
</div>
</ng-template>
<p-paginator [rows]="rows" [first]="first" [totalRecords]="totalRecords" [pageLinkSize]="pageLinks" styleClass="ui-paginator-bottom" [alwaysShow]="alwaysShowPaginator" (onPageChange)="paginate($event)" [rowsPerPageOptions]="rowsPerPageOptions" *ngIf="paginator && paginatorPosition!='top' || paginatorPosition =='both'"></p-paginator>
<div class="ui-datatable-footer ui-widget-header" *ngIf="footer">
<ng-content select="p-footer"></ng-content>
</div>
<div class="ui-column-resizer-helper ui-state-highlight" style="display:none"></div>
<span class="fa fa-arrow-down ui-datatable-reorder-indicator-up" style="position: absolute; display: none;"></span>
<span class="fa fa-arrow-up ui-datatable-reorder-indicator-down" style="position: absolute; display: none;"></span>
</div>
Also I have added this new component in the declarations array in the app.module.ts file. So, I know that it is being included, which is the reason why I am getting a parse error.
The errors which I encounter in the console is:
Unhandled Promise rejection: Template parse errors:
Can't bind to 'pColumnHeaders' since it isn't a known property of 'tr'. ("ass="ui-datatable-thead">
<tr *ngIf="!headerColumnGroup" class="ui-state-default" [ERROR ->][pColumnHeaders]="columns"></tr>
<ng-template [ngIf]="headerColumnGroup">
"): ng:///AppModule/CsxDatatableComponent.html#14:74
Can't bind to 'pColumnHeaders' since it isn't a known property of 'tr'. (" <tr *ngFor="let headerRow of headerColumnGroup.rows" class="ui-state-default" [ERROR ->][pColumnHeaders]="headerRow.columns"></tr>
</ng-template>
</thead>
"): ng:///AppModule/CsxDatatableComponent.html#16:100
Can't bind to 'pColumnFooters' since it isn't a known property of 'tr'. ("ass="ui-datatable-tfoot">
<tr *ngIf="!footerColumnGroup" class="ui-state-default" [ERROR ->][pColumnFooters]="columns"></tr>
<ng-template [ngIf]="footerColumnGroup">
"): ng:///AppModule/CsxDatatableComponent.html#20:74
Can't bind to 'pColumnFooters' since it isn't a known property of 'tr'. (" <tr *ngFor="let footerRow of footerColumnGroup.rows" class="ui-state-default" [ERROR ->][pColumnFooters]="footerRow.columns"></tr>
</ng-template>
</tfoot>
"): ng:///AppModule/CsxDatatableComponent.html#22:100
Can't bind to 'pTableBody' since it isn't a known property of 'tbody'. ("datatable-data ui-widget-content': true, 'ui-datatable-hoverable-rows': (rowHover||selectionMode)}" [ERROR ->][pTableBody]="columns"></tbody>
</table>
</div>
"): ng:///AppModule/CsxDatatableComponent.html#25:137
Can't bind to 'pScrollableView' since it isn't a known property of 'div'. ("-helper-clearfix" [ngClass]="{'max-height':scrollHeight}">
<div *ngIf="frozenColumns" [ERROR ->][pScrollableView]="frozenColumns" frozen="true"
[ngStyle]="{'width':this.frozenWid"): ng:///AppModule/CsxDatatableComponent.html#31:41
Can't bind to 'pScrollableView' since it isn't a known property of 'div'. ("ozenWidth}" class="ui-datatable-scrollable-view ui-datatable-frozen-view"></div>
<div [ERROR ->][pScrollableView]="scrollableColumns" [ngStyle]="{'width':this.unfrozenWidth, 'left': this.frozenWidt"): ng:///AppModule/CsxDatatableComponent.html#33:19
Can't bind to 'virtualScroll' since it isn't a known property of 'div'. ("is.unfrozenWidth, 'left': this.frozenWidth}"
class="ui-datatable-scrollable-view" [ERROR ->][virtualScroll]="virtualScroll" (onVirtualScroll)="onVirtualScroll($event)"
[ngClas"): ng:///AppModule/CsxDatatableComponent.html#34:55 ; Zone: <root> ; Task: Promise.then ;
pColumnHeaders, pColumnFooters are all components which are already exported via the DataTableModule. I am unable to figure out how to make these parsing errors go away, I am sure I am missing something.
Any help is much appreciated.
Update:
This is how my app.module.ts looks. I have the DataTableModule, BrowserModule and FormsModule imported. I am able to use the standard primeNg datatable component on my views, just not able to override it.
app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { HttpModule } from '#angular/http';
/* PRIME NG */
import {
AutoCompleteModule,
PanelMenuModule,
MenuItem,
MenubarModule,
OverlayPanelModule,
TabViewModule,
ButtonModule,
CodeHighlighterModule,
DropdownModule,
DialogModule,
MultiSelectModule ,
InputTextModule,
TooltipModule,
CheckboxModule,
SplitButtonModule,
RadioButtonModule,
MessagesModule,
ConfirmDialogModule,
ConfirmationService,
AccordionModule,
PanelModule,
FieldsetModule,
CalendarModule,
DataTableModule,
MenuModule,
BreadcrumbModule,
TreeModule,
DomHandler,
ChartModule
} from 'primeng/primeng';
import { ObjectUtils } from '../../node_modules/primeng/components/utils/ObjectUtils';
/* APP-SPECIFIC */
import { WindowRef } from './windowref';
import { routing } from './app.routing';
import { MyDatatableComponent } from './components/my-datatable.component';
#NgModule({
declarations: [
DatatableComponent,
ChartsGraphsComponent,
CsxDatatableComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
routing,
AutoCompleteModule,
BrowserAnimationsModule,
PanelMenuModule,
MenubarModule,
OverlayPanelModule,
TabViewModule,
ButtonModule,
CodeHighlighterModule,
DropdownModule,
MultiSelectModule,
DialogModule,
InputTextModule,
TooltipModule,
CheckboxModule,
SplitButtonModule,
RadioButtonModule,
MessagesModule,
ConfirmDialogModule,
AccordionModule,
PanelModule,
FieldsetModule,
CalendarModule,
DataTableModule,
MenuModule,
BreadcrumbModule,
TreeModule,
ChartModule
],
providers: [
DomHandler,
ObjectUtils
],
bootstrap: [AppComponent]
})
export class AppModule { }
You see this error because the selectors you're trying to use are not exported by their respective modules, because they're part of the internal/private part of the PrimeNG framework.
Importing the DataTableModule will make no difference if the selectors you're trying to use are not exported.
In the case of [pColumnHeaders], defined in datatable.ts by the ColumnHeaders component, you'll see that the ColumnHeaders component is not exported in the DataTableModule definition:
#NgModule({
imports: [CommonModule,SharedModule,PaginatorModule,FormsModule],
exports: [DataTable,SharedModule],
declarations: [DataTable,DTRadioButton,DTCheckbox,ColumnHeaders,ColumnFooters,TableBody,ScrollableView,RowExpansionLoader]
})
export class DataTableModule { }
Source of datatable.ts
For you to be able to use the [pColumnHeaders] selector, the DataTableModule would have to export the ColumnHeaders component like so:
#NgModule({
imports: [CommonModule,SharedModule,PaginatorModule,FormsModule],
exports: [DataTable,SharedModule,ColumnHeaders],
declarations: [DataTable,DTRadioButton,DTCheckbox,ColumnHeaders,ColumnFooters,TableBody,ScrollableView,RowExpansionLoader]
})
export class DataTableModule { }
My guess is that this design is intentional and that you're trying to use 'private' and undocumented selectors that are not part of the API.
The question you have to ask yourself is what it is you're trying to achieve. Chances are that the PrimeNG DataTable API provides the interface to do that.