$ (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!
source to share
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 .)
source to share
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>
source to share
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);
});
});
source to share
$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
source to share