Skip to content

Commit

Permalink
Merge pull request #46 from czeckd/stringloader
Browse files Browse the repository at this point in the history
Update for Angular 6 and add function to load SVG from string.
  • Loading branch information
czeckd authored May 6, 2018
2 parents 18c43d6 + 0cf3c5f commit db6bbec
Show file tree
Hide file tree
Showing 10 changed files with 222 additions and 139 deletions.
41 changes: 25 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,25 @@
Angular SVG Icon
=========

The **angular-svg-icon** is an Angular 4.3+ service and component that provides a
The **angular-svg-icon** is an Angular 6 service and component that provides a
means to inline SVG files to allow for them to be easily styled by CSS and code.

The service provides an icon registery that loads and caches a SVG indexed by
its url. The component is responsible for displaying the SVG. After getting the
svg from the registry it clones the `SVGElement` and the SVG to the component's
inner HTML.

A [working demo](http://czeckd.github.io/angular-svg-icon/demo/) shows solution in action.
This [demo](http://czeckd.github.io/angular-svg-icon/demo/) shows this module in action.

## How to use?
```
$ npm i angular-svg-icon --save
```
(**Note:** For use Angular 2.4 through Angular 4.2, please install [email protected]
and see the module's accompanying README.md for instructions.)
**Note on earlier versions of ngx:**
- For Angular 4.3 through Angular 5.x, use [email protected]
- For Angular 2.4 through Angular 4.2, use [email protected]

See the module's accompanying README.md for instructions.

## Integration

Expand All @@ -30,8 +33,8 @@ import { HttpClientModule } from '@angular/common/http';
import { AngularSvgIconModule } from 'angular-svg-icon';

@NgModule({
imports: [ HttpClientModule, AngularSvgIconModule ],
...
imports: [ HttpClientModule, AngularSvgIconModule ],
...
})
export class AppModule {}
```
Expand Down Expand Up @@ -60,23 +63,29 @@ Include the ``private iconReg:SvgIconRegistryService`` in the constructor:
constructor(private iconReg:SvgIconRegistryService) { }
```

The registry has two public functions: `loadSvg(string)` and `unloadSvg(string)`.

To preload a svg file into the registry:
The registry has three public functions: `loadSvg(string)`, `addSvg(string, string)`, and `unloadSvg(string)`.

To preload a SVG file from a URL into the registry:
```typescript
{
...
this.iconReg.loadSvg('foo.svg');
...
this.iconReg.loadSvg('foo.svg');
}
```

To unload a svg from the registry.

To add a SVG from a sting:
```typescript
{
...
this.iconReg.addSvg('box',
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10"><path d="M1 1 L1 9 L9 9 L9 1 Z"/></svg>'
);
}
```
To unload a SVG from the registry.
```typescript
{
...
this.iconReg.unloadSvg('foo.svg');
...
this.iconReg.unloadSvg('foo.svg');
}
```

Expand Down
2 changes: 1 addition & 1 deletion app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { NgModule } from '@angular/core';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
Expand Down
2 changes: 1 addition & 1 deletion app/demo-app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export class DemoAppComponent {
constructor(private registry:SvgIconRegistryService) {
}

getStyle(): string {
getStyle() :string {
return JSON.stringify(this.getNgStyle()).replace(/\"/g, '\'');
}

Expand Down
114 changes: 61 additions & 53 deletions demo/systemjs.config.js
Original file line number Diff line number Diff line change
@@ -1,57 +1,65 @@
(function(global) {

var ngVer = '@5.0.0';

var paths = {
'npm:' : 'https://unpkg.com/'
}

// map tells the System loader where to look for things
var map = {
'app': 'app',
'angular-svg-icon': 'lib',
'rxjs': 'npm:[email protected]',
'tslib': 'npm:[email protected]',
'typescript' : 'npm:[email protected]/lib/typescript.js',

'@angular/core': 'npm:@angular/core/bundles/core.umd.js',
'@angular/common': 'npm:@angular/common/bundles/common.umd.js',
'@angular/common/http': 'npm:@angular/common/bundles/common-http.umd.js',
'@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
'@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
'@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js'
};

// packages tells the System loader how to load when no filename and/or no extension
var packages = {
'app': { main: 'main.ts', defaultExtension: 'ts' },
'angular-svg-icon': { main: 'index.ts', defaultExtension: 'ts' },

'rxjs': { defaultExtension: 'js' },
'tslib': { main: 'tslib.js', defaultExtension: 'js' }
};

var config = {
transpiler: 'typescript',
typescriptOptions: {
sourceMap: true,
emitDecoratorMetadata: true,
experimentalDecorators: true
},
meta: {
typescript: { exports: 'ts' }
},
paths: paths,
map: map,
packages: packages
}

// filterSystemConfig - index.html's chance to modify config before it is registered.
if (global.filterSystemConfig) {
global.filterSystemConfig(config);
}

System.config(config);
var ngVer = '@6.0.0';

var paths = {
'npm:' : 'https://unpkg.com/'
}

// map tells the System loader where to look for things
var map = {
'app': 'app',
'angular-svg-icon': 'lib',
'rxjs': 'npm:[email protected]',
'rxjs/operators': 'npm:[email protected]/operators',
'tslib': 'npm:[email protected]',
'typescript' : 'npm:[email protected]/lib/typescript.js',

'@angular/core': 'npm:@angular/core/bundles/core.umd.js',
'@angular/common': 'npm:@angular/common/bundles/common.umd.js',
'@angular/common/http': 'npm:@angular/common/bundles/common-http.umd.js',
'@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
'@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
'@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js'
};

// packages tells the System loader how to load when no filename and/or no extension
var packages = {
'app': { main: 'main.ts', defaultExtension: 'ts' },
'angular-svg-icon': { main: 'index.ts', defaultExtension: 'ts' },

'rxjs': {
'main': 'index.js',
'defaultExtension': 'js'
},
'rxjs/operators': {
'main': 'index.js',
'defaultExtension': 'js'
},
'tslib': { main: 'tslib.js', defaultExtension: 'js' }
};

var config = {
transpiler: 'typescript',
typescriptOptions: {
sourceMap: true,
emitDecoratorMetadata: true,
experimentalDecorators: true
},
meta: {
typescript: { exports: 'ts' }
},
paths: paths,
map: map,
packages: packages
}

// filterSystemConfig - index.html's chance to modify config before it is registered.
if (global.filterSystemConfig) {
global.filterSystemConfig(config);
}

System.config(config);

})(this);
10 changes: 5 additions & 5 deletions lib/package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"$schema": "../../node_modules/ng-packagr/package.schema.json",
"name": "angular-svg-icon",
"description": "Angular 5 component for inlining SVGs allowing them to be easily styled with CSS.",
"version": "5.1.1",
"description": "Angular 6 component for inlining SVGs allowing them to be easily styled with CSS.",
"version": "6.0.0",
"repository": {
"type": "git",
"url": "https://github.com/czeckd/angular-svg-icon.git"
Expand All @@ -15,9 +15,9 @@
"icon"
],
"peerDependencies": {
"@angular/core": "^4.3.0 || ^5.0.0 || ^6.0.0",
"@angular/common": "^4.3.0 || ^5.0.0 || ^6.0.0",
"rxjs": "^5.5.2"
"@angular/core": "^6.0.0",
"@angular/common": "^6.0.0",
"rxjs": "^6.0.0"
},
"ngPackage": {
"lib": {
Expand Down
52 changes: 26 additions & 26 deletions lib/src/svg-icon-registry.service.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
import { Injectable, Optional, SkipSelf } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { Observable } from 'rxjs/Observable';

import 'rxjs/add/observable/of';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/finally';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/share';
import 'rxjs/add/observable/throw';

import { Observable, of as observableOf, throwError as observableThrowError } from 'rxjs';
import { map, tap, catchError, finalize, share } from 'rxjs/operators';

@Injectable()
export class SvgIconRegistryService {
Expand All @@ -21,42 +13,50 @@ export class SvgIconRegistryService {
constructor(private http:HttpClient) {
}

loadSvg(url:string): Observable<SVGElement> {
/** Add a SVG to the registry by passing a name and the SVG. */
addSvg(name:string, data:string) {
if (!this.iconsByUrl.has(name)) {
const div = document.createElement('DIV');
div.innerHTML = data;
const svg = <SVGElement>div.querySelector('svg');
this.iconsByUrl.set(name, svg);
}
}

/** Load a SVG to the registry from a URL. */
loadSvg(url:string) : Observable<SVGElement> {

if (this.iconsByUrl.has(url)) {
return Observable.of(this.iconsByUrl.get(url));
return observableOf(this.iconsByUrl.get(url));
} else if (this.iconsLoadingByUrl.has(url)) {
return this.iconsLoadingByUrl.get(url);
} else {
const o = <Observable<SVGElement>> this.http.get(url, { responseType: 'text' })
.map(svg => {
const o = <Observable<SVGElement>> this.http.get(url, { responseType: 'text' }).pipe(
map(svg => {
const div = document.createElement('DIV');
div.innerHTML = svg;
return <SVGElement>div.querySelector('svg');
})
.do(svg => {
this.iconsByUrl.set(url, svg);
})
.catch(err => {
}),
tap (svg => this.iconsByUrl.set(url, svg) ),
catchError(err => {
console.error(err);
return Observable.throw(err);
})
.finally(() => {
this.iconsLoadingByUrl.delete(url);
})
.share();
return observableThrowError(err);
}),
finalize(() => this.iconsLoadingByUrl.delete(url) ),
share()
);

this.iconsLoadingByUrl.set(url, o);
return o;
}
}

/** Remove a SVG from the registry by URL (or name). */
unloadSvg(url:string) {
if (this.iconsByUrl.has(url)) {
this.iconsByUrl.delete(url);
}
}

}

export function SVG_ICON_REGISTRY_PROVIDER_FACTORY(parentRegistry:SvgIconRegistryService, http:HttpClient) {
Expand Down
10 changes: 4 additions & 6 deletions lib/src/svg-icon.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Component, DoCheck, ElementRef, HostBinding, Input,
KeyValueChangeRecord, KeyValueChanges, KeyValueDiffer, KeyValueDiffers,
OnChanges, OnDestroy, OnInit, Renderer2, SimpleChange } from '@angular/core';

import { Subscription } from 'rxjs/Subscription';
import { Subscription } from 'rxjs';

import { SvgIconRegistryService } from './svg-icon-registry.service';

Expand All @@ -29,7 +29,7 @@ export class SvgIconComponent implements OnInit, OnDestroy, OnChanges, DoCheck {
private svg:SVGElement;
private icnSub:Subscription;
private differ:KeyValueDiffer<string, string|number>;
private _svgStyle: {[key: string] : string};
private _svgStyle: {[key:string]:string};

constructor(private element:ElementRef,
private differs:KeyValueDiffers,
Expand Down Expand Up @@ -82,10 +82,8 @@ export class SvgIconComponent implements OnInit, OnDestroy, OnChanges, DoCheck {
}

private resetDiffer() {
if (this._svgStyle) {
if (!this.differ) {
this.differ = this.differs.find(this._svgStyle).create();
}
if (this._svgStyle && !this.differ) {
this.differ = this.differs.find(this._svgStyle).create();
}
}

Expand Down
Loading

0 comments on commit db6bbec

Please sign in to comment.