Ambito di accesso AngularJS dalla funzione js esterna


131

Sto cercando di vedere se esiste un modo semplice per accedere all'ambito interno di un controller tramite una funzione javascript esterna (completamente irrilevante per il controller di destinazione)

Ho visto qui un paio di altre domande

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

recupererebbe l'ambito da un elemento DOM, ma i miei tentativi attualmente non stanno producendo risultati adeguati.

Ecco il jsfiddle: http://jsfiddle.net/sXkjc/5/

Attualmente sto attraversando una transizione dal semplice JS all'angolare. Il motivo principale per cui sto cercando di raggiungere questo obiettivo è mantenere il codice della mia libreria originale il più possibile integro; risparmiando la necessità per me di aggiungere ogni funzione al controller.

Qualche idea su come potrei fare per raggiungere questo obiettivo? Anche i commenti sul violino sopra sono ben accetti.


La FYI secondo i documenti che utilizzano .scope()richiede che i dati di debug siano abilitati, ma l' uso dei dati di debug in produzione non è raccomandato per motivi di velocità. Le soluzioni che seguono sembrano ruotare intornoscope()
rtpHarry il

@rtpHarry ha ragione. Le risposte di seguito che richiedono l'utilizzo di scope () sono deprecate. Vedere la mia risposta qui stackoverflow.com/a/34078750/319302
Cagatay Kalan

Risposte:


223

È necessario utilizzare $ scope. $ Apply () se si desidera apportare modifiche a un valore di ambito al di fuori del controllo di angularjs come un gestore di eventi jquery / javascript.

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

Demo: violino


2
@ dk123 angular.element("#scope")non funziona, anche se angular.element($("#scope"))funziona, devi avere anche jquery
Arun P Johny

1
So che è passato del tempo, ma spero che qualcuno possa rispondermi su questo ... Perché var scope = angular.element ($ ("# external")). Scope (); deve essere dichiarato all'interno della funzione di modifica? Se lo sposto nello spazio globale è un non andare?
Marc M.

1
@MarcM. Penso che abbia a che fare con la ricreazione dell'ambito di Angular. Quando si utilizza la funzione di modifica, l'ambito precedente a cui puntava la var globale potrebbe non esistere più (a causa della ricreazione).
dk123

1
angular.element ($ ( "div [ng-Controller = 'myCtrl']")) portata ().; è meglio di #outer aggiuntivo nell'elemento div, immagino
wyverny

1
scope () diventa indefinito quando lo facciamo: $ compileProvider.debugInfoEnabled (false); in angolare. Quindi, come possiamo farlo funzionare con debuginfoEnabled falso?
Agnosco,

26

È passato un po 'di tempo da quando ho pubblicato questa domanda, ma considerando le opinioni che sembra ancora ottenere, ecco un'altra soluzione che ho trovato in questi ultimi mesi:

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

Il codice sopra in sostanza crea una funzione chiamata safeApplyche chiama la $applyfunzione (come indicato nella risposta di Arun) se e attualmente solo Angular non sta attraversando lo $digeststage. D'altra parte, se Angular sta attualmente digerendo le cose, eseguirà semplicemente la funzione così com'è, poiché sarà sufficiente per segnalare ad Angular di apportare le modifiche.

Numerosi errori si verificano quando si tenta di utilizzare la $applyfunzione mentre AngularJs è attualmente nella sua $digestfase. Il safeApplycodice sopra è un wrapper sicuro per prevenire tali errori.

(nota: personalmente mi piace lanciarmi in safeApplyfunzione $rootScopeper motivi di praticità)

Esempio:

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

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


1
Perché la funzione safeApply funziona? Sembra che quello che stai dicendo sia "esegui la funzione da solo se Angular è nelle fasi $ apply o $ digest, altrimenti usa $ apply () per applicare la funzione" .... Ma se esegui la funzione da sola .. .. come si aggiorna qualche modello? Sembra che non sarebbe un comportamento favorevole, a meno che non stia succedendo qualcosa di cui non sono a conoscenza. Qualche meccanismo in Angular fa sondare $ scope per i cambiamenti che potrebbero essersi verificati direttamente ???
trusktr,

Inoltre, se hai bisogno di salvaguardarti da quegli stati, considererei che un bug del metodo $ apply () che deve essere corretto.
trusktr,

@trusktr Da quanto ho capito, l'esecuzione della funzione normalmente viene catturata da angolare se la funzione cambia qualche modello, e quindi angolare li aggiorna nella fase digest successiva.
dk123,

@trusktr Concordo però sul fatto che se il normale $ apply () può essere applicato senza le garanzie, non ci sarebbe niente di meglio. In sostanza, l'unico scopo di safeApply è di salvaguardare dagli errori $ apply (). Non sono sicuro se questo fosse un problema segnalato e ora risolto, o ancora in corso.
dk123,

1
Solo perché me ne sono imbattuto: github.com/angular/angular.js/wiki/When-to-use-$scope.$apply () . _Se stai facendo se (! $ Scope. $$ phase) $ scope. $ Apply () è perché non sei abbastanza alto nello stack di chiamate ._
scheffield

17

Un altro modo per farlo è:

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
Non capisco ancora perché questo commento non sia la risposta migliore per questo. Dopo aver scavato Internet per un paio di giorni, con frustrazione e rabbia, finalmente questo è ciò che ha risolto il mio problema. Grazie @Charleston. Sei grande, signore!
Rajkumar,

13

possiamo chiamarlo dopo aver caricato

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

È da tanto tempo che non faccio questa domanda, ma ecco una risposta che non richiede jquery:

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

3

Ecco una soluzione riutilizzabile: 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

Puoi anche provare:

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

@ dk123 anche questa dose non richiede JQuery.
harish sharma,

1

La risposta accettata è ottima. Volevo vedere cosa succede all'ambito angolare nel contesto di ng-repeat. Il fatto è che Angular creerà un sotto-ambito per ogni elemento ripetuto. Quando si chiama un metodo definito sull'originale $scope, questo mantiene il suo valore originale (a causa della chiusura di JavaScript). Tuttavia, thisfa riferimento all'ambito / oggetto chiamante. Funziona bene, a patto che tu sia chiaro su quando $scopee thissono gli stessi e quando sono diversi. hth

Ecco un violino che illustra la differenza: https://jsfiddle.net/creitzel/oxsxjcyc/


1

Sono un novizio, mi dispiace se è una cattiva pratica. Sulla base della risposta scelta, ho svolto questa funzione:

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

Lo sto usando in questo modo:

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

A proposito, scusami per il mio inglese


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

accesso al valore dell'ambito

supponiamo che programRow.StationAuxitimeTime sia un array di oggetti

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

Dobbiamo usare la funzione angolare J integrata $ si applica alle variabili dell'ambito di accesso o alle funzioni esterne alla funzione del controller.

Questo può essere fatto in due modi :

| * | Metodo 1: Utilizzo dell'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>

| * | Metodo 2: utilizzando init di 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>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.