How to implement json2csv in Angular 2 - json

How to implement json2csv in angular 2 using typescript?(https://www.npmjs.com/package/json2csv). Is there any other better approach.

This may not be based on the original (I haven't checked), but:
https://www.npmjs.com/package/angular2-json2csv
The readme says it should be used as a service, but it can also be used as a plain class, eg:
let csv = new CSVService();
It has its faults though:
If you have an array of objects that are similar, but not all have a value for every single property, the column headers will be missing for those properties.
It doesn't allow you to exclude columns, which may or may not be desired.
Edit:
I've come up with an alternative, which accounts for items with more properties than the others. Use or modify as you wish:
export class JSONToCSV {
private AddValue(Row: string, Value: string) {
let Comma: string = ',';
if (Row === '')
Comma = '';
return Row + Comma + Value;
}
private GetHeader(Item: any) {
let Row: string = '';
for (var Key in Item) {
Row = this.AddValue(Row, Key);
}
return Row + '\r\n';
}
private GetRow(Item: any) {
let Row: string = '';
for (var Key in Item) {
Row = this.AddValue(Row, Item[Key]);
}
return Row + '\r\n';
}
private GetPropCount(Item: any) {
return Object.keys(Item).length;
}
public Convert(Data: any, Filename: string) {
let CSV: string = '';
let ColumnsObject: any = null;
for (var Item of Data) {
if ((ColumnsObject == null) || (this.GetPropCount(Item) > this.GetPropCount(ColumnsObject))) {
ColumnsObject = Item;
}
CSV = CSV + this.GetRow(Item);
}
CSV = this.GetHeader(ColumnsObject) + CSV;
let CSVBlob = new Blob([CSV], { type: 'text/csv' });
if (window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(CSVBlob, Filename);
} else {
// window.open(URL.createObjectURL(CSVBlob));
let url= window.URL.createObjectURL(CSVBlob);
let Anchor: any = document.createElement('a');
Anchor.setAttribute('style', 'display:none;');
document.body.appendChild(Anchor);
Anchor.href = url;
Anchor.download = Filename;
Anchor.click();
}
}
}

#dave-notage response works with Chrome, but not with Firefox.
Here is a working implementation:
<a [download]="csvFileName" [href]="getCSVDownloadLink()">CSV export</a>
import { Component } from '#angular/core';
import { DomSanitizer } from '#angular/platform-browser';
import * as json2csv from 'json2csv';
#Component({
selector: 'csv-download',
templateUrl: './csv-download.component.html',
styleUrls: ['./csv-download.component.scss']
})
export class CsvDownloadComponent {
public csvFileName = `test.csv`;
private SOME_DATA: any[] = [{id: 1, name: 'Peter'}, {id: 2, name: 'Sarah'}];
constructor(
private domSanitizer: DomSanitizer,
) { }
getCSVDownloadLink() {
return this.generateCSVDownloadLink({
filename: this.csvFileName,
data: this.SOME_DATA,
columns: [
'id',
'name',
],
});
}
// you can move this method to a service
public generateCSVDownloadLink(options: { filename: string, data: any[], columns: string[] }): SafeUrl {
const fields = options.columns;
const opts = { fields, output: options.filename };
const csv = json2csv.parse(options.data, opts);
return this.domSanitizer.bypassSecurityTrustUrl('data:text/csv,' + encodeURIComponent(csv));
}
}

Related

Angular 2 download json response data from getList() in csv or Excel format

