Escopo de acesso AngularJS a partir da função js externa

131

Estou tentando ver se existe uma maneira simples de acessar o escopo interno de um controlador através de uma função javascript externa (completamente irrelevante para o controlador de destino)

Eu já vi em algumas outras perguntas aqui que

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

recuperaria o escopo de um elemento DOM, mas minhas tentativas atualmente não estão produzindo resultados adequados.

Aqui está o jsfiddle: http://jsfiddle.net/sXkjc/5/

Atualmente, estou passando por uma transição do JS simples para o Angular. A principal razão pela qual estou tentando conseguir isso é manter o código da biblioteca original intacto, tanto quanto possível; economizando a necessidade de adicionar cada função ao controlador.

Alguma idéia de como eu poderia conseguir isso? Comentários sobre o violino acima também são bem-vindos.

dk123
fonte
Para sua informação, de acordo com os documentos, é .scope()necessário ativar os Dados de depuração, mas o uso de Dados de depuração na produção não é recomendado por motivos de velocidade. As soluções abaixo parecem girar em torno descope()
rtpHarry
@rtpHarry está certo. As respostas abaixo, que requerem o uso de scope (), foram descontinuadas. Veja minha resposta aqui stackoverflow.com/a/34078750/319302
Cagatay Kalan

Respostas:

223

Você precisa usar $ scope. $ Apply () se quiser fazer alterações em um valor de escopo fora do controle de angularjs, como um manipulador de eventos jquery / javascript.

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

Demo: Fiddle

Arun P Johny
fonte
2
@ dk123 angular.element("#scope")não está funcionando, embora angular.element($("#scope"))está trabalhando, você precisa ter jquery também
Arun P Johny
1
Eu sei que já faz um tempo, mas espero que alguns possam me responder sobre isso ... Por que var scope = angular.element ($ ("# outer")). Scope (); tem que ser declarado dentro da função de mudança? Se eu mudar para o espaço global, é impossível.
Marc M.
1
@MarcM. Eu acho que tem a ver com a recreação da Angular. Quando você usa a função de alteração, o escopo anterior para o qual o var global estava apontando pode não existir mais (devido à recreação).
precisa
1
angular.element ($ ("div [ng-controller = 'myCtrl']")). scope (); é melhor do que #outer adicional na div elemento, eu acho
wyverny
1
scope () fica indefinido quando fazemos: $ compileProvider.debugInfoEnabled (false); em angular. Então, como podemos fazê-lo funcionar com debuginfoEnabled false?
Agnosco 24/05
26

Já faz um tempo desde que eu postei essa pergunta, mas, considerando os pontos de vista que isso ainda parece ter, aqui está outra solução que encontrei durante esses últimos meses:

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

O código acima, basicamente cria uma função chamada safeApplyque calles a $applyfunção (como indicado na resposta de Arun) se e somente angular actualmente não está a atravessar o $digestpalco. Por outro lado, se o Angular estiver digerindo atualmente coisas no momento, ele executará a função como está, pois será suficiente para sinalizar ao Angular para fazer as alterações.

Inúmeros erros ocorrem ao tentar usar a $applyfunção enquanto AngularJs está atualmente em seu $digestestágio. O safeApplycódigo acima é um invólucro seguro para evitar esses erros.

(nota: eu pessoalmente gosto de participar safeApplycomo uma função de$rootScope para fins de conveniência)

Exemplo:

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

Demonstração: http://jsfiddle.net/sXkjc/227/

dk123
fonte
1
Por que sua função safeApply funciona? Parece que o que você está dizendo é "execute a função sozinho se Angular estiver nos estágios $ apply ou $ digest, caso contrário, use $ apply () para aplicar a função" .... Mas se você executar a função por si só .. .. como isso atualiza alguns modelos? Parece que isso não seria um comportamento favorável, a menos que haja algo acontecendo que eu não saiba. Algum mecanismo no Angular faz uma pesquisa sobre o escopo $ para alterações que podem ter acontecido diretamente com ele ???
trusktr
Além disso, se você precisar se proteger contra esses estados, consideraria um bug do método $ apply () que precisa ser corrigido.
trusktr
@trusktr Pelo que entendi, a execução da função normalmente é capturada pelo angular se a função alterar algum modelo e, portanto, o angular os atualiza no próximo estágio de resumo.
dk123
@trusktr Eu concordo que, se o $ apply normal () puder ser aplicado sem as salvaguardas, não haveria nada melhor. Em essência, o único objetivo do safeApply é proteger contra os erros $ apply (). Não tenho certeza se este foi um problema relatado e agora foi corrigido ou ainda está em andamento.
dk123
1
Só porque eu tropecei nele: github.com/angular/angular.js/wiki/When-to-use-$scope.$apply () . _Se você estiver fazendo if (! $ Scope. $$ phase) $ scope. $ Apply () é porque você não é alto o suficiente na pilha de chamadas._ #
scheffield
17

Outra maneira de fazer isso é:

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
fonte
1
Ainda não entendo por que esse comentário não é a melhor resposta para isso. Depois de pesquisar na internet por alguns dias, com frustração e raiva, finalmente foi isso que resolveu meu problema. Obrigado @Charleston. Você é ótimo, senhor!
Rajkumar
13

podemos chamá-lo depois de carregado

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

Já faz muito tempo desde que eu fiz essa pergunta, mas aqui está uma resposta que não requer jquery:

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

Aqui está uma solução reutilizável: 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
fonte
2

Você também pode tentar:

function change() {
    var scope = angular.element( document.getElementById('outer') ).scope();
    scope.$apply(function(){
        scope.msg = 'Superhero';
    })
}
harish sharma
fonte
@ dk123 isso também não requer JQuery.
Sharma harish
1

A resposta aceita é ótima. Eu queria ver o que acontece com o escopo Angular no contexto de ng-repeat. O problema é que o Angular criará um sub-escopo para cada item repetido. Ao chamar um método definido no original $scope, ele mantém seu valor original (devido ao fechamento do javascript). No entanto, thisrefere - se ao escopo / objeto de chamada. Isso funciona bem, desde que você tenha certeza de quando $scopeethis é o mesmo e quando eles são diferentes. hth

Aqui está um violino que ilustra a diferença: https://jsfiddle.net/creitzel/oxsxjcyc/

Charlie
fonte
1

Eu sou novato, desculpe se é uma má prática. Com base na resposta escolhida, fiz esta função:

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

Estou usando desta maneira:

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

A propósito, desculpe pelo meu inglês

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

acessando o valor do escopo

suponha que programRow.StationAuxiliaryTime é uma matriz de objetos

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

Precisamos usar a função incorporada Js angulares $ aplicar a variáveis ​​de escopo de acesso ou funções fora da função do controlador.

Isso pode ser feito de duas maneiras:

| * | Método 1: usando o 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>

| * | Método 2: Usando o init do 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
fonte