$ (document). Already an alternative for AngularJS

I am using a template called Gentelella and I am trying to implement AngularJS in it. However, I have a problem with a specific Javascript file. At the end of this file, a function is called $(document).ready

that initializes the Javascript code, which makes some changes to the HTML code. The problem is that the function $(document).ready

is called too early before the HTML is fully loaded.

This problem is probably because I am using ngRoute and this is inserting the template html file in the ng-view index.html. When this happens, the DOM is probably already declaring the document ready before AngularJS injects the template (= HTML).

Basically, I just need to find a way to call some code in the Javascript file as soon as AngularJS enters the template.

I have attached the code to get an idea of ​​the problem:

Snippet custom.min.js

$(document).ready(function () {
  init_sparklines(), init_flot_chart(), init_sidebar(), init_wysiwyg(), init_InputMask(), ...
});

      

Snippet of main.js:

.config(function($routeProvider, $httpProvider) {

  $routeProvider.when('/', {
    templateUrl : 'dash.html',
    controller : 'dash',
    controllerAs: 'controller'
  }).when('/login', {
    templateUrl : 'login.html',
    controller : 'navigation',
    controllerAs: 'controller'
  }).when('/plain_page', {
    templateUrl : 'plain_page.html',
    controller : 'dash',
    controllerAs: 'controller'
  }).otherwise('/');

  $httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';

})

      

Thanks in advance!

+3


source to share


5 answers


Many jQuery plugins depend on workflow 1. draw the DOM. 2. Run the function init()

to set up the code for these DOM elements.

This workflow does not work well in Angular because the DOM is not static: Angular sets up and destroys DOM nodes in its own lifecycle, which can overwrite event bindings or DOM changes made outside of Angular. The finished document is not particularly useful if you are using Angular, because it all indicates that Angular itself is ready to run.

To use Angular effectively, you need to get used to initializing your code only when you really need to. So instead of a big bucket init_foo(); init_bar();

on document.ready, you should have a Foo directive with your own initialization code and a Bar directive with your own initialization code, etc. Each of these directives should only modify the DOM created by that particular directive. This is the only safe way to ensure that the DOM elements needed to change do exist and that you don't create conflicts or unexpected dependencies between directives.

To take one example: I am assuming yours is init_flot_chart()

scanning down through the DOM looking for a specific element inside which it will draw a fleet map. Instead of this top-down approach, create a directive:

angular.module('yourApp')
  .directive('flotWrapper', function () {
    return {
      template: "<div></div>",
      scope: {
        data: '@'
      },
      link: function(scope, elem, attrs) {
        var options = {}; // or could pass this in as an attribute if desired
        $.plot(elem, scope.data, options); // <-- this calls flot on the directive element; no DOM crawling necessary
      }
    };
});

      



which you are using like this:

<flot-wrapper data="{{theChartData}}"></flot-wrapper>

      

... where theChartData

is an object containing any data to be drawn in the chart. (You can add other attributes to pass any other parameters like float parameters, header, etc.)

When Angular draws this flotWrapper directive, it first creates the DOM elements in the template of the directive, and then runs whatever is in its function link

against the root element of the template. (The float library itself can be included via a normal old tag <script>

, so its function plot

is available when the directive needs it).

(Note that this will not automatically update if the content theChartData

changes; a more detailed example that also monitors changes and responds accordingly can be seen here .)

+3


source


When you use ngRoute

, your controller will be fired on page load. You can call the method init()

when the controller starts doing whatever you want.

function MyCtrl($scope) {
    function init() {
        console.log('controller started!');
    }
    init();
}

      

As a side note, this is the best practice recommended in the John Papa Angular guide .




Another option is to use a directive ng-init

like:

<div ng-controller="MyCtrl" ng-init="myFunction()">...</div>

      

+1


source


It has to do with angular's digest loop, it's about how angular works under the hood, data binding, etc. There are great tutorials to explain this.

To solve your problem, use $timeout

this will make the code run in the following loop:

app.controller('Controller', function ($scope, $timeout) {
    $scope.$on('$viewContentLoaded', function(event) {
      $timeout(function() {
        init_sparklines(), init_flot_chart(), init_sidebar(), init_wysiwyg(), init_InputMask(), ...
      },0);
    });
});

      

0


source


The latest version of angular.js has named lifecycle hooks $postLink()

called after this control and its children. Similar to the post-link function, this hook can be used to set up DOM event handlers and direct DOM manipulation. Check out the guide

0


source


$document.ready(function() {
  $scope.$on('$viewContentLoaded', function() {
    $timeout(function() {
      init_sparklines(), init_flot_chart(), init_sidebar(), init_wysiwyg(), init_InputMask(), ...
    })
  })
})

      

update Notice : sry guys this is not a strict solution plz see another answer I wrote

-1


source







All Articles