Ruang lingkup akses AngularJS dari luar fungsi js

131

Saya mencoba melihat apakah ada cara sederhana untuk mengakses ruang lingkup internal pengontrol melalui fungsi javascript eksternal (sama sekali tidak relevan dengan pengontrol target)

Saya telah melihat beberapa pertanyaan lain di sini

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

akan mengambil lingkup dari elemen DOM, tetapi upaya saya saat ini tidak menghasilkan hasil yang tepat.

Inilah jsfiddle: http://jsfiddle.net/sXkjc/5/

Saat ini saya sedang melalui transisi dari JS polos ke Angular. Alasan utama saya berusaha mencapai ini adalah untuk menjaga kode perpustakaan asli saya sebanyak mungkin; menghemat kebutuhan bagi saya untuk menambahkan setiap fungsi ke controller.

Ada ide tentang bagaimana saya bisa mencapai ini? Komentar tentang biola di atas juga diterima.

dk123
sumber
FYI menurut dokumen menggunakan .scope()mengharuskan Data Debug untuk diaktifkan tetapi menggunakan Data Debug dalam produksi tidak dianjurkan karena alasan kecepatan. Solusi di bawah ini sepertinya berputar di sekitarscope()
rtpHarry
@rtpHarry benar. Jawaban di bawah ini yang membutuhkan penggunaan lingkup () sudah usang. Lihat jawaban saya di sini stackoverflow.com/a/34078750/319302
Cagatay Kalan

Jawaban:

223

Anda perlu menggunakan $ scope. $ Apply () jika Anda ingin membuat perubahan pada nilai scope dari luar kendali angularjs seperti event handler jquery / javascript.

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

Demo: Biola

Arun P Johny
sumber
2
@ dk123 angular.element("#scope")tidak berfungsi, meskipun angular.element($("#scope"))berfungsi, Anda harus memiliki jquery juga
Arun P Johny
1
Saya tahu ini sudah lama, tapi saya harap beberapa bisa menjawab saya tentang ini ... Mengapa var scope = angular.element ($ ("# outer")). Scope (); harus dideklarasikan di dalam fungsi perubahan? Jika saya memindahkannya ke ruang global, itu tidak boleh?
Marc M.
1
@MarcM. Saya pikir itu ada hubungannya dengan ruang lingkup rekreasi Angular. Pada saat Anda menggunakan fungsi perubahan, ruang lingkup sebelumnya var global tunjuk mungkin sudah tidak ada lagi (karena rekreasi).
dk123
1
angular.element ($ ("div [ng-controller = 'myCtrl']")). scope (); lebih baik daripada #outer tambahan dalam elemen div, saya kira
wyverny
1
scope () tidak terdefinisi ketika kita melakukannya: $ compileProvider.debugInfoEnabled (false); dalam sudut. Jadi bagaimana kita membuatnya bekerja dengan debuginfoEnabled palsu?
Agnosco
26

Sudah lama sejak saya memposting pertanyaan ini, tetapi mengingat pandangan yang sepertinya masih ada, inilah solusi lain yang saya dapatkan selama beberapa bulan terakhir ini:

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

Kode di atas pada dasarnya menciptakan fungsi yang disebut safeApplyyang calles yang $applyfungsi (seperti yang dinyatakan dalam jawaban Arun) jika dan hanya sudut saat tidak akan melalui satu $digesttahap. Di sisi lain, jika Angular saat ini sedang mencerna hal-hal, itu hanya akan menjalankan fungsi seperti itu, karena itu akan cukup untuk memberi sinyal ke Angular untuk melakukan perubahan.

Banyak kesalahan terjadi ketika mencoba menggunakan $applyfungsi saat AngularJs sedang dalam $digesttahap. The safeApplykode di atas adalah pembungkus yang aman untuk mencegah kesalahan tersebut.

(catatan: Saya pribadi suka membuang safeApplysebagai fungsi $rootScopeuntuk keperluan kenyamanan)

Contoh:

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

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

