I am trying to add tracking script in .js file to my angular 12 application.
(function() {
var ds = document.getElementsByTagName("script")[0];
var dm = document.createElement("img");
dm.width = 1;
dm.height = 1;
dm.alt = " ";
dm.src = "https://example.com/url=" + window.location.href;
ds.parentNode.insertBefore(dm, ds);
})();
Script fires properly on the first page, but doesn't fire on navigating to another page on my website. When i check in elements window.location.href is not changing for the new page. It is because of SPA. How can i get latest location on all pages and script to fire on all pages
You could do it the Angular way, although idk if that will work.
You can go into your root component (should be AppComponent), and simply throw this inside the constructor or ngOnInit()
#Component({
...
})
export class AppComponent {
constructor(router: Router) {
router.events.pipe(
filter(route => route instanceof NavigationEnd),
concatMap((route) => ajax('https://example.com/url=' + route.url)),
).subscribe();
}
}
Unless you need your tracker to be an Img for some reason, or you get permission / CORS issues. This should work nicely
Related
I want to add conditions to load this script in the head tag. I need to check if the URL is from our live domain then only it runs otherwise not. I could simply add this script to the head if there was no condition requirement. How I can inject this script in the head tag in angular?
For eg:
window.origin == 'https://www.stackoverflow.com' then inject this script into the head tag otherwise not.
<script>
(function(h,o,t,j,a,r){
h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
h._hjSettings={hjid:*******,hjsv:*};
a=o.getElementsByTagName('head')[0];
r=o.createElement('script');r.async=1;
r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;
a.appendChild(r);
})(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');
</script>
You can handle this in one of your components, preferably in app.component. You could check the URL of course but more elegant would be to have some flag like enableHotjarTracking in your environment.ts file and set it to true only for your production environment.
Then you could call it as follows in your app.component.ts
import { environment } from './environments/environment';
import { DOCUMENT } from '#angular/common';
...
// inject document wrapper
constructor(
#Inject(DOCUMENT) private document: Document,
){}
ngAfterContentInit() {
if(environment.enableHotjarTracking) {
((h, o, t, j, a, r) => {
h.hj =
h.hj ||
/* tslint:disable:only-arrow-functions */
function () {
(h.hj.q = h.hj.q || []).push(arguments);
};
h._hjSettings = { hjid: xxxx, hjsv: x };
a = o.getElementsByTagName('head')[0];
r = o.createElement('script');
r.async = 1;
r.src = t + h._hjSettings.hjid + j + h._hjSettings.hjsv;
a.appendChild(r);
})(window as any, this.document, 'https://static.hotjar.com/c/hotjar-', '.js?sv=');
}
}
You could also keep your hotjar id in the environment file.
I have an application where I need to print content that doesn't exist on the page but does exist in the angular template. In the template, I have a div with a click method that will accept an identifier, and then build an iframe based on the content of the id it received. The first snippet is what the clickable element looks like.
<div (click)="printButton('#printThis')" class="menu-item print-menu-item">Race {{ raceSelected?.raceNumber }}</div>
This code snippet is just a basic element with omitted private data. So it will just be an ng-template with an identifier and an iframe that I access from the method pasted below.
<ng-template #printThat>
// content that I will print but not important for this question
</ng-template>
<ng-template #printThis>
// content that I will print but not important for this question
</ng-template>
<iframe #iframe></iframe>
The last code snippet is the method on the component that builds the iframe and brings up the print dialog.
public async printButton(printMode: string): Promise<void> {
let printTemplate;
if (printMode === '#printThat') {
await this.getAllRacesForPrint()
printTemplate = this.printAll;
} else if (printMode === '#printThis') {
printTemplate = this.printSingleRace;
}
const iframe = this.iframe.nativeElement;
this.portalHost = new DomPortalOutlet(
iframe.contentDocument.body,
this.componentFactoryResolver,
this.appRef,
this.injector
);
const portal = new TemplatePortal(
printTemplate,
this.viewContainerRef
);
// Attach portal to host
this.portalHost.attach(portal);
iframe.contentWindow.onafterprint = () => {
iframe.contentDocument.body.innerHTML = '';
};
this._attachStyles(iframe.contentWindow);
iframe.contentWindow.print();
}
These two private functions are invoked in the method above to add the css to the iframe.
private _attachStyles(targetWindow: Window): void {
// Copy styles from parent window
document.querySelectorAll('style').forEach((htmlElement) => {
targetWindow.document.head.appendChild(htmlElement.cloneNode(true));
});
// Copy stylesheet link from parent window.
const styleSheetElement = this._getStyleSheetElement();
targetWindow.document.head.appendChild(styleSheetElement);
}
private _getStyleSheetElement(): HTMLLinkElement {
const styleSheetElement = document.createElement('link');
document.querySelectorAll('link').forEach((htmlElement) => {
if (htmlElement.rel === 'stylesheet') {
const absoluteUrl = new URL(htmlElement.href).href;
styleSheetElement.rel = 'stylesheet';
styleSheetElement.type = 'text/css';
styleSheetElement.href = absoluteUrl;
}
});
return styleSheetElement;
}
This works perfectly on all devices without a problem EXCEPT Android devices. On Android, the print dialog box comes up but the page is blank and has no content. Are there any good solutions for printing for Android that do not require bringing in a package or am I missing something here?
I am struggling with barba js v2. After ajaxtransition my main.js script stops working. I would like to reinit this script somehow ...
I have simple barba transition like this ->
import barba from "#barba/core"
class Transition {
constructor() {
// console.log(barba)
this.events()
}
events() {
// console.log("events")
barba.init({
transitions: [
{
name: "default-transition",
leave() {
// create your stunning leave animation here
console.log("leave")
},
enter() {
console.log("enter")
// create your amazing enter animation here
}
}
]
})
}
}
export default Transition
and at the and of </body> tag I have
<script src="js/main-dist.js"></script>
</body>
Inside this main-dist.js script there are couple of other scripts that are imported, for example a function that shows current date.
When I go to the page at first time, everything works fine, but when I go to another page and come back to the page that should display the current date, the date is not displaying because script is not initialized. It initalizes only on load not on ajaxload.
So my roadblock is to re-init somehow this script on ajaxload.
I figured it out. There is barba hook "after" that we can use in the transition script :)
barba.hooks.after(() => {
const bottomDOM = document.getElementsByTagName("body")[0]
const newScript = document.createElement("script")
const oldScript = document.querySelector(".main-script")
newScript.src = "js/main-dist.js"
newScript.className = "main-script"
oldScript.remove()
bottomDOM.appendChild(newScript)
})
I have a <script class="main-script" src="js/main-dist.js"></script> at the end of the DOM, and use barba.hook to remove it and then add it again
I'm trying to create a React Portal that when mounted, requires running a specific line to load an ActiveReports Designer component.
Here's is my portal code:
constructor(props: IWindowPortalProps) {
super(props);
this.containerEl = document.createElement('div'); // STEP 1: create an empty div
this.containerEl.id = 'designer-host';
this.containerEl.className = styles.designerHost;
this.externalWindow = null;
}
private copyStyles = (sourceDoc: Document, targetDoc: Document) => {
Array.from(sourceDoc.styleSheets).forEach(styleSheet => {
if (styleSheet.cssRules) { // true for inline styles
const newStyleEl = sourceDoc.createElement('style');
Array.from(styleSheet.cssRules).forEach(cssRule => {
newStyleEl.appendChild(sourceDoc.createTextNode(cssRule.cssText));
});
targetDoc.head.appendChild(newStyleEl);
} else if (styleSheet.href) { // true for stylesheets loaded from a URL
const newLinkEl = sourceDoc.createElement('link');
newLinkEl.rel = 'stylesheet';
newLinkEl.href = styleSheet.href;
targetDoc.head.appendChild(newLinkEl);
}
});
}
componentDidMount() {
this.externalWindow = window.open('', '', `height=${window.screen.height},width=${window.screen.width}`);
this.externalWindow.document.body.appendChild(this.containerEl);
this.externalWindow.document.title = 'A React portal window';
this.externalWindow.addEventListener('load', () => {
new Designer('#designer-host');
});
}
render() {
return ReactDOM.createPortal(null, this.containerEl);
}
However, when the new window loads, I get the error
Error: Cannot find the host element. at Function.<anonymous>
which indicates that the designer-host div is not there. I think the load function points to the main DOM and not the new window's one.
Alternatively, I tried appending the ActiveReports .js file by doing in my componentDidMount()
s.type = "text/javascript";
s.src = "../node_modules/#grapecity/activereports/lib/node_modules/#grapecity/ar-js-designer/index.js";
this.externalWindow.document.head.append(s);
and then assigning the Designer instantiation on the onLoad property of the element. Again with no luck.
Is there maybe a way I could run JavaScript a code after the portal has been loaded and point to that DOM?
Thank you
I work for GrapeCity. Could you please go to our support portal and submit a ticket. We will need a full code sample for us to be able to answer this question. Please give us a download link to the sample within the ticket.
Thank you
Long story short: I'm trying to add a front-end app to my portfolio site that uses React. I would like to integrate the app into the component as it renders. What I have setup right now is:
React component:
class Giphy extends Component {
constructor(props) {
super(props);
this.state = {src: 1}
this.handleClick = this.handleClick.bind(this);
}
handleClick(event) {
this.setState({src: event.target.value})
}
componentDidMount() {
const script = document.createElement("script");
script.type = "text/javascript";
script.src = "/scripts/giphyLogic.js";
document.body.appendChild(script);
}
...and a bunch of stuff in the render() method that doesn't matter
the script that I want to load involves a bunch of jQuery and simple JS stuff.
function displayButtons() {
$("#buttons").empty();
for (i=0; i<buttonArray.length; i++){
var a = $("<button type='button' class='btn btn-info'>");
var btnID = buttonArray[i].replace(/\s+/g, "+")
a.attr("id", btnID);
a.text(buttonArray[i]);
$("#buttons").append(a);
}
}
$("#addButton").on("click", function() {
var newButton = $(".form-control").val();
buttonArray.push(newButton);
displayButtons();
})
function displayGIFs() {
$(".btn-info").on("click", function() {
$("#resultsContainer").empty();
var subject = $(this).attr("id");
var giphyURL = "http://api.giphy.com/v1/gifs/search?q=" + subject + "&api_key=dc6zaTOxFJmzC";
$.ajax({ url: giphyURL, method: "GET"}).done(function(res) {
for (t=0; t<25; t++) {
var rating = res.data[t].rating;
var image = $("<img>");
var imgURLmoving = res.data[t].images.fixed_height.url;
var imgURLstill = res.data[t].images.fixed_height_still.url;
image.attr("src", imgURLstill);
image.attr("data-still", imgURLstill);
image.attr("data-moving", imgURLmoving);
image.attr("data-state", "still")
image.addClass("gif");
$("#resultsContainer").append("<p>" + rating + "</p");
$("#resultsContainer").append(image);
}
})
$(document.body).on("click", ".gif", function() {
var state = $(this).attr("data-state");
if (state === "still") {
$(this).attr("src", $(this).data("moving"));
$(this).attr("data-state", "moving");
} else {
$(this).attr("src", $(this).data("still"));
$(this).attr("data-state", "still");
}
})
})
}
displayButtons();
displayGIFs();
This all works on a standalone HTML document, but I can't seem to get the script to work properly. When the component loads and I inspect the page,
<script type="text/javascript" src="/scripts/giphyLogic.js"></script>
is there under the bundle.js script tag, but nothing from the script happens.
I get an "Uncaught SyntaxError: Unexpected token <" error that is attributed to giphyLogic.js:1 even though in the actual .js file, that line is blank. I've looked around, and this apparently happens when a file is included that doesn't exist, but the file is definitely there. I've double checked the path (by including an image in the same folder and loading the image successfully on the page) and it's correct.
Is there a way to resolve this, or am I going to have to create methods within the React component that I'm creating?
Do not mix jQuery and react. Learn how to use react properly by reading the well-written documentation. They can guide you through the many examples to get a simple app up and running.
Once again, do NOT use jQuery and react. jQuery wants to manually manipulate the DOM, and react manages a virtual DOM. The two will conflict more often than not, and you're going to have a bad time. If you have a very deep understanding of react, there are very few scenarios in which you could maybe use some jQuery, but nearly all of the time, it is to be avoided at all costs.
Obviously things like $.ajax() are fine, but for anything dealing with DOM manipulation, stay away. And if you only end up using jQuery for $.ajax() calls... you should switch to a leaner library like axios or use the native fetch API.