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

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

Я видел на пару других вопросов здесь, что

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

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

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

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

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

11 ответов

Решение

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

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

Демо: скрипка

Прошло довольно много времени с тех пор, как я опубликовал этот вопрос, но, учитывая мнения, которые, похоже, все еще появляются, вот еще одно решение, с которым я столкнулся за последние несколько месяцев:

$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 этап. С другой стороны, если 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/

Еще один способ сделать это:

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

Мы можем назвать это после загрузки

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

Я давно не задавал этот вопрос, но вот ответ, который не требует jquery:

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

Вот многоразовое решение: 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';
    });

};

Вы также можете попробовать:

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

Я новичок, так что извините, если это плохая практика. Основываясь на выбранном ответе, я сделал эту функцию:

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

Я использую это так:

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

Кстати, извините за мой английский

Принятый ответ великолепен. Я хотел посмотреть на то, что происходит с угловой областью в контексте ng-repeat, Дело в том, что Angular создаст подцел для каждого повторяющегося элемента. При вызове метода, определенного в оригинале $scope, который сохраняет свое первоначальное значение (из-за закрытия JavaScript). Тем не менее this ссылается на вызывающую область / объект. Это хорошо работает, пока вы ясно, когда $scope а также this одинаковы и когда они разные. НТН

Вот скрипка, которая иллюстрирует разницу: https://jsfiddle.net/creitzel/oxsxjcyc/

Так я поступил со своим CRUDManager classинициализируется в контроллере Angular, который позже передается событию нажатия кнопки 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 Сохранить событие нажатия кнопки вне контроллера:

    $(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 необходимо разместить ВНЕ КОНТРОЛЛЕРА, чтобы предотвратить его повторное срабатывание.

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

доступ к значению области

Предположим, что programRow.StationAuxiliTime является массивом объектов

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

Нам нужно использовать встроенную функцию Angular J $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>
Другие вопросы по тегам