Importing json2csv module in Angular 4 - angularjs

I am trying to use this library in my application to convert JSON data to CSV file format. I installed the lib into my project as it mentions https://www.npmjs.com/package/json2csv
npm install json2csv --save.
I also see the module in my node_module folder. Then in my component class i am calling it like so
import { json2csv } from 'json2csv';
But then I get this error
[ts] Module '"c:/dev/angularworkspace/tntzweb/node_modules/json2csv/index"' has no exported member 'json2csv'.
Can someone please help me!!

Change the import to:
import * as json2csv from 'json2csv';
Then implement as:
let fields = ['field1', 'field2', 'field3'];
  let result = json2csv({ data:[{ field1: 'a', field2: 'b', field3: 'c' }], fields: fields });
  console.log(result);

The other answers are now outdated. For json2csv version 5, first:
npm install --save json2csv #types/json2csv
Then at the top of your Angular component/service/etc:
import { parse } from 'json2csv';
Then to generate the csv in your method:
const csv = parse(json);
There are, of course, all kinds of options you can pass to parse() and json2csv exposes other classes and functions you can import and use as well. There are useful examples in the tests from #types/json2csv.

Here is a complete CSV download 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));
}
}

You can use the angular 2 version of the library. The link to the same is: https://github.com/aqeel-legalinc/angular2-json2csv

Related

Using ngrx-data how to configure the app to fetch data of specific entities from specific urls

If we follow ngrx-data example and look at the Entity DataService, we can fetch the Hero data that we have in-memory (hard-coded) without any configuration. The default will work the same as if we configured:
const defaultDataServiceConfig: DefaultDataServiceConfig = {
root: 'api', // or a running server url, e.g: 'http://localhost:4000/api'
timeout: 3000, // request timeout
}
and in e.g: EntityStoreModule
#NgModule({
providers: [{ provide: DefaultDataServiceConfig, useValue: defaultDataServiceConfig }]
})
Question:
How will we configure our app to fetch data for entity "Heros" from the default source:
root: 'api'
and data for entity "Villans" from a URL:
root: 'http://localhost:4000/villans'
and data for other entities from their (other/various) respective URLs ...?
After reviewing the docs specifically:
Custom EntityDataService and
Replace the HttpUrlGenerator
I came up with this solution. Anyone feel free to comment.
Define/review your data types - entity metadata - entity names;
Create mapping to plurals for non-default plural entity names (default is: name + 's');
For entities with the non-default root URL create a mapping of entity names to specific URL;
File: ../entity-metadata.ts
// Step 1:
const entityMetadata: EntityMetadataMap = {
Hero: {},
Villan: {},
Creature: {},
DataA01: {}
// etc.
}
// Step 2:
const pluralNames = {
Hero: 'heroes',
DataA01: 'data-a01'
}
export const entityConfig = {
entityMetadata,
pluralNames
};
// Step 3:
export const rootUrls = {
// Hero: - not needed here, data comes from default root
Villan: 'http://localhost:4001',
Creature: 'http://localhost:4001',
DataA01: 'http://remoteserver.net:80/publicdata',
}
Replace the HttpUrlGenerator (doc) with your own URL generator (DynamicHttpUrlGenerator)
File: ../http-dyn-url-generator.ts
import { Injectable } from '#angular/core';
import {
DefaultHttpUrlGenerator,
HttpResourceUrls,
normalizeRoot,
Pluralizer,
DefaultPluralizer,
} from '#ngrx/data';
import { rootUrls } from '../data/ngrx-data/db01-entity-metadata';
#Injectable()
export class DynamicHttpUrlGenerator extends DefaultHttpUrlGenerator {
constructor(private aPluralizer: Pluralizer = new DefaultPluralizer(undefined)) {
super(aPluralizer);
}
protected getResourceUrls(entityName: string, root: string): HttpResourceUrls {
let resourceUrls = this.knownHttpResourceUrls[entityName];
if ( ! resourceUrls) {
// rootUrls contains
// mapping of individual ngrx data entities
// to the root URLs of their respective data sources.
// It contains only entities which do not have
// the default root URL.
if (rootUrls.hasOwnProperty(entityName)) {
root = rootUrls[entityName];
}
const nRoot = normalizeRoot(root);
const url = `${nRoot}/${this.aPluralizer.pluralize(entityName)}/`.toLowerCase();
// remove after testing
console.log('-- entityName: ' + entityName + ', URL: ' + url)
resourceUrls = {
entityResourceUrl: url,
collectionResourceUrl: url
};
this.registerHttpResourceUrls({ [entityName]: resourceUrls });
}
return resourceUrls;
}
}
For each of your data entity create a custom EntityDataService
HeroDataService
VillanDataService
CreatureDataService
DataA01DataService
etc.
(doc and code is here) - the code example is under
// store/entity/hero-data-service.ts
Register your DynamicHttpUrlGenerator and your custom EntityDataServices in your app's module, in my case:
File: ../ngrx-data-store.module.ts
(in a simple app, directly in file: app.module.ts)
#NgModule({
imports: [ ... ],
providers: [ { provide: HttpUrlGenerator, useClass: DynamicHttpUrlGenerator },
HeroDataService,
VillanDataService,
CreatureDataService,
DataA01DataService
]
})
Use your custom EntityDataServices in your components for each given entity the same way as all standard or default EntityDataServices to fetch data. The data will be pulled from the respective URLs you set in the const: rootUrls.
Don't forget to get your URLs' data server(s) configured and started.
A few important considerations:
on your server you may need to enable CORS handling. E.g: on nestjs use:
app.enableCors();
if your client app uses: Angular in-memory-web-api you need to enable access to remote server as follows:
File: ../in-mem-data.module.ts (or as you named it)
import { NgModule } from '#angular/core';
import { HttpClientModule } from '#angular/common/http';
import { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api';
import { InMemDataService } from '../../services/data/in-mem-data/in-mem-data.service';
#NgModule({
imports: [
HttpClientModule,
HttpClientInMemoryWebApiModule.forRoot(InMemDataService, {
passThruUnknownUrl: true // <--- IMPORTANT for remote data access
}),
]
})
export class InMemDataModule {}

