AngularJS从js函数外部访问范围

时间:2013-03-15 04:43:39

标签: angularjs angularjs-scope

我试图通过外部javascript函数(与目标控制器完全无关)来查看是否有一种简单的方法来访问控制器的内部范围

我在这里看到了其他几个问题

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

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

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

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

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

12 个答案:

答案 0 :(得分:221)

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

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

演示:Fiddle

答案 1 :(得分:26)

自从我发布这个问题已经有一段时间了,但考虑到这似乎仍然存在的观点,这是我在过去几个月中遇到的另一个解决方案:

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

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

当AngularJs当前处于$apply阶段时,尝试使用$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/

答案 2 :(得分:15)

另一种方法是:

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

答案 3 :(得分: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");
    });
}

答案 4 :(得分:8)

自从我提出这个问题已经有很长一段时间了,但是这里的答案不需要jquery:

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

答案 5 :(得分: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';
    });

};

答案 6 :(得分:2)

您也可以尝试:

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

答案 7 :(得分:1)

接受的答案很棒。我想看一下ng-repeat上下文中Angular范围会发生什么。问题是,Angular将为每个重复项创建一个子范围。调用原始$scope上定义的方法时,会保留其原始值(由于javascript闭包)。但是,this引用调用范围/对象。只要您清楚$scopethis何时相同以及何时不同,这一点就可以了。 HTH

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

答案 8 :(得分:1)

我是新手,很抱歉,如果这是一个不好的做法。根据所选答案,我做了这个功能:

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

我这样使用它:

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

顺便说一句,抱歉我的英文

答案 9 :(得分: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);
        });

答案 10 :(得分:0)

我们需要使用内置函数 $ apply 的Angular J来处理控制器函数之外的范围变量或函数。

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

| * |方法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>

答案 11 :(得分:0)

这就是我在Angular控制器中初始化CRUDManager class的方式,后来将其传递给在控制器外部定义的jQuery按钮单击事件:

在Angular Controller中:

        // Note that I can even pass over the $scope to my CRUDManager's constructor.
        var crudManager = new CRUDManager($scope, contextData, opMode);

        crudManager.initialize()
            .then(() => {
                crudManager.dataBind();
                $scope.crudManager = crudManager;
                $scope.$apply();
            })
            .catch(error => {
                alert(error);
            });

在控制器外部的jQuery Save按钮中单击事件:

    $(document).on("click", "#ElementWithNgControllerDefined #btnSave", function () {
        var ngScope = angular.element($("#ElementWithNgControllerDefined")).scope();
        var crudManager = ngScope.crudManager;
        crudManager.saveData()
            .then(finalData => {
               alert("Successfully saved!");
            })
            .catch(error => {
               alert("Failed to save.");
            });
    });

当您需要将jQuery事件放置在控制器外部以防止其触发两次时,这特别重要且有用。