外部JS函数的AngularJS访问范围


131

我正在尝试查看是否存在通过外部javascript函数访问控制器内部范围的简单方法(与目标控制器完全无关)

我在其他几个问题上看到

angular.element("#scope").scope();

会从DOM元素中检索范围,但是我的尝试目前未产生正确的结果。

这是jsfiddle:http : //jsfiddle.net/sXkjc/5/

我目前正在经历从纯JS到Angular的过渡。我试图实现这一目标的主要原因是要保持原始库代码尽可能完整。无需我将每个功能添加到控制器。

关于如何实现这一目标的任何想法?也欢迎对上面的小提琴发表评论。


根据文档使用的FYI .scope()要求启用调试数据,但出于速度原因,不建议在生产中使用调试数据。以下解决方案似乎围绕着scope()
rtpHarry 2014年

@rtpHarry是正确的。以下不建议使用scope()的答案。在这里查看我的答案stackoverflow.com/a/34078750/319302
Cagatay Kalan

Answers:


223

如果要从angularjs控件之外(例如jquery / javascript事件处理程序)对范围值进行任何更改,则需要使用$ scope。$ apply()

function change() {
    alert("a");
    var scope = angular.element($("#outer")).scope();
    scope.$apply(function(){
        scope.msg = 'Superhero';
    })
}

演示:小提琴


2
@ dk123 angular.element("#scope")无法正常工作,尽管仍在angular.element($("#scope"))工作,您还需要使用jquery
Arun P Johny

