Angular svg as template for component shown as text - javascript

I'm currently trying to display a svg icon by using Angular component like this
import {Component} from '#angular/core';
#Component({
selector: 'app-profile-icon',
templateUrl: './profile-icon.svg',
styleUrls: ['./profile-icon.component.scss'],
})
export class ProfleIconComponent {
}
An I call this element in a html file. This component is instantiated but with no svg content. Just the path of the svg with some random text.
Is some Angular configuration I missed? Because it works fine if I wrote like this without the component, or just copy paste the svg content to a html template.
<img src='./profile-icon.svg'>
Thanks you very much.

Add assets folder to your angular.json.
"assets": [
"src/assets"
],
Then access the SVG icon in the HTML template like below -
<img src="/assets/profile-icon.svg">

This question is very old, but if somebody else falls here, I've got the same problem trying to show a big SVG file, just got the name of the SVG file in text.
Not sure, but probably because I'm using an old version (Angular 6).
Solved by renaming the svg file as html and changing the templateUrlto point the renamed html file.

Related

craco-plugin-scoped-css not working on react.js css

I m using react.js
My problem is that css on one component is coming on other component. so to try and fix it I tried using craco-plugin-scoped-css
craco-plugin-scoped-css is not working for some reason for me, heres what I did to install:
I first ran npm i craco-plugin-scoped-css
then created craco.config.js inside src folder and pasted:
module.exports = {
plugins: [
{
plugin: require('craco-plugin-scoped-css')
}
]
}
I renamed my home.css and contact.css to home.scoped.css and contact.scoped.css, but for some reason, css is contact.scoped.css is overlaping css on home.scoped.css
I tried to add craco-plugin-scoped-css outside of src which didnt work
Edit: I would like to share that There is a main file, a header and a footer a main page file. and I m trying to add the styles to main file but instead its syncing the classes from footer file

How to read HTML file into component in Angular

I am trying to create dynamic print template in Angular 12. I would like to fill the html body text dynamically based on the parameter passed on the selector used in the main component view. Print layout component is in Shared module and both the html templates are in app folder.
My requirements are:
I want to read the html file in the print layout component and
display it. I don't want to create component and render the
component in the print layout
I don't want to save the html file in the backend and trigger api to
fetch the html
print-layout.component.html
<div [innerHtml]="myTemplate"></div>
print-layout.component.ts
#Component({
selector: 'app-print-layout',
templateUrl: './print-layout.component.html',
styleUrls: ['./print-layout.component.scss']
})
export class PrintLayoutComponent implements OnInit{
#Input() modalID;
myTemplate;
ngOnInit() {
if(modalID == "1")
template = '../../app/tools/test/test-message1.html';
else (modalID == "2")
template = '../../app/tools/test/test-message2.html';
}
}
Also, I have gone through this solution Read HTML File into template in Angular 2? where they are creating component dynamically from main component file.
Is there any way to display html template file in the main component without creating component. Also, please suggest is it the right way to display html content without creating component in Angular...?
You can try to use iframe tag inside the print-layout.component.html like this
<iframe [src]="myTemplate"></iframe>
Obviously on ngOnInit() you need to assign path to myTemplate as same name to use in html

Using Font-awesome icons dynamically does not work with the SVG & JS implementation

So I'm using font-awesome's new JS&SVG implementation for their v5 icons. The implementation works fine, for icons (e.g. <i class='fas fa-home'></i>) that are present in the DOM at page load and the <i> tag is replaced with an <svg> tag.
Problem occurs when I load in some HTML server-side and insert it into the DOM, the <i> tags does not converted and thus no icon is displayed. I cannot find any method that I can use in my JS (like after the content is added to the DOM) to "reinstance" the JS implementation to load the SVG icons in place.
Has anyone come by this problem?
I'm using it like this and working well even on "after-loaded" html parts.
My fontawesome.js is looking like this:
import { library, dom, config } from '#fortawesome/fontawesome-svg-core';
config.autoReplaceSvg = true;
config.observeMutations = true; // <- this is what you need the most
import { faUser } from '#fortawesome/free-solid-svg-icons/faUser';
import { faFacebook } from '#fortawesome/free-brands-svg-icons/faFacebook';
library.add(faUser, faFacebook);
// And this is important too
// Replace any existing <i> tags with <svg> and set up a MutationObserver to
// continue doing this as the DOM changes.
dom.watch();
...and then I require this fontawesome.js in my vendors.js.
The reason why it is not working for you is mentioned in the documentation:
Different default configs
DOM watching is on by default when Font
Awesome is loaded from #fortawesome/fontawesome-free or
#fortawesome/fontawesome-pro but it's disabled for the
#fortawesome/fontawesome-svg-core.
Here are some useful links on the configuration, watching the dom and svg-javascript-core

