npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@esss/ng-xform

v0.25.2

Published

Angular lib

Downloads

120

Readme

ng-xform - Angular library built using ngx-library yeoman generator.

npm version Build Status Coverage Status dependencies Status devDependencies Status

Demo

View all the directives in action at Demo and Demo source code

Dependencies

  • Angular (requires Angular 6, tested with 6.1.0)

Installation

Install above dependencies via npm.

npm i --save @ng-select/[email protected] [email protected] [email protected]

Now install @esss/ng-xform via:

npm i --save @esss/ng-xform

You will need to import styles. Example: 'src/styles.scss'

@import 'bootstrap/dist/css/bootstrap.min.css';
@import 'ngx-bootstrap/datepicker/bs-datepicker.css';
@import "@ng-select/ng-select/themes/default.theme.css";

Setup the MeasureComponent adding the js file on .angular-cli.json

"scripts": [
  "../node_modules/mathjs/dist/math.js"
]

SystemJS

Note:If you are using SystemJS, you should adjust your configuration to point to the UMD bundle. In your systemjs config file, map needs to tell the System loader where to look for @esss/ng-xform:

map: {
  '@esss/ng-xform': 'node_modules/@esss/ng-xform/bundles/ng-xform.umd.js',
}

Once installed you need to import the main module:

import { NgXformModule } from '@esss/ng-xform';

The only remaining part is to list the imported module in your application module. The exact method will be slightly different for the root (top-level) module for which you should end up with the code similar to (notice NgXformModule):

import { NgXformModule } from '@esss/ng-xform';

@NgModule({
  declarations: [AppComponent, ...],
  imports: [NgXformModule, ...],  
  bootstrap: [AppComponent]
})
export class AppModule {
}

Other modules in your application can simply import NgXformModule:

import { NgXformModule } from '@esss/ng-xform';

@NgModule({
  declarations: [OtherComponent, ...],
  imports: [NgXformModule, ...], 
})
export class OtherModule {
}

Usage

Template:

 <ng-xform [horizontalForm]="horizontal" [labelWidth]="labelWidth" [fields]="fields" ></ng-xform>

Component:

export class HomeComponent implements OnInit, OnDestroy {

  @ViewChild(NgXformEditSaveComponent) xformComponent: NgXformEditSaveComponent;
  @ViewChild('customField') customFieldTmpl: TemplateRef<any>;

  private colors: any[] = [
    { id: 0, name: 'other' },
    { id: 1, name: 'blue' },
    { id: 2, name: 'yellow' },
    { id: 3, name: 'white' },
    { id: 4, name: 'black' },
    { id: 5, name: 'orange' },
    { id: 6, name: 'purple' }
  ];

  public onchangefn = new Subject<string>();

  public fields: DynamicField[];
  public horizontal = false;
  public labelWidth = 2;
  public model: any;
  public outputhelper = {'A': 1, 'B': 2, 'C': 3};
  public subscriptions: Subscription[] = [];

  constructor(private titleService: Title, private http: HttpClient) { }