The end game is simple, my Angular app gets and generates a list of data entries on a view called customers-list.component.html like so:
Name: Olivia
Age: 23
Active: true
----------------
Name: Julia
Age: 22
Active: true
----------------
Name: Wes
Age: 23
Active: true
----------------
Name: Gabe
Age: 24
Active: false
I want to be able to download a .csv file of said entries of data.
In the customers-list.component.ts, I've tried this function getcsvFile(), defined the data that is passed in through the service.ts, defined a new Blob() function and used JSON.stringify(data) and passed in getCustomersList() data and save it as a .csv:
export class CustomersListComponent implements OnInit {
customers: Observable<Customer[]>;
constructor(private customerService: CustomerService) { }
......
getcsvFile() {
this.customers = this.customerService.getCustomersList();
let file = new Blob([JSON.stringify(this.customers)], { type: 'data:application/csv;charset=utf-8,content_encoded_as_url' });
saveAs(file, 'customerList.csv')
}
}
Heres the service.ts:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class CustomerService {
private baseUrl = 'http://localhost:8000/customers';
constructor(private http: HttpClient) { }
.........
getCustomersList(): Observable<any> {
return this.http.get(`${this.baseUrl}/`);
}
}
but when I download the csv file and open it, i dont see the actual data thats been entried, but rather all this weird information thats still in json format:
{
"_isScalar":false,
"source":{"_isScalar":false,
"source":{"_isScalar":false,
"source":{"_isScalar":true,
"value":{"url":"http://localhost:8000/customers/",
"body":null,"reportProgress":false,
"withCredentials":false,
"responseType":"json",
"method":"GET",
"headers":{"normalizedNames":{},
"lazyUpdate":null,"headers":{}},
"params":{"updates":null,
"cloneFrom":null,"encoder":{},
"map":null},
"urlWithParams":"http://localhost:8000/customers/"}},
"operator":{"concurrent":1}},
"operator":{}},
"operator":{}
}
when i want to see something closer to this :
[
{"id": 2, "name": "Olivia", "age": 23, "active": true},
{"id": 3, "name": "Julia", "age": 22, "active": true},
{"id": 4, "name": "Wes", "age": 23, "active": true},
{"id": 5, "name": "Gabe", "age": 24, "active": false}
]
What am I missing?
Would be interesting to see what your saveAs function does, but anyhow, if you do not want to install a module, you can easily do it yourself.
// Download CSV
download(data: any, filename: string, columns: string, header: string, delimiter: string | undefined) {
const csvData = this.convertToCSV(data, columns, header, delimiter);
const link: any = document.createElement('a');
link.setAttribute('style', 'display:none;');
document.body.appendChild(link);
const blob = new Blob([csvData], {type: 'text/csv'});
link.href = window.URL.createObjectURL(blob);
const isIE = !!(<any> document).documentMode;
if (isIE) {
navigator.msSaveBlob(blob, filename + '.csv');
} else {
link.download = filename + '.csv';
}
link.click();
link.remove();
}
and to transform your JSON into a CSV, you can do it like that:
/**
* exports json (array) data to CSV
* #param data
* #param {string} columns
* #param {string} header
* #param {string | undefined} delimiter
* #returns {string}
*/
convertToCSV(data: any, columns: string, header: string, delimiter: string |
undefined) {
let row = '';
const del = delimiter ? delimiter : ';';
const head = header.split(del);
const col = columns.split(del);
// creating the header
for (const headerTxt of head) {
row += headerTxt + del;
}
row += '\r\n';
// start with the rows
for (const dataset of data) {
let line = '';
for (let i = 0; i < col.length; i++) {
let dataToAdd = dataset[col[i]];
if (dataset[col[i]] == null || dataset[col[i]] === undefined) {
dataToAdd = '';
}
line += '"' + dataToAdd + '"' + del;
}
row += line + '\r\n';
}
return row;
}
so in your case you would most likely call it like that:
download(this.customers, 'customer',
'id,name,age,active',
'ID,Name,Age,Active', ',')
Hope that helps :)
Edit:
I see, you are not subscribing your observable, that most likely is the error. Try this:
getcsvFile() {
this.customerService.getCustomersList()
.pipe(take(1)) // <-- HERE
.subscribe(customers=>{ // <-- AND HERE
if (customers) {
download(customers, 'customer','id,name,age,active','ID,Name,Age,Active', ',');
}
});
}
Greetings

How to load json from file and set it as global variable in Vue?