SVG flickering in Chrome in Angular app with data update

I'm working on an app in Angular 4. In one view I'm using some svgs placed between data that is retrieved from API request. It looks like this:
<div>
<div>
<svg><use xlink:href="./assets/svg/machine.svg#message-icon"></use></svg>
</div>
<div>{{machine.state}}</div>
<div>
<svg><use xlink:href="./assets/svg/machine.svg#settings-icon"></use></svg>
</div>
</div>
All svgs are put in one file (machine.svg), and are defined in < symbol > tags with ids.
Now my problem is when I set interval every 2 seconds to update data from API request, my svg icons appear to flicker with every update, but it only happens in Chrome.
I've checked the network logs and it seems that whole svg file is downloaded with every API request:
While in Mozilla everything works fine, svg is downloaded only once:
I've tried to put svg in < object > tag, but the requests are even more numerous. Putting every single svg in < img > tag seemed to resolve the problem with requests, but I would prefer to be in control of "fill" property. Putting the whole svg directly on the page solved problem too, but it doesn't seem to be a clean solution.
My question is if there is a way to retrieve svg from a file without Chrome downloading it constantly?
Also faced with this situation, the easiest way for me is to create a separate shared component that contains all the icons I need and which takes the parameters I need. For me, this is the fastest and most flexible solution.
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'ngx-svg-icon',
templateUrl: './svg-icon.component.html',
styleUrls: ['./svg-icon.component.scss']
})
export class SvgIconComponent implements OnInit {
#Input() icon: string;
#Input() fill: string;
constructor() {}
ngOnInit() {}
}
Usage:
<ngx-svg-icon [icon]="'settings'" [fill]="'#ededed'"></ngx-svg-icon>
Try to configure your server to add cache-control headers to those requests. I have the same issue on localhost, but on my production server icons come with cache-control: max-age=172800 header and are not re-requested again.

FusionCharts not rendering properly when <base> tag included in HTML head

