npm package: @silmar/ng-core
Description: [![npm (scoped)](https://img.shields.io/npm/v/@silmar/ng-core.svg)](https://www.npmjs.com/package/@silmar/ng-core) [![pipeline status](https://gitlab.com/etg-public/silmar-ng-core/badges/master/pipeline.svg)](https://gitlab.com/etg-public/silmar-core/comm
Author: @ETG Authors
Latest version: 12.0.1

# SilmarNgCore

[![npm (scoped)](https://img.shields.io/npm/v/@silmar/ng-core.svg)](https://www.npmjs.com/package/@silmar/ng-core)
[![pipeline status](https://gitlab.com/etg-public/silmar-ng-core/badges/master/pipeline.svg)](https://gitlab.com/etg-public/silmar-core/commits/master)
[![NPM](https://img.shields.io/npm/l/@silmar/ng-core.svg?style=flat-square)](https://www.npmjs.com/package/@silmar/ng-core)

[Checkout the demo/docs page](https://etg-public.gitlab.io/silmar-ng-core)

A bunch of useful Angular4+ pipes, directives and components (*maybe mainly useful for our company but anyhow*). Feel free to dissect and use as you wish.

We are using parts of [date-fns](https://date-fns.org/) and [flag-icon-css](http://flag-icon-css.lip.is/), so thanks guys.

### Install
```
npm i @silmar/ng-core
// or
npm i @silmar/ng-core
```

### Documentation (*kind of...*)

#### Strings module
##### capitalize pipe
```html
{{'capitalize pipe'|capitalize}}
{{'capitalize every word pipe'|capitalize:true}}
```

##### highlight pipe
```html
<span [innerHtml]="'Highlight within text pipe' | highlight:'within'"></span>
```

##### join pipe
```html
{{ ['Eiffel Tower', 'Paris', 'France'] | join:', '}}
```

##### repeat pipe/directive
```html
{{'★' | repeat:5}}
<i class="fa fa-star" *siRepeat="5"></i>
```

##### sprintf pipe
```html
{{"The quick :color fox jumps over the lazy :animal" | sprintf:{color:"brown", animal:"dog"} }}
```

##### trim pipe
```html
{{' John Doe ' | trim}}
{{'+123456987' | trim:'+'}}
```
##### truncate pipe
```html
{{'Chuck Norris counted to infinity... twice.' | truncate:15}}
result: Chuck Norris co...

{{'Chuck Norris counted to infinity... twice.' | truncate:3:'...':true}}
result: Chuck Norris counted...
```

#### Arrays module
##### filter pipe
```typescript
  filterAdults(item) {
    return item > 10;
  }
```
```html
{{[4, 13, 29, 5, 33, 0] | filter:filterAdults}}
```

##### shuffle pipe
```html
{{[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | shuffle}}
```

#### ValidatorsModule
Includes custom validators, directives and error component

##### FormErrorComponent
Show error message on invalid input

**selector**: `si-form-error`

**example**
```html
<input name="username" [(ngModel)]="someProp" required minlegth="5" #username="ngModel" />
<si-form-error [input]="username"
    [messages]="{'required':'This field is required!','minlength':'Enter at least :requiredLength characters'}">
</si-form-error>
```

##### RequiredInputDirective
Add `*` symbol on corresponding label and change color if invalid.  
Just include the `ValidatorsModule` and the directive will catch all labels assigned to required fields.

**example**
```html
<label for="username">Username</label>
<input id="username" name="username" [(ngModel)]="prop" required /> 
```

##### MaxValidator
Validate maximum numerical value

**example**
```html
<input type="number" [max]="4" />
```

##### MinValidator
Validate minimum numerical value

**example**
```html
<input type="number" [min]="4" />
```

##### RequiredIfValidator
Validate a required control if another one exists and is not empty.

**example** Phone` is REQUIRED if `extension` is preset
```html
<input type="text" name="phone" [(ngModel)]="user.phone" siRequiredIf="extension"/>
<input type="text" name="extension" [(ngModel)]="user.extension" siRequiredIf="phone" reverse="true"/>
```

##### RequiredIfEmptyValidator
Validate a control as required if another one does not exists or is empty.

**example** `Phone` is REQUIRED if `email` is empty:
```html
<input type="text" name="phone" [(ngModel)]="user.phone" siRequiredIfEmpty="email"/>
<input type="text" name="email" [(ngModel)]="user.email" siRequiredIfEmpty="phone" reverse="true"/>
```

#### Geo Module

Angular 2+ component for embedding google maps, using flags etc 

##### Flags
```
npm i flag-icon-css
npm i flag-icon-css
``` 

Edit `.angular-cli.json` and add in the `styles` array one of the two:
```json
[
  "../node_modules/flag-icon-css/sass/flag-icon.scss"
  //OR
  "../node_modules/flag-icon-css/css/flag-icon.min.css"
]
```
or add in your styles.scss
```scss
@import  "~flag-icon-css/sass/flag-icon.scss";
```
or add in your styles.css
```css
@import "../node_modules/flag-icon-css/css/flag-icon.min.css";
```

##### Embedded Map
Add `GeoModule` in root module with configuration
```typescript
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';


import { AppComponent } from './app.component';
import {GeoModule} from '../lib/src';


@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    GeoModule.forRoot({apiKey:'YOUR_GMAPS_API_KEY'}) // <-- ADD THIS
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
```

#### Seo Module
Angular 2+ services and components for SEO tracking tools

Import `SeoModule` `forRoot` providing seo configuration

```typescript
@NgModule({
 ...
  imports: [
    SeoModule.forRoot(seoConfig) // <-- ADD THIS
  ],
  ...
})
export class AppModule { }
```

##### Google Analytics Service

###### Usage

Track pageview
```typescript
gaSvc.pageView('/products', 'Page Title');
// OR
gaSvc.pageView('/products');
```

Track events
```typescript
gaSvc.sendEvent('Buttons', 'Click', 'Buy now', '1200');
```

Track timing events
```typescript
if (window && window.performance) {
  // Gets the number of milliseconds since page load
  // (and rounds the result since the value must be an integer).
  var timeSincePageLoad = Math.round(performance.now());

  // Sends the timing hit to Google Analytics.
  gaSvc.sendTiming('JS Dependencies', 'load', timeSincePageLoad);
}
```

###### Configuration
| Option | Description | Default |
|------|-----|-----|
| isInProdMode | Whether app is in production mode | FALSE |
| trackInNonProd | Should track in non production mode | TRUE |

#### Storage Module
Abstraction over local storage, session storage, cookie and memory storage with Universal support.

###### Storages
* LocalStorage
* SessionStorage
* CookieStorage
* MemoryStorage

###### Usage
```typescript
construct(storage: LocalStorage) {
 storage.setItem('foo', 'bar'); // set a scalar value
 storage.getItem('foo');        // get a scalar value
 storage.setObject('foo-obj');  // set an object or array value
 storage.getObject('foo-obj');  // get an object or array value
 storage.removeItem('foo');     // remove value by key
 storage.key(3);                // returns the name of the nth key in the storage
 storage.clear();               // wipe all values
 storage.length;                // count of keys in storage 
}
```

CookieStorage has an extra arguments for some of the methods:

Arguments:
* removeItem

| arg | type | description |
|------|-----|-----|
| key | string | Key |
| domain | string | Domain |
| path | string | Path |

* setItem

| arg | type | description |
|------|-----|-----|
| key | string | Key |
| value | string | Value |
| ttl | number | Validity in seconds (dimension may be changed via `dimension`) |
| dimension | string | `minutes`, `hours`, `days` or leave empty for `seconds` |
| domain | string | Domain |
| path | string | Path |
| secure | boolean | Adds secure cookie flag |
 
* setObject (see setItem)

```typescript
construct(storage: CookieStorage) {
  storage.removeItem('foo', 'domain.com', '/path');
  storage.setItem('foo', 'bar', 2, 'days', 'domain.com', '/path', true);
}
```