AngularJS-Zugriffsbereich von außerhalb der js-Funktion

131

Ich versuche herauszufinden, ob es eine einfache Möglichkeit gibt, über eine externe Javascript-Funktion auf den internen Bereich eines Controllers zuzugreifen (für den Ziel-Controller völlig irrelevant).

Ich habe hier bei ein paar anderen Fragen gesehen, dass

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

würde den Bereich von einem DOM-Element abrufen, aber meine Versuche führen derzeit zu keinen richtigen Ergebnissen.

Hier ist die jsfiddle: http://jsfiddle.net/sXkjc/5/

Ich mache gerade einen Übergang von einfachem JS zu Angular durch. Der Hauptgrund, warum ich dies erreichen möchte, besteht darin, meinen ursprünglichen Bibliothekscode so intakt wie möglich zu halten. Ich muss nicht jede Funktion zur Steuerung hinzufügen.

Irgendwelche Ideen, wie ich das erreichen könnte? Kommentare zu der obigen Geige sind ebenfalls willkommen.

dk123
quelle
Zu Ihrer Information müssen gemäß den verwendeten Dokumenten .scope()die Debug-Daten aktiviert sein, die Verwendung von Debug-Daten in der Produktion wird jedoch aus Geschwindigkeitsgründen nicht empfohlen . Die folgenden Lösungen scheinen sich umscope()
rtpHarry
@rtpHarry ist richtig. Antworten, für die die Verwendung von scope () erforderlich ist, sind veraltet. Siehe meine Antwort hier stackoverflow.com/a/34078750/319302
Cagatay Kalan

Antworten:

223

Sie müssen $ scope. $ Apply () verwenden, wenn Sie Änderungen an einem Bereichswert vornehmen möchten, die außerhalb der Kontrolle von anglejs liegen, wie z. B. einem jquery / javascript-Ereignishandler.

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

Demo: Fiddle

Arun P Johny
quelle
2
@ dk123 angular.element("#scope")funktioniert nicht, obwohl angular.element($("#scope"))funktioniert, müssen Sie auch jquery haben
Arun P Johny
1
Ich weiß, dass es eine Weile her ist, aber ich hoffe, einige können mir darauf antworten ... Warum ist var scope = angular.element ($ ("# äußere")). Scope (); müssen innerhalb der Änderungsfunktion deklariert werden? Wenn ich es in den globalen Raum verschiebe, ist es ein No Go?
Marc M.
1
@MarcM. Ich denke, das hat mit Angulars Scope Recreation zu tun. Zu dem Zeitpunkt, an dem Sie die Änderungsfunktion verwenden, ist der vorherige Bereich, auf den die globale Variable zeigte, möglicherweise nicht mehr vorhanden (aufgrund der Neuerstellung).
dk123
1
angle.element ($ ("div [ng-controller = 'myCtrl']")). scope (); ist besser als zusätzliches #outer im div-Element, denke ich
wyverny
1
scope () wird dabei undefiniert: $ compileProvider.debugInfoEnabled (false); in eckigen. Wie können wir es also mit debuginfoEnabled false zum Laufen bringen?
Agnosco
26

Es ist schon eine Weile her, dass ich diese Frage gestellt habe, aber angesichts der Ansichten, die dies immer noch zu bekommen scheint, ist hier eine andere Lösung, auf die ich in den letzten Monaten gestoßen bin:

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

Der obige Code erstellt im Grunde eine Funktion namens safeApply, die die $applyFunktion aufruft (wie in Aruns Antwort angegeben), wenn und nur Angular derzeit die Phase nicht durchläuft$digest . Wenn Angular jedoch gerade Dinge verdaut , führt es die Funktion einfach so aus, wie sie ist, da dies ausreicht, um Angular zu signalisieren, die Änderungen vorzunehmen.

Beim Versuch, die $applyFunktion zu verwenden, während AngularJs sich derzeit in der $digestPhase befindet , treten zahlreiche Fehler auf . Der safeApplyobige Code ist ein sicherer Wrapper, um solche Fehler zu vermeiden.

(Hinweis: Ich persönlich mag es, aus Bequemlichkeitsgründen safeApplyals Funktion von $rootScopeeinzusteigen)

Beispiel:

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

Demo: http://jsfiddle.net/sXkjc/227/