I'm new to Vue. I want to read employeeId from a login form and ust it to load some json files named according as employeeId.json like (10000001.json, 20000001.json) and set the json object as a global variable so I can easily access it in all components.
Firstly, I don't know how to dynamically load json files. Using import sees not work. Some one suggested using require should work. But there are not many examples, I don't know where to put require...
Secondly, how do I set the json as global after the employeeId props in? I'm very confused where to put it (inside the export default or not? inside methods or not? or inside created/mounted or not?) and where to use this or not...
This is the script section of my headerNav.vue file.
<script>
//**I placed them here now, it works, but employeeId is hard coded...
import json10000001 from "./json/10000001.json";
import json20000001 from "./json/20000001.json";
import json30000001 from "./json/30000001.json";
// var employeeId = employeeIdFromLogin;
var jsonForGlobal;
var employeeId = 10000001;
var jsonFileCurrentObj;
if (employeeId == "10000001") {
jsonForGlobal = jsonFileCurrentObj = json10000001;
} else if (employeeId == "20000001") {
jsonForGlobal = jsonFileCurrentObj = json20000001;
} else if (employeeId == "30000001") {
jsonForGlobal = jsonFileCurrentObj = json30000001;
}
export default {
// props:{
// employeeIdFromLogin: String,
// },
props:['employeeIdFromLogin'],
jsonForGlobal,
// employeeIdFromLogin,
data() {
return {
docked: false,
open: false,
position: "left",
userinfo: {},
jsonFileCurrent: jsonFileCurrentObj,
// employeeIdFromLogin: this.GLOBAL3.employeeIdFromLogin
// jsonFile: currentJsonFile
};
},
mounted() {
//**I tried put it here, not working well...
// var employeeId = this.employeeIdFromLogin;
// // var jsonForGlobal;
// console.log("headernav.employeeIdFromLogin="+this.employeeIdFromLogin);
// // var employeeId = 10000001;
// var jsonFileCurrentObj;
// if (employeeId == "10000001") {
// this.jsonForGlobal = this.jsonFileCurrentObj = json10000001;
// } else if (employeeId == "20000001") {
// this.jsonForGlobal = this.jsonFileCurrentObj = json20000001;
// } else if (employeeId == "30000001") {
// this.jsonForGlobal = this.jsonFileCurrentObj = json30000001;
// }
},
methods: {
switchPage(pageName) {
this.$emit("switchPage", pageName);
}
//**I don't know how to use the require...
// var employeeId = 10000001;
// getJsonFile(employeeId) {
// this.currentJsonFile = require("../assets/json/" + employeeId + ".json");
// }
}
};
You might want to use vuex to manage global store. But if you don't want includes Vuex, there is a simpler way to have global state:
Define globalStore.js
// globalStore.js
export const globalStore = new Vue({
data: {
jsonForGlobal: null
}
})
then import it and use in component:
import {globalStore} from './globalStore.js'
export default {
props: ['employeeIdFromLogin'],
data: function ()
return {
jsonLocal: globalStore.jsonForGlobal,
jsonFileCurrent: null
}
},
watch: {
employeeIdFromLogin: {
handler(newVal, oldVal) {
const data = require('./json/' + this.employeeIdFromLogin + '.json')
this.jsonFileCurrent = data
globalStore.jsonForGlobal = data
}
}
}
}

json 2 typescript mapping gives type error