1
我知道已经有一段时间了,但是我希望有人能回答这个问题……为什么var scope = angular.element($(“#outer”))。scope(); 必须在change函数中声明?如果我将其移至全球空间,那是不行的吗?
Marc M.

1
@马克 我认为这与Angular的范围重建有关。到您使用change函数时,全局var指向的先前作用域可能不再存在(由于重新创建)。
dk123

1
angular.element($(“ div [ng-controller ='myCtrl']”))。scope(); 比div元素中的附加#outer更好,我猜
wyverny

1
当我们这样做时,scope()变得不确定:$ compileProvider.debugInfoEnabled(false); 在角度。那么如何使它与debuginfoEnabled false一起使用呢?
Agnosco

26

自从我发布这个问题以来已经有一段时间了,但是考虑到似乎仍然可以得到的意见,这是最近几个月来我想到的另一种解决方案:

$scope.safeApply = function( fn ) {
    var phase = this.$root.$$phase;
    if(phase == '$apply' || phase == '$digest') {
        if(fn) {
            fn();
        }
    } else {
        this.$apply(fn);
    }
};

上面的代码基本上创建了一个名为safeApply$apply函数,如果只有Angular当前没有经过$digest阶段,则调用该函数(如Arun的回答所述)。另一方面,如果Angular 当前正在消化事物,它将按原样执行该函数,因为这足以向Angular发出信号以进行更改。

$applyAngularJs当前处于使用$digest阶段时,尝试使用该函数时会发生许多错误。safeApply上面的代码是防止此类错误的安全包装。

(注:我个人比较喜欢到卡盘safeApply之间的函数关系$rootScope为方便起见)

例:

function change() {
    alert("a");
    var scope = angular.element($("#outer")).scope();
    scope.safeApply(function(){
        scope.msg = 'Superhero';
    })
}

演示:http//jsfiddle.net/sXkjc/227/


1
为什么您的safeApply功能起作用?似乎您在说的是“如果Angular处于$ apply或$ digest阶段,则自行执行该函数,否则,请使用$ apply()来应用该函数” ..但是,如果您自己执行该函数。 ..如何更新任何模型?除非有我不知道的事情发生,否则这似乎不是好行为。Angular中的某些机制是否会对$ scope进行轮询以查看可能直接发生在其上的更改???
trusktr 2014年

另外,如果您需要防范这些状态,那么我认为$ apply()方法的一个错误需要修复。
trusktr 2014年

@trusktr据我了解,如果函数更改任何模型,则正常执行函数会被角度捕获,因此,角度将在下一摘要阶段更新它们。
dk123 2014年

@trusktr我同意,但是,如果可以在没有保护措施的情况下应用正常的$ apply(),那就没有什么比这更好的了。本质上,safeApply的唯一目的是防止$ apply()错误。不知道这是否是已报告的问题,现在已解决,还是仍然存在。
dk123 2014年

1
只是因为我偶然发现了它:github.com/angular/angular.js/wiki/When-to-use-$scope.$apply()。(!$范围$$阶段)。_IF你正在做的,如果$范围$适用(),那是因为你在通话stack._不够高
scheffield

17

另一种方法是:

var extScope;
var app = angular.module('myApp', []);
app.controller('myController',function($scope, $http){
    extScope = $scope;
})
//below you do what you want to do with $scope as extScope
extScope.$apply(function(){
    extScope.test = 'Hello world';
})

1
我仍然不明白为什么这个评论不是最好的答案。经过几天的挫折和愤怒,上网终于解决了我的问题。谢谢@查尔斯顿。您太好了,先生!
拉吉玛(Rajkumar)

13

加载后我们可以调用它

http://jsfiddle.net/gentletech/s3qtv/3/

<div id="wrap" ng-controller="Ctrl">
    {{message}}<br>
    {{info}}
    </div>
    <a  onClick="hi()">click me </a>

    function Ctrl($scope) {
        $scope.message = "hi robi";
        $scope.updateMessage = function(_s){
            $scope.message = _s;    
        };
    }

function hi(){
    var scope = angular.element(document.getElementById("wrap")).scope();
        scope.$apply(function() {
        scope.info = "nami";
        scope.updateMessage("i am new fans like nami");
    });
}

8

我问这个问题已经很长时间了,但这是不需要jquery的答案:

function change() {
    var scope = angular.element(document.querySelector('#outside')).scope();
    scope.$apply(function(){
        scope.msg = 'Superhero';
    })
}

3

这是一个可重用的解决方案:http : //jsfiddle.net/flobar/r28b0gmq/

function accessScope(node, func) {
    var scope = angular.element(document.querySelector(node)).scope();
    scope.$apply(func);
}

window.onload = function () {

    accessScope('#outer', function (scope) {
        // change any property inside the scope
        scope.name = 'John';
        scope.sname = 'Doe';
        scope.msg = 'Superhero';
    });

};

2

您也可以尝试:

function change() {
    var scope = angular.element( document.getElementById('outer') ).scope();
    scope.$apply(function(){
        scope.msg = 'Superhero';
    })
}

@ dk123这也不需要JQuery。
harish sharma

1

公认的答案是伟大的。我想看看的背景下Angular范围发生了什么ng-repeat。事实是,Angular将为每个重复项创建一个子范围。调用在original上定义的方法时,该方法将$scope保留其原始值(由于javascript闭包)。但是,this引用调用范围/对象。这工作顺利,只要你在何时明确$scopethis是相同的,当他们是不同的。hth

这是一个说明差异的小提琴:https : //jsfiddle.net/creitzel/oxsxjcyc/


1

我是新手,不好意思。根据选择的答案,我执行了以下功能:

function x_apply(selector, variable, value) {
    var scope = angular.element( $(selector) ).scope();
    scope.$apply(function(){
        scope[variable] = value;
    });
}

我以这种方式使用它:

x_apply('#fileuploader', 'thereisfiles', true);

对了,对不起我的英语


0
<input type="text" class="form-control timepicker2" ng-model='programRow.StationAuxiliaryTime.ST88' />

访问范围值

假设programRow.StationAuxiliaryTime是对象数组

 $('.timepicker2').on('click', function () 
    {
            var currentElement = $(this);

            var scopeValues = angular.element(currentElement).scope();
            var model = currentElement.attr('ng-model');
            var stationNumber = model.split('.')[2];
            var val = '';
            if (model.indexOf("StationWaterTime") > 0) {
                val = scopeValues.programRow.StationWaterTime[stationNumber];
            }
            else {
                val = scopeValues.programRow.StationAuxiliaryTime[stationNumber];
            }
            currentElement.timepicker('setTime', val);
        });

0

我们需要使用内置函数$ apply中的 Angular Js 来访问范围变量或控制器函数外部的函数。

这可以通过两种方式完成:

| * | 方法1:使用Id:

<div id="nameNgsDivUid" ng-app="">
    <a onclick="actNgsFnc()"> Activate Angular Scope</a><br><br>
    {{ nameNgsVar }}
</div>

<script type="text/javascript">

    var nameNgsDivVar = document.getElementById('nameNgsDivUid')

    function actNgsFnc()
    {
        var scopeNgsVar = angular.element(nameNgsDivVar).scope();
        scopeNgsVar.$apply(function()
        {
            scopeNgsVar.nameNgsVar = "Tst Txt";
        })
    }

</script>

| * | 方法2:使用ng-controller的init:

<div ng-app="nameNgsApp" ng-controller="nameNgsCtl">
    <a onclick="actNgsFnc()"> Activate Angular Scope</a><br><br>
    {{ nameNgsVar }}
</div>

<script type="text/javascript">

    var scopeNgsVar;
    var nameNgsAppVar=angular.module("nameNgsApp",[])
    nameNgsAppVar.controller("nameNgsCtl",function($scope)
    {
        scopeNgsVar=$scope;
    })

    function actNgsFnc()
    {
        scopeNgsVar.$apply(function()
        {
            scopeNgsVar.nameNgsVar = "Tst Txt";
        })
    }

</script>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.