92

Simple question, I hope.

I want to run a script when the Angular2 equivalent of $document.ready() is fired. What is the best way to achieve this?

I've tried putting the script at the end of index.html, but as I found out, this doesn't work! I take it that it has to go in some kind of component declaration?

Is it possible to run load the script from a .js file?

EDIT - Code:

I've got the following js and css plugins injected into my application (from the Foundry html theme).

    <link href="css/themify-icons.css" rel="stylesheet" type="text/css" media="all" />
    <link href="css/bootstrap.css" rel="stylesheet" type="text/css" media="all" />
    ...


    <script src="js/jquery.min.js"></script>
    <script src="js/bootstrap.min.js"></script>
    <script src="js/flexslider.min.js"></script>
    ...
    <script src="js/scripts.js"></script> //This initiates all the plugins

As noted, the scripts.js 'instantiates' the whole thing, and thus is needed to be run after Angular is ready. script.js

Got it working:

import {Component, AfterViewInit} from 'angular2/core';

@Component({
  selector: 'home',
  templateUrl: './components/home/home.html'
})
export class HomeCmp implements AfterViewInit {


    ngAfterViewInit() {
       //Copy in all the js code from the script.js. Typescript will complain but it works just fine
    }
Chris
  • 7,830
  • 6
  • 38
  • 72
  • after some hours of research, I still got the same issue. > Module not found: Error: Can't resolve '@types/jquery' I installed it with npm install --save -D @types/jquery, then when i try to import it in the Module (due to the fact that i got a Message from the toolbox that it doesn't know $ from jQuery) in my Component.ts it says my first message ! I hope my explanations are corrects Thanks again for all the help this community gave to me ! btw : This is my first real message so I hope to write a good one – Alexandre Saison May 29 '17 at 10:15

6 Answers6

70

Copying the answer from Chris:

Got it working:

import {AfterViewInit} from 'angular2/core';    

export class HomeCmp implements AfterViewInit {    

    ngAfterViewInit() {
       //Copy in all the js code from the script.js. Typescript will complain but it works just fine
    }
Sameer Alibhai
  • 3,092
  • 4
  • 36
  • 36
  • 5
    Not sure why the downvotes. This worked for me, but also introduced a race between the legacy JS code I was trying to run and the view compiler. I ended up using `AfterViewChecked`, but all the same, here's an upvote for pointing me in the right direction. – lukiffer Jun 01 '16 at 22:05
  • 1
    This might work but it might not be the best practice. What would be better is have all of the external code wrapped in some global, but well namespaced function, then call this function from `ngAfterViewInit()`. E.g. `window.MY_APP = {}; MY_APP.init = function () {/*copy all that script.js here*/ }`. Then in your component, `import ...; declare var MY_APP: any; class HomeComponent() { ngAfterViewInit() { MY_APP.init(); } }` But the bottom line is still that you don't have an angular2 app - your script.js is basically an old-school jquery page. You could turn most of it into NG2 components. – Zlatko Aug 09 '16 at 08:30
  • 2
    I am not downvoting this but in this method I can reach DOM elements. However when I try to get element.css('height') it returns to me 0px Thus I cannot use it for setting css. – Blast Apr 01 '17 at 10:30
  • It worked for me perfectly :) I think, at this stage you have already DOM, but might not have yet all the sources loaded, like images. So it's exactly like `$document.ready()`. – Affilnost Apr 25 '18 at 12:27
  • 1
    Sweet and smooth! – Sam Nov 06 '19 at 20:34
  • Upvoted this answer because it contains a comment with the actual solution: using AfterViewChecked – jgerman Dec 16 '19 at 21:20
37

You can fire an event yourself in ngOnInit() of your Angular root component and then listen for this event outside of Angular.

This is Dart code (I don't know TypeScript) but should't be to hard to translate

@Component(selector: 'app-element')
@View(
    templateUrl: 'app_element.html',
)
class AppElement implements OnInit {
  ElementRef elementRef;
  AppElement(this.elementRef);

  void ngOnInit() {
    DOM.dispatchEvent(elementRef.nativeElement, new CustomEvent('angular-ready'));
  }
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • Ok, perfect. Could you possibly provide a quick example of such code? Sorry, but quite new to ng2 – Chris Dec 31 '15 at 13:29
  • Preferably I'd like to be able to load a js file when the onInit occurs. This file has all my document ready code (from a html template I'm using) and is in js, so I can't just copy paste it in since I'm writing ng2 in .ts – Chris Dec 31 '15 at 13:32
  • Check the [reference](https://angular.io/docs/ts/latest/api/core/OnInit-interface.html) for ngOnInit. – Boris Dec 31 '15 at 13:32
  • 1
    @Boris it doesn't get me very far I'm afraid – Chris Dec 31 '15 at 13:35
  • @Chris I see your comment, what is the code, why would it not be possible to load it in onInit? – Boris Dec 31 '15 at 13:36
  • Is the code you want to run after ready part of your Angular application or is it supposed to run outside Angular? – Günter Zöchbauer Dec 31 '15 at 13:36
  • @GünterZöchbauer I've added some code and a little explanation above – Chris Dec 31 '15 at 13:44
  • As part of your Angular application or outside of Angular. I think you should start with the Angular tutorials at https://angular.io/docs/ts/latest/tutorial – Günter Zöchbauer Dec 31 '15 at 13:45
  • As part of my angular application – Chris Dec 31 '15 at 13:50
  • 9
    Then you just run the code in `ngAfterViewInit() { ... }`. No need to fire an event. – Günter Zöchbauer Dec 31 '15 at 13:52
  • @GünterZöchbauer do you have any idea why this doesn't work in the app.component, but works fine in the component specific to the view? Hope this makes sense – Chris Jan 03 '16 at 18:27
  • Actually no. What do you mean by "app.component", the root component? What do you mean by "doesn't work"? Is `ngAfterViewInit` not called? Can you please update your question and add your current code? – Günter Zöchbauer Jan 03 '16 at 18:34
16

I went with this solution so I didn't have to include my custom js code within the component other than the jQuery $.getScript function.

Note: Has a dependency on jQuery. So you will need jQuery and jQuery typings.

I have found this is a good way to get around custom or vendor js files that do not have typings available that way TypeScript doesn't scream at you when you go to start your app.

import { Component,AfterViewInit} from '@angular/core'

@Component({
  selector: 'ssContent',
  templateUrl: 'app/content/content.html',
})
export class ContentComponent implements AfterViewInit  {

  ngAfterViewInit(){
    $.getScript('../js/myjsfile.js');
  }
}

Update Actually in my scenario the OnInit lifecycle event worked better because it prevented the script from loading after the views were loaded, which was the case with ngAfterViewInit, and that cause the view to show incorrect element positions prior to the script loading.

ngOnInit() {
    $.getScript('../js/mimity.js');
  }
dynamiclynk
  • 2,275
  • 27
  • 31
8

the accepted answer is not correct, and it makes no sens to accept it considering the question

ngAfterViewInit will trigger when the DOM is ready

whine ngOnInit will trigger when the page component is only starting to be created

phil123456
  • 211
  • 3
  • 13
4

In order to use jQuery inside Angular only declare the $ as following: declare var $: any;

Ilir Hushi
  • 99
  • 5
0

In your main.ts file bootstrap after DOMContentLoaded so angular will load when DOM is fully loaded.

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}



document.addEventListener('DOMContentLoaded', () => {
  platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.log(err));
});
Vikas Kandari
  • 1,612
  • 18
  • 23