Rollup Build failure for SCSS exports to be used in TS ( [!] Error: 'default' is not exported by src/styles/variables.scss )

I'm running into the following rollup build failure where I would like to be able to used exports from a scss file in my typescript files.
The build failure reads as follows:
[!] Error: 'default' is not exported by src/styles/variables.scss,
imported by src/components/Layout/Layout.themes.tsx
https://rollupjs.org/guide/en/#error-name-is-not-exported-by-module
src/components/Layout/Layout.themes.tsx (1:7) 1: import vbl from
'../../styles/variables.scss';
My rollup config looks as follows:
import scss from 'rollup-plugin-scss';
import typescript from 'rollup-plugin-typescript2';
import image from '#rollup/plugin-image';
import { terser } from 'rollup-plugin-terser';
import pkg from './package.json';
export default {
input: ['src/index.tsx'],
output: [
{
file: pkg.main,
format: 'cjs',
sourcemap: true,
name: 'Main'
},
{
file: pkg.module,
format: 'esm',
sourcemap: true,
name: 'tree-shaking'
}
],
external: [...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.devDependencies || {}), ...Object.keys(pkg.peerDependencies || {})],
plugins: [image(), scss({ output: 'dist/styles.css' }), typescript({ useTsconfigDeclarationDir: true }), terser()]
};
The variables.scss contains:
// colors
$color-blue: #1c4077;
$color-orange: #e87d1e;
:export {
colorBlue: $color-blue;
colorOrange: $color-orange;
}
The variables.scss.d.ts typings file contains:
export interface IGlobalScss {
colorBlue: string;
colorOrange: string;
}
export const variables: IGlobalScss;
export default variables;
And the Layout.themes.tsx file reads as follows:
import vbl from '../../styles/variables.scss';
export const myTheme = {
headerColor: vbl.colorBlue,
footerColor: vbl.colorOrange
}
I've tried an import of the non-default export import { variables } from '../../styles/variables.scss'; but it fails as well with:
[!] Error: 'variables' is not exported by src/styles/variables.scss,
imported by src/components/Layout/Layout.themes.tsx
https://rollupjs.org/guide/en/#error-name-is-not-exported-by-module
src/components/Layout/Layout.themes.tsx (1:9) 1: import {
variables } from '../../styles/variables.scss';
I am able to serve the project via Storybook, however when I build via Rollup I encounter the error listed above. Please assist me in resolving this build failure?
Here is a CodeSandbox for this example. Extract the zip, yarn and run either yarn start or yarn build to test in VSCode. You'll notice that yarn start succeeds whereas yarn build will fail as mentioned above.
I think the problem is that the output property is not false.
Here is what the plugin does when that property is set to false:
if (options.output === false) {
const css = compileToCSS(code)
return {
code: 'export default ' + JSON.stringify(css),
map: { mappings: '' }
}
}
and this happens in the transform hook, which is invoked before the parsing takes place. This is important because export default ... is treated as a module, meaning you can import it in your js files.
So I think you'll have to manually bundle that variables file with:
scss({ output: false }).
Now, another problem arises: when you import from the .scss file, you'll get the :export object stringified.
For example:
"export default ":export {\n colorBlue: #1c4077;\n colorOrange: #e87d1e; }\n""
the plugin in use does not seem to handle this case.
So I think the solution involves manipulating that string so that you'd end up with something like this:
`{ colorX: 'value', colorY: 'value' }`

Jhipster webpack compilation error when checking an array value

I am using Jhipster with Angular. I have a method that is trying to check to see if the user in as admin.
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { IPost } from 'app/shared/model/post.model';
import { AccountService } from 'app/core/auth/account.service';
import { Subscription } from 'rxjs';
import { Account } from 'app/core/user/account.model';
#Component({
selector: 'jhi-post-detail',
templateUrl: './post-detail.component.html'
})
export class PostDetailComponent implements OnInit {
post: IPost | null = null;
authSubscription!: Subscription;
account: Account | null = null;
constructor(protected activatedRoute: ActivatedRoute, private accountService: AccountService) { }
ngOnInit(): void {
this.activatedRoute.data.subscribe(({ post }) => (this.post = post));
this.authSubscription = this.accountService.getAuthenticationState().subscribe(account => (this.account = account));
}
previousState(): void {
window.history.back();
}
private isAdmin(): boolean | undefined {
return this.account?.authorities.includes('ROLE_ADMIN');
}
}
When the code is compiled I get an error
ERROR in ./src/main/webapp/app/entities/post/post-detail.component.ts 21:30
Module parse failed: Unexpected token (21:30)
File was processed with these loaders:
* ./node_modules/angular2-template-loader/index.js
* ./node_modules/cache-loader/dist/cjs.js
* ./node_modules/thread-loader/dist/cjs.js
* ./node_modules/ts-loader/index.js
* ./node_modules/eslint-loader/dist/cjs.js
You may need an additional loader to handle the result of these loaders.
| }
| isAdmin() {
> return this.account ? .authorities.includes('ROLE_ADMIN') : ;
| }
| };
ℹ 「wdm」: Failed to compile.
As a workaround, if I just hard-code the return value to 'true' in the isAdmin() method it works and compiles. How come just checking to see if the array contains something causes the webpack to freak out?
Optional chaining was introduced in Typescript 3.7, current JHipster 6.7.1 uses Typescript 3.4.5 so it's not very surprising that your expression is not understood and translated as ternary operator.
Try upgrading typescript version in package.json and npm install to see if it solves it.

