Доступ к AngularJS извне функции js


131

Я пытаюсь увидеть, есть ли простой способ получить доступ к внутренней области контроллера через внешнюю функцию javascript (совершенно не имеющую отношения к целевому контроллеру)

Я видел здесь еще пару вопросов,

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

получит область видимости из элемента DOM, но мои попытки в настоящее время не дают надлежащих результатов.

Вот jsfiddle: http://jsfiddle.net/sXkjc/5/

Сейчас я прохожу переход от простого JS к Angular. Основная причина, по которой я пытаюсь добиться этого, - сохранить как можно больше нетронутого исходного кода библиотеки; избавляя меня от необходимости добавлять каждую функцию в контроллер.

Есть идеи, как я могу добиться этого? Также приветствуются комментарии к приведенной выше скрипке.


К вашему сведению, согласно документации, для использования .scope()требуется, чтобы были включены данные отладки, но использование данных отладки в производстве не рекомендуется из соображений скорости. Приведенные ниже решения, похоже, вращаются вокругscope()
rtpHarry 05

@rtpГарри прав. Ответы ниже, требующие использования scope (), устарели. См. Мой ответ здесь stackoverflow.com/a/34078750/319302
Чагатай Калан

Ответы:


223

Вам нужно использовать $ scope. $ Apply (), если вы хотите внести какие-либо изменения в значение области вне контроля angularjs, например, обработчика событий jquery / javascript.

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 ($ ("# external")). Scope (); должны быть объявлены внутри функции изменения? Если я перенесу его в глобальное пространство, ничего не получится?
Marc M.

1
@MarcM. Я думаю, это связано с воссозданием объема Angular. К тому времени, когда вы используете функцию изменения, предыдущая область видимости, на которую указывала глобальная переменная, может больше не существовать (из-за воссоздания).
dk123

1
angular.element ($ ( "DIV [нг-контроллер = 'myCtrl']")) Объем (). лучше, чем дополнительный #outer в элементе div, я думаю
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функция (как указано в ответе Аруна) , если и только Угловая в настоящее время не проходят на $digestсцене. С другой стороны, если Angular в настоящее время что-то переваривает , он просто выполнит функцию как есть, так как этого будет достаточно, чтобы сообщить Angular о внесении изменений.

Многочисленные ошибки возникают при попытке использовать $applyфункцию, пока AngularJs находится на ее $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

Кроме того, если вам нужно защитить себя от этих состояний, я бы подумал, что это ошибка метода $ apply (), которую необходимо исправить.
trusktr

@trusktr Насколько я понимаю, выполнение функции обычно перехватывается angular, если функция изменяет какие-либо модели, и, следовательно, angular обновляет их на следующем этапе дайджеста.
dk123

@trusktr Я согласен с тем, что, если бы нормальный $ apply () можно было применить без защиты, не было бы ничего лучше. По сути, единственная цель safeApply - защита от ошибок $ apply (). Однако не уверен, была ли это проблема, о которой сообщалось, и теперь она исправлена, или все еще продолжается.
dk123

1
Просто потому, что я наткнулся на него: github.com/angular/angular.js/wiki/When-to-use-$scope.$apply () . _Если вы выполняете if (! $ Scope. $$ phase) $ scope. $ Apply (), то это потому, что вы недостаточно высоки в стеке вызовов. _
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
Я до сих пор не понимаю, почему этот комментарий не лучший ответ на этот вопрос. После нескольких дней копания в Интернете с разочарованием и гневом, наконец, это решило мою проблему. Спасибо @Charleston. Вы молодцы, сэр!
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 создаст дополнительную область для каждого повторяющегося элемента. При вызове метода, определенного в оригинале $scope, он сохраняет свое исходное значение (из-за закрытия javascript). Однако это thisотносится к вызывающей области / объекту. Это работает хорошо, до тех пор , пока вы ясно , когда $scopeи thisте же , и когда они различны. НТН

Вот скрипка, иллюстрирующая разницу: 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.StationA secondaryTime - это массив объектов

 $('.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

Нам нужно использовать Angular Js, встроенную в функцию $ apply, для доступа к переменным области видимости или функциям вне функции контроллера.

Это можно сделать двумя способами:

| * | Метод 1: Использование идентификатора:

<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: Использование init ng-controller:

<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>
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.