  ngOnInit() {
    const minDate = new Date();
    const maxDate = new Date();

    this.subscriptions.push(this.onchangefn.asObservable().subscribe(
      (value: any) =>  this.xformComponent.setValue({'outputopt': this.outputhelper[value]})
    ));

    minDate.setDate(minDate.getDate() - 3);
    maxDate.setDate(maxDate.getDate() + 3);
    this.titleService.setTitle('Home | @esss/ng-xform');
    this.fields = [
      new TextField({
        key: 'name',
        label: 'Name',
        validators: [
          Validators.minLength(3)
        ]
      }),
      new TextField({
        key: 'email',
        label: 'E-mail',
        validators: [
          Validators.required,
          Validators.email
        ]
      }),
      new SelectField({
        key: 'color_ro',
        label: 'Color read-only',
        readOnly: true,
        searchable: true,
        options: this.colors,
        optionLabelKey: 'name',
      }),
      new SelectField({
        key: 'color',
        label: 'Color',
        searchable: true,
        options: this.colors,
        addNewOption: true,
        addNewOptionText: 'Add Color',
        optionLabelKey: 'name',
      }),
      new TextField({
        key: 'other',
        label: 'Other color',
        visibilityFn: (value: any) => value.color && value.color.id === 0
      }),
      new NestedFormGroup({
        key: 'address',
        fields: [
          new SelectField({
            key: 'country',
            label: 'Country',
            searchHandler: this.observableSource.bind(this),
            searchByValueKeyHandler: this.observableSourceByPlaceId.bind(this),
            searchOnFocus: true,
            searchable: true,
            optionLabelKey: 'name',
            optionValueKey: 'alpha3Code',
            validators: [
              Validators.required
            ]
          })
        ]
      }),
      new SelectField({
        key: 'type',
        label: 'Type',
        options: ['a', 'b'],
        validators: [
          Validators.required
        ]
      }),
      new SelectField({
        key: 'type_tags',
        label: 'Type tags',
        options: [{id: 1, description: 'A'}, {id: 2, description: 'B'}, {id: 3, description: 'C'}],
        optionLabelKey: 'description',
        optionValueKey: 'id',
        multiple: true
      }),
      new MeasureField({
        key: 'length',
        label: 'Length',
        modelUnit: 'mm',
        viewUnit: of('m').pipe(delay(200)),
        availableUnits: of(['m', 'cm', 'mm']).pipe(delay(200))
      }),
      new MeasureField({
        key: 'width',
        label: 'Width',
        modelUnit: 'inch',
        viewUnit: of('inch').pipe(delay(200)),
        availableUnits: of(['inch', 'ft']).pipe(delay(200))
      }),
      new SelectField({
        key: 'opt',
        label: 'Select an option',
        options: [{id: 'A', description: 'Option A'}, {id: 'B', description: 'Option B'}, {id: 'C', description: 'Option C'}],
        optionLabelKey: 'description',
        optionValueKey: 'id',
        onChangeFn: (value: string) => {
          this.onchangefn.next(value);
        }
      }),
      new TextField({
        key: 'outputopt',
        label: 'Output of option',
        readOnly: true,
      }),
      new CheckboxField({
        key: 'news',
        label: 'News'
      }),
      new RadioGroupField({
        key: 'gender',
        label: 'Gender',
        options: of([{id: 1, label: 'male'}, {id: 2, label: 'female'}]).pipe(delay(2000)),
        optionValueKey: 'id',
        optionLabelKey: 'label'
      }),
      new MultilineField({
        key: 'comment',
        label: 'Comment',
        rows: 4
      }),
      new DateField({
        key: 'birth',
        label: 'Date of birth',
        theme: 'blue',
        minDate: minDate,
        maxDate: maxDate,
        showWeekNumbers: true
      }),
      new DateRangeField({
        key: 'range',
        label: 'Date range',
        theme: 'blue'
      }),
      new CustomField({
        key: 'custom_amount',
        label: 'Custom Field Amount',
        tmpl: this.customFieldTmpl
      }),
    ];
  }

  ngOnDestroy() {
    this.subscriptions.forEach(sub => sub.unsubscribe());
  }

  public onSubmit(values: object) {
    this.model = values;
  }

  populate() {
    this.xformComponent.setValue({
      name: 'Customer',
      email: '[email protected]',
      type_tags: [2],
      type: 'b',
      color: { id: 3, name: 'white' },
      color_ro: { id: 3, name: 'white' },
      address: {
        street: 'ChIJn7h-4b9JJ5URGCq6n0zj1tM'
      },
      gender: 1,
      length: { value: 2, unit: 'm'},
      width: { value: 3, unit: 'ft'},
      opt: 'A',
      news: true,
      comment: 'Mussum Ipsum, cacilds vidis litro abertis. Mauris nec dolor in eros commodo tempor. Aenean aliquam molestie leo, vitae ' +
      'iaculis nisl. Quem num gosta di mé, boa gentis num é. Tá deprimidis, eu conheço uma cachacis que pode alegrar sua vidis. Em pé ' +
      'sem cair, deitado sem dormir, sentado sem cochilar e fazendo pose. Leite de capivaris, leite de mula manquis sem cabeça. Praesent ' +
      'vel viverra nisi. Mauris aliquet nunc non turpis scelerisque, eget. Casamentiss faiz malandris se pirulitá. Sapien in monti ' +
      'palavris qui num significa nadis i pareci latim.',
      birth: new Date(),
      range: [
        '2018-09-06T03:00:00.000Z',
        '2018-10-08T03:00:00.000Z'
      ],
      custom_amount: 456
    });
  }

