如何从javascript访问范围angularjs?

时间:2017-01-12 03:26:46

标签: angularjs

我对此帖Pass Angular scope variable to Javascript也有同样的问题。但我无法用他们的答案来解决我的问题。

我的角度控制器

<div class="main">
    <div id="logo"><img src="img/logo.png" /></div>
    <div id="main-links">
        <a style="cursor:pointer"><img id="img-1" style="margin-left: 0" src="img/icons/forums.png" onmouseover="this.src='img/icons/forums-hover.png'" onmouseout="this.src='img/icons/forums.png'" /></a>
        <a style="cursor:pointer"><img id="img-2" src="img/icons/servers.png" onmouseover="this.src='img/icons/servers-hover.png'" onmouseout="this.src='img/icons/servers.png'" /></a>
        <a style="cursor:pointer"><img id="img-3" src="img/icons/staff.png" onmouseover="this.src='img/icons/staff-hover.png'" onmouseout="this.src='img/icons/staff.png'" /></a>
        <a style="cursor:pointer"><img id="img-4" src="img/icons/donate.png" onmouseover="this.src='img/icons/donate-hover.png'" onmouseout="this.src='img/icons/donate.png'" /></a>
    </div>
</div>

我的Html

angular.module('App').controller('HomeController', [
    '$rootScope', '$scope', '$state', '$timeout', 'ReportService', 'MsgService',
    function($rootScope, $scope, $state, $timeout, ReportService, MsgService) {

        $scope.$on('$viewContentLoaded', function() {
            console.log('HomeController');
            $scope.get_locations();
        });

        // get locations
        $scope.get_locations = function() {
            var data = {};
            // call http get to my api
            MsgService.get_all_locations(data, function(response) {
                if (response.code == 1) { // success
                    $scope.locations_array = response.data; // data that I want to access to script
                } else {
                    alert(response.message);
                }
            });
        }
    }
]);

我尝试从浏览器开发工具访问然后它可以访问范围。但是我的代码无法访问它。

Chorme develop tool

如何解决这个问题?

1 个答案:

答案 0 :(得分:2)

此处的直接问题是计时问题 - 您在填充值之前很久就试图从范围中读取locations_array值。

事件的顺序如下:

    文件触发器的
  1. ready事件,在Angular甚至考虑启动之前,你的内联JS代码会运行,试图从范围中读取值,但目前还不存在。
  2. Angular引导您的Angular应用程序以响应文档的ready事件(这可能在#1之前,具体取决于页面上脚本的顺序)。这将调用HomeController构造函数,该构造函数仅为$viewContentLoaded事件设置一个侦听器。
  3. $viewContentLoaded事件被广播,您发起对位置的异步请求。
  4. 如果稍后返回某些位置,则会在范围内填充它们。
  5. 不要依赖.scope()

    除了时序问题之外,您的解决方案还有另一个主要问题 - 它依赖于AngularJS包含的调试信息。显然,它是默认的,但是disable this debug information可以在生产中获得显着的性能提升。

    如果其他人出现,可能在您离开后,并尝试禁用调试信息以提高性能或出于其他原因(这是生产中的推荐做法),它将停止.scope()从工作

    因此,依靠.scope(),您正在努力禁用调试信息,这是一种最佳做法和性能助推器,现在或将来都无法用于您的应用,因为它会破坏事物。对于那个开发者而言,这对任何事情来说都是显而易见的。

    所以依靠.scope()进行调试以外的任何事情都应该是最后的选择。

    那我该怎么做呢?

    就像我提到的,这是一个计时问题 - 您需要等到最终加载位置,然后再运行依赖它们的代码。

    幸运的是,我们在JS中有很多选项来处理异步值 - 回调,承诺,RxJS可观察等等。选择你最喜欢的。

    示例:使用全局承诺

    在你的控制器中,在全局范围内创建一个promise(icky,但它需要在某个地方的Angular之外),并在加载时使用位置数据解析该promise。

    var resolveLocations;
    window.locationsPromise = new Promise(function (resolve) { 
        resolveLocations = resolve;
    });
    angular.module('App').controller('HomeController', [
        '$rootScope', '$scope', '$state', '$timeout', 'ReportService', 'MsgService',
        function($rootScope, $scope, $state, $timeout, ReportService, MsgService) {
    
            $scope.$on('$viewContentLoaded', function() {
                console.log('HomeController');
                $scope.get_locations();
            });
    
            // get locations
            $scope.get_locations = function() {
                var data = {};
                // call http get to my api
                MsgService.get_all_locations(data, function(response) {
                    if (response.code == 1) { // success
                        resolveLocations(response.data); // resolve the promise
                        $scope.locations_array = response.data; // data that I want to access to script
                    } else {
                        alert(response.message);
                    }
                });
            }
        }
    ]);
    

    然后,您的普通(非角度)javascript(需要在加载Angular javascript文件后运行)可以使用该承诺在可用时对数据执行某些操作:

    <script type="text/javascript">
    
    $(document).ready(function() {
        window.locationsPromise.then(function (locations_array) {
            console.dir(locations_array);
            // do something with the data
        });
    });
    
    </script>
    

    可能有更好的方法

    在不知道为什么你认为你需要在Angular之外访问这些数据的情况下,很难肯定地说,但是可能还有其他更好的方法来处理Angular代码和依赖于其他Javascript代码之间的相互作用它

    也许您创建了一个指令来集成jQuery插件或其他服务,或者其他什么,但由于AngularJS代码只是普通的JS,因此不需要将它们视为彼此独立。您只需要正确的时间,以便获得可用的数据。祝你好运!