Can't resolve all parameters for

I am new with Angular. I am getting an error when I am trying to create a production build (ng build --prod). The error thrown is as follow
ERROR in Can't resolve all parameters for OpcionValor in C:/Users/Usuario/Documents/global_workspace/hcdu_proyect/HCDU_FRONT/HCDU/src/app/modulos/anamesis/anamnesis.module.ts: (?, ?)
.
ERROR in ./src/main.ts
Module not found: Error: Can't resolve './$$_gendir/app/app.module.ngfactory' in 'C:\Users\Usuario\Documents\global_workspace\hcdu_proyect\HCDU_FRONT\HCDU\src'
# ./src/main.ts 4:0-74
# multi ./src/main.ts
The file anamnesis.module.ts contains the following code:
import {NgModule} from '#angular/core';
import {CommonModule} from '#angular/common';
import {OpcionComboBox, OpcionComboBoxComplex} from '../interfaces/interfaces.module'
#NgModule({
imports: [
CommonModule,
],
declarations: []
})
export class OpcionValor implements OpcionComboBox {
constructor(private nombre: string, private valor: string) {
this.nombre = nombre;
this.valor = valor;
}
getEntityValor(): string {
return this.valor;
}
setEntityValor(valor: string) {
this.valor = valor;
}
}
export class OpcionValorObservacion extends OpcionValor implements OpcionComboBoxComplex {
observacion: string;
constructor(name: string, valor: string, observacion: string) {
super(name,valor);
this.observacion = observacion;
}
getEntityObservacion(): string {
return this.observacion;
}
setEntityObservacion(observacion: string) {
this.observacion = observacion;
}
}
export interface AnamnesisInterface {
getOpcionSeleccionadaPorNombre(nombre:string):OpcionValor;
setOpcionValorPorNombre(nombre:string, valor:string);
setOpcionValorObservacionPorNombre(nombre:string, valor:string, observacion:string);
}
I am not sure why the error is thrown if I do not have that error in dev environment. Please, somebody can help me to solve this error?
Your module is expecting two input parameters to its constructor, both of type string. Angular does not know how to construct it, most likely. I assume somewhere you have a top-level AppModule or some equivalent which looks similar to this:
#NgModule({
imports: [ OpcionValor ],
bootstrap: [ AppComponent ]
})
export class AppModule {
}
It needs to inject an OpcionValor module but can't because it doesn't know what to pass in for the constructor parameters.
I think you may need to do a little redesigning. Should nombre and valor really be members of OpcionValor, or do they belong on a Component? Should OpcionValor even be a module, or should it actually be a Component?
I had solved this issue by adding the class declaration regarding the ts file name.
The module files is called anamnesis.module.ts so I had to add the following class declaration:
export class AnamnesisModule { }
So, my module code is :
File name: anamnesis.module.ts
import {NgModule} from '#angular/core';
import {CommonModule} from '#angular/common';
import {OpcionComboBox, OpcionComboBoxComplex} from '../interfaces/interfaces.module'
#NgModule({
imports: [
CommonModule
],
declarations: []
})
**export class AnamnesisModule { }**
export class OpcionValor implements OpcionComboBox {
nombre: string;
valor: string;
constructor(nombre: string, valor?: string) {
this.nombre = nombre;
this.valor = valor;
}
..................
}
export class OpcionValorObservacion extends OpcionValor implements OpcionComboBoxComplex {
observacion: string;
constructor(name: string, valor?: string, observacion?: string) {
super(name,valor);
this.observacion = observacion;
}
.........
}
I am not sure why but it is working. I suppose there is a relation between the file name and the class declaration required.

Angular 2 Observables and Change detection - How to get one component to retrieve a value, set by another component in a service?

I think I'm overlooking something very fundamental, and I've been banging my head for a couple of days now. I'm new to Angular and reactive programming.
So, I have one service and two components.
In my versionService.ts I have a helper method which allows components to set a currentVersion in a _dataStore.
private _dataStore: {
currentVersion: any
};
currVersionStream$: Subject<Version>;
constructor(public http: Http) {
this.currVersionStream$ = new BehaviorSubject<Version>(null);
this._dataStore = {
currentVersion: null
};
}
public setCurrentVersion(v: Version): void {
if (v != null) {
this._dataStore.currentVersion = v;
this.currVersionStream$.next(this._dataStore.currentVersion);
}
}
Then in my component select-version.component.ts, through a (click) event from the view/template, I use the setCurrentVersion helper method from the VersionService.ts to store the cliked on version.
In select.version.template.html:
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li *ngFor="#v of availableVersions" (click)="selectedVersion(v)">
<a href="#">
Version {{v.versionID}}
</a>
</li>
<li>No version</li>
</ul>
In version.component.ts: Here I call on the method in the service.
Update: I inject versionService in both of my components.
import {VersionService} from '../../services/services';
#Component({
selector: 'select-version',
templateUrl: 'app/component/selectVersion/select-version.template.html',
providers: [VersionService]
})
export class SelectVersionComponent implements OnInit {
constructor(public versionService: VersionService) {}
public selectedVersion(v: Version) {
console.log("SVC - set this version: " + v.versionID);
this.versionService.setCurrentVersion(v);
}
So, in my second component I want to retrieve the value set/stored in the service (_dataStore), and display it in its view/template (of my second component)
In my second-component.template.html:
<h2>{{selectedVersion}}</h2>
In my second-component.ts:
Update:
import {VersionService} from '../../services/services';
#Component({
selector: 'main-container',
templateUrl: 'app/component/mainContainer/main-container.template.html',
providers: [VersionService],
})
selectedVersion: any;
constructor(public versionService: VersionService) {
this.versionService.currVersionStream$.subscribe((v) => {
if(v != null) {
this.selectedVersion = "Version" + v.versionID
}
}, error => console.error (error));
}
Update:
In my main component, app.component.ts:
import {SidebarComponent} from './component/sidebar/sidebar.component';
import {MainContainerComponent} from './component/mainContainer/main-container.component';
#Component({
selector: 'init-app',
templateUrl: 'app/app-component.template.html',
directives: [SidebarComponent, MainContainerComponent],
})
export class AppComponent {
constructor() {}
}
In my boot.ts:
import {bootstrap} from 'angular2/platform/browser'
import {AppComponent} from './app.component'
import {HTTP_PROVIDERS} from 'angular2/http'
bootstrap(AppComponent, [HTTP_PROVIDERS])
.catch(err => console.error(err));
What am I missing to be able to view the currentVersion in my template of the second component, and will it update each time a new value is set?
Thanks for any reply!
To complement what Eric and pixelbits said, you don't share the same instance of the service. One instance is created per component since you use the providers attribute at this level.
If you want to know more about the hierarchical injection, you could have a look at this answer:
What's the best way to inject one service into another in angular 2 (Beta)?.
Hope it helps you,
Thierry

Resources