dk123
quelle
1
Warum funktioniert Ihre safeApply-Funktion? Anscheinend sagen Sie: "Führen Sie die Funktion selbst aus, wenn sich Angular in der Phase $ apply oder $ Digest befindet. Andernfalls verwenden Sie $ apply (), um die Funktion anzuwenden." .... Wenn Sie die Funktion jedoch selbst ausführen. .. wie aktualisiert das irgendwelche Modelle? Das scheint kein günstiges Verhalten zu sein, es sei denn, es ist etwas los, von dem ich nichts weiß. Geht ein Mechanismus in Angular eine Umfrage zum $ -Bereich für Änderungen durch, die möglicherweise direkt daran vorgenommen wurden?
Trusktr
Wenn Sie sich vor diesen Zuständen schützen müssen, würde ich davon ausgehen, dass ein Fehler der $ apply () -Methode behoben werden muss.
Trusktr
@trusktr Soweit ich weiß, wird die Ausführung der Funktion normalerweise von Angular erfasst, wenn die Funktion Modelle ändert, und Angular aktualisiert sie daher in der nächsten Digest-Phase.
dk123
@trusktr Ich würde jedoch zustimmen, dass es nichts Besseres geben würde, wenn das normale $ apply () ohne die Sicherheitsvorkehrungen angewendet werden kann. Im Wesentlichen besteht der einzige Zweck von safeApply darin, sich vor den $ apply () -Fehlern zu schützen. Ich bin mir jedoch nicht sicher, ob dies ein gemeldetes und jetzt behobenes oder noch laufendes Problem war.
dk123
1
Nur weil ich darüber gestolpert bin: github.com/angular/angular.js/wiki/When-to-use-$scope.$apply () . _Wenn Sie tun, wenn (! $ Scope. $$ Phase) $ scope. $ Apply (), liegt es daran, dass Sie nicht hoch genug im Aufrufstapel sind. _
scheffield
17

Ein anderer Weg, dies zu tun, ist:

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';
})
Charleston
quelle
1
Ich verstehe immer noch nicht, warum dieser Kommentar nicht die beste Antwort darauf ist. Nachdem ich ein paar Tage lang mit Frustration und Wut im Internet gebuddelt hatte, löste dies endlich mein Problem. Vielen Dank, dass Sie @Charleston. Sie sind großartig, Sir!
Rajkumar
13

wir können es nach dem Laden nennen

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

Es ist lange her, dass ich diese Frage gestellt habe, aber hier ist eine Antwort, für die keine Abfrage erforderlich ist:

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

Hier ist eine wiederverwendbare Lösung: 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';
    });

};
Flobar
quelle
2

Sie können auch versuchen:

function change() {
    var scope = angular.element( document.getElementById('outer') ).scope();
    scope.$apply(function(){
        scope.msg = 'Superhero';
    })
}
Harish Sharma
quelle
@ dk123 dies erfordert auch keine JQuery.
Harish Sharma
1

Die akzeptierte Antwort ist großartig. Ich wollte sehen, was mit dem Angular-Bereich im Kontext von passiert ng-repeat. Die Sache ist, Angular erstellt einen Unterbereich für jedes wiederholte Element. Wenn Sie eine im Original definierte Methode aufrufen $scope, behält diese ihren ursprünglichen Wert bei (aufgrund des Schließens von Javascript). Das thisbezieht sich jedoch auf den aufrufenden Bereich / das aufrufende Objekt. Das funktioniert gut aus, so lange , wie Sie sind klar, wann $scopeund thisgleich sind und wenn sie verschieden sind. hth

Hier ist eine Geige, die den Unterschied veranschaulicht: https://jsfiddle.net/creitzel/oxsxjcyc/

Charlie
quelle
1

Ich bin Neuling, tut mir leid, wenn es eine schlechte Praxis ist. Basierend auf der gewählten Antwort habe ich diese Funktion ausgeführt:

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

Ich benutze es so:

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

Übrigens, entschuldige mein Englisch

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

Zugriff auf den Bereichswert

Angenommen, programRow.StationAuxiliaryTime ist ein Array von Objekten

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

Wir müssen Angular Js verwenden, die in die Funktion $ apply für Zugriffsbereichsvariablen oder Funktionen außerhalb der Controller-Funktion integriert sind.

Dies kann auf zwei Arten erfolgen:

| * | Methode 1: Verwenden der 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>

| * | Methode 2: Verwenden von init von 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>
Sujay UN
quelle