  public observableSource(keyword: any): Observable<any[]> {
    const url = `https://restcountries.eu/rest/v2/name/${keyword}`;
    if (keyword) {
      return this.http.get(url)
        .pipe(
          map((res) => res as any[])
        );
    } else {
      return of([]);
    }
  }

  public observableSourceByPlaceId(keyword: any): Observable<any> {
    return of({
      'alpha3Code': 'BRA',
      'name': 'Brazil'
    }).pipe(delay(300));
  }
}

Custom Field

It's possible to create your own field template and set it on dynamic field list through CustomField

Example: my-component.html

<ng-template #customField let-customControl="control" let-isEditing="isEditing">
  <div class="input-group">
    <div class="input-group-addon">$</div>
    <input type="number"
      [formControl]="customControl"
      [attr.disabled]="!isEditing || null" 
      class="form-control"
      style="text-align:right" 
      id="exampleInputAmount" 
      placeholder="Amount" />
    <div class="input-group-addon">.00</div>
  </div>
</ng-template>

my-component.ts


  @ViewChild('customField') customFieldTmpl: TemplateRef<any>;
  public fields: DynamicField[];
  ...
  ngOnInit() {
    this.fields = [
      new CustomField({
        key: 'custom_amount',
        label: 'Custom Field Amount',
        tmpl: this.customFieldTmpl
      }),
    ];
  }

Typed key validation

Now it is possible to define a type that will be used to validate the key field values

Example:


class Address {
  street: string;
  city: string;
}

class User {
  name: string;
  email: string;
  address: Address;
}

export class UserComponent {

  public fields: DynamicField[];

  constructor() {

    this.fields = [
      new TextField<User>({
        key: 'name',
        label: 'Name',
        validators: [
          Validators.minLength(3)
        ]
      }),
      new TextField<User>({
        key: 'email',
        label: 'E-mail',
        validators: [
          Validators.required,
          Validators.email
        ]
      }),
      new NestedFormGroup<User>({
        key: 'address',
        fields: [
          new TextField<Address>({
            key: 'street',
            label: 'Street',
          }),
          new TextField<Address>({
            key: 'city',
            label: 'City',
          }),
        ]
      })
    ];
  }
}

In the example, the TextField is created specialized whit the User class

new TextField<User>({

the TextField key attribute will accept only keys of the class User (i.e. 'name', 'email', 'address'), and show and error if any other value is provided.

On change function

You can add a parameter onChangeFn on your DynamicField fields. This parameter receives a anonymous function, just like in the following example:

new TextField({
  key: 'phrase',
  label: 'Write a phrase',
  onChangeFn: (value: string) => {
    // push new typed value to a subject
    this.onchangefnSubject.next(value);
  }
}),

This parameter can be used to execute async functions that depends on user input or push values of a field to a Subject() just like is shown above.

Locales

DatepickerField can use different locales.

It's possible to change a locale by calling use method of BsLocaleService, list of available locales is in dropdown below.

To use a different locale, you have to import it from ngx-bootstrap/chronos first, then define it in your @NgModule using function defineLocale

Example:

import { defineLocale, LocaleData } from 'ngx-bootstrap/chronos';
import { ptBrLocale } from 'ngx-bootstrap/locale';
defineLocale(ptBrLocale.abbr, ptBrLocale);

...

export class AppModule {

  constructor(bsLocaleService: BsLocaleService) {
    // aplly locale
    bsLocaleService.use(ptBrLocale.abbr);
  }
}

Demo source code load locales.

Development

After cloning of this repository will be necessary run once npm run setup, so will be able to run npm run demo to start the demo locally

For more information view common development activities on https://github.com/tinesoft/generator-ngx-library#development

License

Copyright (c) 2018 ESSS. Licensed under the MIT License (MIT)