Reputation: 10828
I'm trying to load svgs inline with angular 7.
So far I tried:
import icon = require('./icon.svg');
results in icon.svg
due to file-loader
import icon = require('raw-loader?!./icon.svg');
results in __webpack_public_path__ + "icon.svg";
which is the same as:
import * as icon3 from 'raw-loader?!./icon.svg';
and
import icon4 from 'raw-loader?!./icon.svg';
will become undefined.
However renaming the icon.svg
in something like icon.foo
and then loading the icon with:
import * as icon from 'raw-loader?!./icon.foo';
and the appropriate type in typings.d.ts
results in the anticipated behavior and the variable icon holds the inlined content.
For me it seams like the file-loader somehow precedes the raw loader. Changing node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/common.js
to load svgs like htmls in the rules works as well. But this is not a way to go.
Any ideas?
Upvotes: 4
Views: 8618
Reputation: 1756
If you do not want to use any additional loaders, you can actually use SVG files as templates for components:
@Component({
selector: 'app-some-svg',
templateUrl: './some-svg.svg',
styleUrls: ['./some-svg.scss'],
})
If you want to be able to control the SVG from the outside (for example because you want to change colors), you can use @HostBinding
for that.
Example: Let's try to control the fill color of a svg.
Given the following SVG:
<svg xmlns="http://www.w3.org/2000/svg" width="54" height="54" viewBox="0 0 54 54">
<circle class="circle" cx="27" cy="27" r="27" fill="#7df481" />
</svg>
You can write the controller for it like so:
type FlexibleFillColor = 'green' | 'red';
@Component({
selector: 'app-flexible-fill',
templateUrl: './flexible-fill.svg',
styleUrls: ['./flexible-fill.scss'],
})
export class FlexibleFillComponent implements OnInit, OnChanges {
@Input() color: FlexibleFillColor = 'grey';
@HostBinding('class') className = this.color;
ngOnInit() {
this.className = this.color;
}
ngOnChanges(changes: SimpleChanges) {
this.className = changes.color.currentValue as FlexibleFillColor;
}
}
Since @HostBinding
is not automatically updated when the @Input
value changes, the OnChanges
interface is needed, where the value can then be updated
The SCSS for it would look something like this:
:host {
&.green {
.circle {
fill: green;
}
}
&.red {
.circle {
fill: red;
}
}
svg {
width: 32px;
height: 32px;
margin: 1.5em 0 0 0.5em;
}
}
If necessary you can also use all this to show and hide elements in the SVG
Upvotes: 0
Reputation: 10828
Because the rule is already defined, it has to be overruled by putting two !!
at the beginning of the loader:
import icon = require('!!raw-loader?!./icon.svg');
ADDITION 2021
it should work without require ... do not forget the typings.d.ts
import icon from '!!raw-loader?!./icon.svg';
See: https://webpack.js.org/loaders/raw-loader/ at the very bottom
Beware, if you already define loader(s) for extension(s) in webpack.config.js you should use:
'!!raw-loader!./file.css'; // Adding
!!
to a request will disable all loaders specified in the configuration
Upvotes: 12
Reputation: 2537
I would suggest you to create a .ts
file
my-svg.ts
export const mySVG = `<svg></svg>`;
Then you can import it normally
import {mySVG} from 'path/to/file/my-svg.ts'
Upvotes: 1