I'm using AngularJS and FusionCharts together in my web application. The upcoming release of AngularJS v1.3.0 will require there to be a <base> tag in the HTML head, so as to resolve all relative links, regardless of where the app is hosted in the site's directory.
When including the <base> tag with the latest version of FusionCharts (currently v3.4.0), the 3D charts do not render properly. For example, a 3D pie chart appears and has rotation and clickable slices, as well as tooltips and color on the inside edges of the slices. However, the entire outer color is black.
Excluding the <base> tag causes the chart to look and behave normally.
Does anyone have any idea how to resolve this? Unfortunately, I don't own the source code, otherwise I'd hack at it myself.
Here's the link to the non-working jsFiddle: http://jsfiddle.net/aaronaudic/59Bmf/207
SOLUTION:
I originally awarded the correct solution to #pankaj, because his solution of simply adding the following line at page load seemed to fix the problem:
document.getElementsByTagName("base")[0].setAttribute("href", window.location.pathname+window.location.search);
However, this only works if the charts are on the initially-loaded page (when user navigates directly to page with the charts); when navigating to the page by way of something like ui-router, I was still seeing black.
The correct answer is from #Shamasis. Adding the following to the page load will fix the issue application-wide:
eve.on('raphael.new', function () {
this.raphael._url = this.raphael._g.win.location.href.replace(/#.*?$/, '');
});
His original caveat mentioned that the export functions may be hampered from the Cloud, and this may be (I don't export from the cloud). However, exporting locally, as can be observed in this jsFiddle, works perfectly well: http://jsfiddle.net/aaronaudic/Gs6sN/14
My base tag, in the head of the page, is simply:
<base href="/">
The issue is not primarily with FusionCharts - it is a generic SVG issue. In SVG, when gradient colour is applied on an element, it actually "refers" to another gradient element on the page. This is somewhat similar to how links can refer to hashtags using <a id="hash" /> on a page.
Now, when you are setting a <base> to the page, the references are going haywire. The gradients now refer to an element with URL as provided in your base tag.
One way to fix this is to access the internal graphics renderer and hard-set the URL to the absolute location of the page. The way to do that would be to access RedRaphael object within FusionCharts core and set the _url variable for the same.
The following code should do it for you.
eve.on('raphael.new', function () {
this.raphael._url = this.raphael._g.win.location.href.replace(/#.*?$/, '');
});
The only caveat is that specifying absolute URL as reference to gradient elements does not work in some older browsers (I'm not sure exactly - could be Safari 5 or FF 3.0). It may also have some negative impact while exporting FusionCharts as image - the relative URLS will be invalidated when the SVG is rasterised on FusionCharts Cloud Export servers.
I'm fixing this problem on Angular 7 and FusionCharts here, FusionCharts.options.SVGDefinitionURL='absolute' didn't help much. It fixed Safari, but just on the first route with pie charts. Any further navigation would break again, and now Chrome is also broken after navigating.
I considered the Raphael workaround, but couldn't find a way to get a eve reference, so I decided to try removing the baseHref, which seems to be the "cause" of the problem.
Here is what I did:
Removed the base from index.html (left it there commented so everyone knows why) and also put the favicon as an absolute resource.
<!-- Configuring deployUrl and APP_BASE_HREF in the main module,
see [[this stackoverflow link]] -->
<!--<base href="/">-->
...
<link rel="icon" type="image/x-icon" href="/favicon.ico">
Configured deployUrl on angular.json (see this question)
I'm using multiple projects layout here, so for me it was added on path projects.my-project.architect.build.options.deployUrl, should be simpler in the default project.
"deployUrl": "/",
Configured my app module to inject the configuration for the router (docs)
import { APP_BASE_HREF } from '#angular/common'
...
#NgModule({
...
providers: [
{ provide: APP_BASE_HREF, useValue: '/' },
...
],
...
})
Everything looks good now, all browsers work, Angular router seems to be working fine as well.
TLDR: set FusionCharts.options.SVGDefinitionURL='absolute'; in your JavaScript to fix this problem
Detailed:
There is a FusionChart solution to this.
The problem you mention comes from SVG using relative references to things like gradients, resolving incorrectly due to the tag being present.
This problem is described on https://github.com/angular/angular.js/issues/8934.
One possible solution would be setting $locationProvider.html5Mode({ enabled: true, requireBase: false }); and using absolute paths.
Although this does solve the problem there is a solution by FusionCharts by setting FusionCharts.options.SVGDefinitionURL='absolute'; in your JavaScript. (http://www.fusioncharts.com/dev/api/fusioncharts/fusioncharts-properties.html#FusionCharts.options-attributes-SVGDefinitionURL)
You can simply set absolute url in base tag
document.getElementsByTagName("base")[0].setAttribute("href", window.location.pathname+window.location.search);
Here is jsfiddle: http://jsfiddle.net/59Bmf/208/
In angular you can use bind the url using a property in controller.
$scope.absurl=$location.absUrl()
And use it inside view
<base href="{{absurl}}">
#Shamasis Bhattacharya saved my life.
This solution solved my problem with fusioncharts in Ionic4+Angular8 project.
This is what I did in app.component.ts component:
import { Component } from '#angular/core';
import { Platform } from '#ionic/angular';
declare var eve;
#Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.scss']
})
export class AppComponent {
constructor() {
this.initializeApp();
}
initializeApp() {
this.platform.ready().then(() => {
eve.on('raphael.new', function() {
this.raphael._url = this.raphael._g.win.location.href.replace(/#.*?$/, '');
});
});
}
}

Categories