Okej so Im trying to map a list of .Net objects to my Angular frontend by way of Web Api 2. The objects are sent, I get them, but depending on the circumstances the objects and their properties might be an Employment reference, Assignment reference or an Assignment organization unit reference.
Here is an image of how the list of objects can look, with one AssignmentHolder that can be one of those three classes and a list of DependentEntities that can be one of those three classes.
Here is how they look in my Angular app:
This is the object containing them:
#JsonObject('AssignmentListItem')
export class AssignmentListItem {
#JsonProperty('AssignmentHolder')
AssignmentHolder: any = undefined;
#JsonProperty('DependentEntities')
DependentEntities: any = undefined;
#JsonProperty('AssignmentRoles', [AssignmentRole])
AssignmentRoles: AssignmentRole[] = undefined;
#JsonProperty('NumberOfDependentEntities', Number)
NumberOfDependentEntities: Number = undefined;
#JsonProperty('IsInherited', Boolean)
IsInherited: boolean = undefined;
}
These are the classes.
#JsonObject('ReferenceBase')
export class ReferenceBase {
#JsonProperty('OrganizationRegistrationNumber', OrganizationRegistrationNumber)
OrganizationRegistrationNumber: OrganizationRegistrationNumber = undefined;
#JsonProperty('IsIncomplete', Boolean)
IsIncomplete: Boolean = undefined;
#JsonProperty('SortingName', String)
SortingName: string = undefined;
}
-------
#JsonObject('EmploymentReference')
export class EmploymentReference extends ReferenceBase {
#JsonProperty('NationalCivicRegistrationNumber', String)
NationalCivicRegistrationNumber: NationalCivicRegistrationNumber = undefined;
#JsonProperty('GivenName', String)
GivenName: string = undefined;
#JsonProperty('Surname', String)
Surname: string = undefined;
#JsonProperty('FullName', String)
FullName: string = undefined;
constructor() {
super();
this.FullName = (this.GivenName + ' ' + this.Surname);
this.SortingName = this.FullName;
}
}
-----
#JsonObject('AssignmentReference')
export class AssignmentReference extends ReferenceBase {
#JsonProperty('AssignmentRoles', [AssignmentRole])
AssignmentRoles: AssignmentRole[] = undefined;
#JsonProperty('OrganizationName', String)
OrganizationName: string = undefined;
#JsonProperty('NationalCivicRegistrationNumber', NationalCivicRegistrationNumber)
NationalCivicRegistrationNumber: NationalCivicRegistrationNumber = undefined;
#JsonProperty('Surname', String)
Surname: string = undefined;
#JsonProperty('FullName', String)
FullName: string = undefined;
#JsonProperty('GivenName', String)
GivenName: string = undefined;
}
------
#JsonObject('AssignmentOrganizationalUnitReference')
export class AssignmentOrganizationalUnitReference extends ReferenceBase {
#JsonProperty('OrganizationName', String)
OrganizationName: string = undefined;
#JsonProperty('Name', String)
Name: string = undefined;
#JsonProperty('Active', Boolean)
Active: Boolean = undefined;
#JsonProperty('IncludeSubUnits', Boolean)
IncludeSubUnits: Boolean = undefined;
#JsonProperty('AssignmentRoles', [AssignmentRole])
AssignmentRoles: AssignmentRole[] = undefined;
#JsonProperty('UnitId', String)
UnitId: string = undefined;
#JsonProperty('Type', OrganizationalUnitReferenceType)
Type: OrganizationalUnitReferenceType = undefined;
}
So those are the objects I want to map too depending on what Is in the assignmentlist I get back
This is my custom DTO so that I can use a custom converter:
#JsonObject('AssignmentsDto')
export class AssignmentsDto {
#JsonProperty('AssignmentList', ObjectConverter)
AssignmentList: AssignmentListItem[] = undefined;
}
this is my JsonCustomConverter
#JsonConverter
export class ObjectConverter implements JsonCustomConvert<AssignmentListItem[]> {
// We receive the instance and just serialize it with the standard json2typescript method.
serialize(assignmentListItems: AssignmentListItem[]): any {
const jsonConvert = new JsonConvert();
return jsonConvert.serialize(assignmentListItems);
}
// We receive a json object (not string) and decide
// based on the given properties whether we want to
// create an instance of AssignmentReference or AssignmentOrgUnitReference.
deserialize(assignmentListItems: any): AssignmentListItem[] {
const jsonConvert = new JsonConvert();
let assignments = new Array<AssignmentListItem>();
//Map the Holder entity.
for (let assignment of assignmentListItems) {
if (assignment.AssignmentHolder['__type'] === 'something.something.Web.Models.EmploymentReference' ||
assignment.AssignmentHolder['__type'] === 'something.something.Web.Models.AssignmentEmploymentReference') {
let tempAssignment: AssignmentListItem = jsonConvert.deserialize(assignment.AssignmentHolder, EmploymentReference);
//For every assignment there is a list of Dependents. Here we map those.
for (let dependent of assignment.DependentEntities) {
if (dependent['__type'] === 'something.something.Web.Models.EmploymentReference' ||
dependent['__type'] === 'something.something.Web.Models.AssignmentEmploymentReference') {
let tempDependent: EmploymentReference = jsonConvert.deserialize(dependent, EmploymentReference);
tempAssignment.DependentEntities.push(tempDependent);
} else if (dependent['__type'] === 'something.something.Web.Models.AssignmentOrganizationalUnitReference') {
let tempDependent: AssignmentOrganizationalUnitReference = jsonConvert.deserialize(dependent, AssignmentOrganizationalUnitReference);
tempAssignment.DependentEntities.push(tempDependent);
}
}
assignments.push(tempAssignment);
} else if (assignment.AssignmentHolder['__type'] === 'something.something.Web.Models.AssignmentOrganizationalUnitReference') {
let tempAssignment: AssignmentListItem = jsonConvert.deserialize(assignment.AssignmentHolder, AssignmentOrganizationalUnitReference);
//For every assignment there is a list of Dependents. Here we map those.
for (let dependent of assignment.DependentEntities) {
if (dependent['__type'] === 'something.something.Web.Models.EmploymentReference' ||
dependent['__type'] === 'something.something.Web.Models.AssignmentEmploymentReference') {
let tempDependent: EmploymentReference = jsonConvert.deserialize(dependent, EmploymentReference);
tempAssignment.DependentEntities.push(tempDependent);
} else if (dependent['__type'] === 'something.something.Web.Models.AssignmentOrganizationalUnitReference') {
let tempDependent: AssignmentOrganizationalUnitReference = jsonConvert.deserialize(dependent, AssignmentOrganizationalUnitReference);
tempAssignment.DependentEntities.push(tempDependent);
}
}
assignments.push(tempAssignment);
}
}
console.log('return ', assignments);
return assignments;
}
}
And finally, this is the Assignment Api Service where i use the converter.
// GET LIST OF ASSIGNMENTS
getAssignmentList(
filterStr: string,
orgNoParam: string,
skip: number,
take: number
): Observable<any> {
// set headers
let head = new HttpHeaders();
head = head.append('Content-Type', 'application/json');
// set binds to model reciever
const data = {
'orgNoParam': orgNoParam,
'filterStr': filterStr,
};
let body = JSON.stringify(data);
// set query parameters
let url = this.assignmentListUrl + '?skip=' + skip + '&take=' + take;
return this.http.post<any>(url, body, { headers: head })
.map(this.convertData)
.catch(this.handleError);
}
private convertData(res: Response) {
let jsonConvert = new JsonConvert();
jsonConvert.valueCheckingMode = ValueCheckingMode.ALLOW_NULL;
let deSerializedAssignments: AssignmentListItem[] = jsonConvert.deserialize(res, AssignmentsDto).AssignmentList;
return deSerializedAssignments;
The error I get in console is :
Fatal error in JsonConvert. Failed to map the JSON object to the JavaScript class "AssignmentsDto" because of a type error. Class property: AssignmentList Expected type: undefined JSON property: AssignmentList JSON type: [object, object, object, object, object]
I solved this by making sure every single property from the json object was being mapped to the typescript classes and in AssignmentsDto I added a second The object property as well as the converter, like so:
#JsonProperty('AssignmentList',[AssignmentListItem], ObjectConverter)
AssignmentList: AssignmentListItem[] = undefined;
Hope this helps someone!

Explicitly Trusting HTML - Angular 5

I have created a pipe to format the XML string that I get from a server as a pretty printing.
import { Pipe, PipeTransform } from '#angular/core';
import * as jQuery from 'jquery';
import { escape } from 'querystring';
import { DomSanitizer, SafeHtml } from '#angular/platform-browser';
//import * as angular from '../angular.js';
//CAMBIAR a string
#Pipe({
name: 'formatXml'
})
export class FormatXmlPipe implements PipeTransform {
constructor(private sanitized: DomSanitizer) { }
transform(xml: String): SafeHtml {
var formatted = '';
var reg = /(>)(<)(\/*)/g;
xml = xml.replace(reg, '$1\r\n$2$3');
var pad = 0;
jQuery.each(xml.split('\r\n'), function (index, node) {
var indent = 0;
if (node.match(/.+<\/\w[^>]*>$/)) {
indent = 0;
} else if (node.match(/^<\/\w/)) {
if (pad != 0) {
pad -= 1;
}
} else if (node.match(/^<\w[^>]*[^\/]>.*$/)) {
indent = 1;
} else {
indent = 0;
}
var padding = '';
for (var i = 0; i < pad; i++) {
padding += ' ';
}
formatted += padding + node + '\r\n';
pad += indent;
});
var escaped = formatted.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/ /g, ' ').replace(/\n/g, '<br />');
// https://stackoverflow.com/questions/39240236/insert-xml-into-dom-in-angular-2
let safeEscaped = this.sanitized.bypassSecurityTrustHtml(escaped);
return safeEscaped;
//let safeEscaped = this.sanitized.bypassSecurityTrustHtml(escaped);
//return safeEscaped;
}
}
the string that I have is shown in the following div:
<tr *ngFor="let message of messages; let i = index;">
<td *ngIf="i == _rowToShow" >{{message.xmlString | formatXml}}</td>
</tr>
_rowToShow is just a variable to limit the rows to show to an specific one and it works so it can not be the problem
so basically what I think that it is happening is that I am calling correctly to the pipe formatXml and I get the correct value of the string, but it is not a trusting HTML so it does not show it properly (it shows only the original XML).
I have read that to solve this problem in Angular 1.2 was just needed to use $sce.trustAsHtml but I do not really know how to do it.
https://odetocode.com/blogs/scott/archive/2014/09/10/a-journey-with-trusted-html-in-angularjs.aspx
Update
At the end what I get is
SafeValue must use [property]=binding:
plus my XML
Any body know what can be the problem?

Transform Request to Autoquery friendly

We are working with a 3rd party grid (telerik kendo) that has paging/sorting/filtering built in. It will send the requests in a certain way when making the GET call and I'm trying to determine if there is a way to translate these requests to AutoQuery friendly requests.
Query string params
Sort Pattern:
sort[{0}][field] and sort[{0}][dir]
Filtering:
filter[filters][{0}][field]
filter[filters][{0}][operator]
filter[filters][{0}][value]
So this which is populated in the querystring:
filter[filters][0][field]
filter[filters][0][operator]
filter[filters][0][value]
would need to be translated to.
FieldName=1 // filter[filters][0][field]+filter[filters][0][operator]+filter[filters][0][value] in a nutshell (not exactly true)
Should I manipulate the querystring object in a plugin by removing the filters (or just adding the ones I need) ? Is there a better option here?
I'm not sure there is a clean way to do this on the kendo side either.
I will explain the two routes I'm going down, I hope to see a better answer.
First, I tried to modify the querystring in a request filter, but could not. I ended up having to run the autoqueries manually by getting the params and modifying them before calling AutoQuery.Execute. Something like this:
var requestparams = Request.ToAutoQueryParams();
var q = AutoQueryDb.CreateQuery(requestobject, requestparams);
AutoQueryDb.Execute(requestobject, q);
I wish there was a more global way to do this. The extension method just loops over all the querystring params and adds the ones that I need.
After doing the above work, I wasn't very happy with the result so I investigated doing it differently and ended up with the following:
Register the Kendo grid filter operations to their equivalent Service Stack auto query ones:
var aq = new AutoQueryFeature { MaxLimit = 100, EnableAutoQueryViewer=true };
aq.ImplicitConventions.Add("%neq", aq.ImplicitConventions["%NotEqualTo"]);
aq.ImplicitConventions.Add("%eq", "{Field} = {Value}");
Next, on the grid's read operation, we need to reformat the the querystring:
read: {
url: "/api/stuff?format=json&isGrid=true",
data: function (options) {
if (options.sort && options.sort.length > 0) {
options.OrderBy = (options.sort[0].dir == "desc" ? "-" : "") + options.sort[0].field;
}
if (options.filter && options.filter.filters.length > 0) {
for (var i = 0; i < options.filter.filters.length; i++) {
var f = options.filter.filters[i];
console.log(f);
options[f.field + f.operator] = f.value;
}
}
}
Now, the grid will send the operations in a Autoquery friendly manner.
I created an AutoQueryDataSource ts class that you may or may not find useful.
It's usage is along the lines of:
this.gridDataSource = AutoQueryKendoDataSource.getDefaultInstance<dtos.QueryDbSubclass, dtos.ListDefinition>('/api/autoQueryRoute', { orderByDesc: 'createdOn' });
export default class AutoQueryKendoDataSource<queryT extends dtos.QueryDb_1<T>, T> extends kendo.data.DataSource {
private constructor(options: kendo.data.DataSourceOptions = {}, public route?: string, public request?: queryT) {
super(options)
}
defer: ng.IDeferred<any>;
static exportToExcel(columns: kendo.ui.GridColumn[], dataSource: kendo.data.DataSource, filename: string) {
let rows = [{ cells: columns.map(d => { return { value: d.field }; }) }];
dataSource.fetch(function () {
var data = this.data();
for (var i = 0; i < data.length; i++) {
//push single row for every record
rows.push({
cells: _.map(columns, d => { return { value: data[i][d.field] } })
})
}
var workbook = new kendo.ooxml.Workbook({
sheets: [
{
columns: _.map(columns, d => { return { autoWidth: true } }),
// Title of the sheet
title: filename,
// Rows of the sheet
rows: rows
}
]
});
//save the file as Excel file with extension xlsx
kendo.saveAs({ dataURI: workbook.toDataURL(), fileName: filename });
})
}
static getDefaultInstance<queryT extends dtos.QueryDb_1<T>, T>(route: string, request: queryT, $q?: ng.IQService, model?: any) {
let sortInfo: {
orderBy?: string,
orderByDesc?: string,
skip?: number
} = {
};
let opts = {
transport: {
read: {
url: route,
dataType: 'json',
data: request
},
parameterMap: (data, type) => {
if (type == 'read') {
if (data.sort) {
data.sort.forEach((s: any) => {
if (s.field.indexOf('.') > -1) {
var arr = _.split(s.field, '.')
s.field = arr[arr.length - 1];
}
})
}//for autoquery to work, need only field names not entity names.
sortInfo = {
orderByDesc: _.join(_.map(_.filter(data.sort, (s: any) => s.dir == 'desc'), 'field'), ','),
orderBy: _.join(_.map(_.filter(data.sort, (s: any) => s.dir == 'asc'), 'field'), ','),
skip: 0
}
if (data.page)
sortInfo.skip = (data.page - 1) * data.pageSize,
_.extend(data, request);
//override sorting if done via grid
if (sortInfo.orderByDesc) {
(<any>data).orderByDesc = sortInfo.orderByDesc;
(<any>data).orderBy = null;
}
if (sortInfo.orderBy) {
(<any>data).orderBy = sortInfo.orderBy;
(<any>data).orderByDesc = null;
}
(<any>data).skip = sortInfo.skip;
return data;
}
return data;
},
},
requestStart: (e: kendo.data.DataSourceRequestStartEvent) => {
let ds = <AutoQueryKendoDataSource<queryT, T>>e.sender;
if ($q)
ds.defer = $q.defer();
},
requestEnd: (e: kendo.data.DataSourceRequestEndEvent) => {
new DatesToStringsService().convert(e.response);
let ds = <AutoQueryKendoDataSource<queryT, T>>e.sender;
if (ds.defer)
ds.defer.resolve();
},
schema: {
data: (response: dtos.QueryResponse<T>) => {
return response.results;
},
type: 'json',
total: 'total',
model: model
},
pageSize: request.take || 40,
page: 1,
serverPaging: true,
serverSorting: true
}
let ds = new AutoQueryKendoDataSource<queryT, T>(opts, route, request);
return ds;
}
}