dk123
sumber
1
Mengapa fungsi safeApply Anda berfungsi? Sepertinya apa yang Anda katakan adalah "jalankan fungsi dengan sendirinya jika Angular berada dalam tahap $ apply atau $ digest, jika tidak gunakan $ apply () untuk menerapkan fungsi" .... Tetapi jika Anda menjalankan fungsi dengan sendirinya .. .. Bagaimana cara memperbarui model apa pun? Sepertinya itu bukan perilaku yang menguntungkan, kecuali ada sesuatu yang terjadi yang tidak saya ketahui. Apakah beberapa mekanisme di Angular melakukan polling dengan $ scope untuk perubahan yang mungkin terjadi secara langsung?
trusktr
Plus, jika Anda perlu melindungi terhadap keadaan tersebut, maka saya akan mempertimbangkan bahwa bug dari metode $ apply () yang perlu diperbaiki.
trusktr
@trusktr Dari apa yang saya mengerti, menjalankan fungsi biasanya ditangkap oleh sudut jika fungsi mengubah model apa pun, dan karenanya sudut memperbarui mereka di tahap intisari berikutnya.
dk123
@trusktr Saya setuju bahwa jika $ normal berlaku () dapat diterapkan tanpa perlindungan, tidak akan ada yang lebih baik. Pada dasarnya, satu-satunya tujuan safeApply adalah untuk melindungi terhadap kesalahan $ apply (). Meskipun tidak yakin apakah ini masalah yang dilaporkan dan sekarang sudah diperbaiki, atau masih merupakan masalah yang berkelanjutan.
dk123
1
Hanya karena saya tersandung: github.com/angular/angular.js/wiki/When-to-use-$scope.$apply () . _Jika Anda melakukan if (! $ Scope. $$ phase) $ scope. $ Apply () itu karena Anda tidak cukup tinggi dalam panggilan stack._
scheffield
17

Cara lain untuk melakukannya adalah:

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
sumber
1
Saya masih tidak mengerti mengapa komentar ini bukan jawaban terbaik untuk ini. Setelah menggali internet selama beberapa hari, dengan frustrasi dan kemarahan, akhirnya ini yang memecahkan masalah saya. @Charleston terima kasih. Anda hebat, tuan!
Rajkumar
13

kita bisa menyebutnya setelah dimuat

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");
    });
}
musim gugur
sumber
8

Sudah lama sejak saya mengajukan pertanyaan ini, tapi inilah jawaban yang tidak memerlukan jquery:

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

Inilah solusi yang dapat digunakan kembali: 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
sumber
2

Anda juga dapat mencoba:

function change() {
    var scope = angular.element( document.getElementById('outer') ).scope();
    scope.$apply(function(){
        scope.msg = 'Superhero';
    })
}
harish sharma
sumber
@ dk123 dosis ini juga tidak memerlukan JQuery.
harish sharma
1

Jawaban yang diterima sangat bagus. Saya ingin melihat apa yang terjadi pada ruang lingkup sudut dalam konteks ng-repeat. Masalahnya, Angular akan membuat sub-lingkup untuk setiap item yang diulang. Saat memanggil ke metode yang ditentukan pada aslinya $scope, yang mempertahankan nilai aslinya (karena penutupan javascript). Namun, thismerujuk pada ruang lingkup panggilan / objek. Ini bekerja dengan baik, selama Anda jelas kapan $scopedan thissama dan kapan mereka berbeda. hth

Berikut adalah biola yang menggambarkan perbedaannya: https://jsfiddle.net/creitzel/oxsxjcyc/

Charlie
sumber
1

Saya pemula, sangat menyesal jika ini adalah praktik yang buruk. Berdasarkan jawaban yang dipilih, saya melakukan fungsi ini:

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

Saya menggunakannya dengan cara ini:

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

Omong-omong, maaf untuk bahasa Inggris saya

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

mengakses nilai ruang lingkup

menganggap bahwa programRow.StationAuxiliaryTime adalah array objek

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

Kita perlu menggunakan Angular Js built in function $ berlaku untuk variabel lingkup acsess atau fungsi di luar fungsi controller.

Ini dapat dilakukan dengan dua cara:

| * | Metode 1: Menggunakan 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>

| * | Metode 2: Menggunakan init of 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
sumber