简体   繁体   English

$(document).ready AngularJS的替代品

[英]$(document).ready alternative for AngularJS

I'm using a template called Gentelella and I'm trying to implement AngularJS into it. 我正在使用一个名为Gentelella的模板,我正在尝试将AngularJS实现到它中。 However, I'm having an issue with a certain Javascript file. 但是,我遇到了某个Javascript文件的问题。 In the end of this file, a $(document).ready function is called which initialises Javascript code that makes some changes in the HTML code. 在此文件的末尾,调用$(document).ready函数,该函数初始化在HTML代码中进行一些更改的Javascript代码。 The issue is that the $(document).ready function is called too early, before the HTML is fully loaded. 问题是在HTML完全加载之前, $(document).ready函数调用得太早。

This issue occurs probably because I'm using ngRoute and this injects the template html file into the ng-view of the index.html. 出现此问题可能是因为我正在使用ngRoute,这会将模板html文件注入index.html的ng-view。 When this happens, the DOM probably already announces a document ready before AngularJS has injected the template (=HTML). 当发生这种情况时,DOM可能已经在AngularJS注入模板(= HTML)之前宣布准备好文档。

So basically, I just need to find a way to call some code in a Javascript file once AngularJS has injected the template. 基本上,一旦AngularJS注入模板,我只需要找到一种方法在Javascript文件中调用一些代码。

I attached some code to gain some insight into the issue: 我附上了一些代码来深入了解这个问题:

Snippet of the custom.min.js custom.min.js的片段

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

Snippet of the main.js: 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! 提前致谢!

Many jQuery plugins depend on a workflow of 1. draw the DOM. 许多jQuery插件依赖于1.绘制DOM的工作流程。 2. run an init() function to set up code against those DOM elements. 2.运行init()函数来设置针对这些DOM元素的代码。

That workflow fares poorly in Angular, because the DOM isn't static: Angular sets up and destroys DOM nodes on its own lifecycle, which can overwrite event bindings or DOM changes made outside Angular. 该工作流在Angular中表现不佳,因为DOM不是静态的:Angular在其自己的生命周期中设置和销毁DOM节点,这可以覆盖在Angular之外进行的事件绑定或DOM更改。 Document ready isn't particularly useful when you're using Angular, because all it indicates is that Angular itself is ready to start running. 当您使用Angular时,文档就绪并不是特别有用,因为它表明Angular本身已准备好开始运行。

To use Angular effectively, you have to get into the habit of initing code only when it's actually needed. 要有效地使用Angular,您必须养成仅在实际需要时才启动代码的习惯。 So instead of a big bucket of init_foo(); init_bar(); 而不是init_foo(); init_bar(); init_foo(); init_bar(); on document.ready, you should have a Foo directive with its own init code, and a Bar directive with its own specific init code, and so on. 在document.ready上,你应该有一个带有自己的初始化代码的Foo指令,以及一个带有自己特定初始化代码的Bar指令,依此类推。 Each of those directives should only modify the DOM created by that specific directive. 这些指令中的每一个都应该只修改由该特定指令创建的DOM。 This is the only safe way to ensure that the DOM elements you need to modify actually exist, and that you're not creating conflicts or unexpected interdependencies between directives. 这是确保您需要修改的DOM元素实际存在的唯一安全方法,并且您不会在指令之间创建冲突或意外的相互依赖性。

To take one example: I'm guessing your init_flot_chart() crawls down through the DOM looking for a particular element inside of which it'll draw a flot chart. 举一个例子:我猜你的init_flot_chart()通过DOM向下搜索,寻找一个特定元素,在其中绘制一个flot图表。 Instead of that 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's element; no DOM crawling necessary
      }
    };
});

which you use like this: 您使用这样的:

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

...where theChartData is an object containing whatever data is to be drawn in the chart. ...其中theChartData是一个对象,包含要在图表中绘制的任何数据。 (You can add other attributes to pass in whatever other parameters you like, such as the flot options, a title, etc.) (您可以添加其他属性以传入您喜欢的任何其他参数,例如flot选项,标题等)

When Angular draws that flotWrapper directive, it first creates the DOM element(s) in the directive template, and then runs whatever is in its link function against the template's root element. 当Angular绘制flotWrapper指令时,它首先在指令模板中创建DOM元素,然后针对模板的根元素运行其link函数中的任何内容。 (The flot library itself can be included via a plain old <script> tag so its plot function is available when the directive needs it.) (flot库本身可以通过普通的旧<script>标签包含在内,因此当指令需要时,它的plot功能可用。)

(Note that this wouldn't update automatically if the contents of theChartData change; a more elaborate example which also watches for changes and responds appropriately can be seen here .) (注意,如果theChartData的内容theChartData变化,这不会自动更新; 这里可以看到一个更精细的例子,它也会观察变化并做出适当的响应。)

As you are using ngRoute , your controller will run when the page is loaded. 在使用ngRoute ,控制器将在加载页面时运行。 You can call an init() method when the controller starts to do whatever you want. 当控制器开始执行您想要的任何操作时,您可以调用init()方法。

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

As a side note, it is a best practice recommanded in John Papa Angular's guide . 作为旁注,这是John Papa Angular指南中推荐的最佳实践。


Another possibily is to use the ng-init directive, for example: 另一种可能是使用ng-init指令,例如:

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

There is a lifecycle hooks named $postLink() in recent version of angular.js, Called after this controller's element and its children have been linked. 在最新版本的angular.js中有一个名为$postLink()的生命周期钩子,在此控制器的元素及其子元素已被链接之后调用。 Similar to the post-link function this hook can be used to set up DOM event handlers and do direct DOM manipulation.Check the guide 与post-link函数类似,此挂钩可用于设置DOM事件处理程序并执行直接DOM操作。请查看指南

$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 rigorous solution, plz see another answer I wrote 更新通知 :sry家伙,这不是一个严格的解决方案,请参阅我写的另一个答案

This is related to angular digest cycle, it's about how angular works underneath the hood, data binding etc. There are great tutorials explaining this. 这与角度消化周期有关,它是关于角度如何在引擎盖下工作,数据绑定等。有很好的教程解释这一点。

To solve your problem, use $timeout , it will make the code execute on the next cycle: 要解决您的问题,请使用$timeout ,它将使代码在下一个周期执行:

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);
    });
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM