ขอบเขตการเข้าถึง AngularJS จากฟังก์ชัน js ภายนอก


131

ฉันกำลังพยายามดูว่ามีวิธีง่ายๆในการเข้าถึงขอบเขตภายในของคอนโทรลเลอร์หรือไม่ผ่านฟังก์ชั่นจาวาสคริปต์ภายนอก (ไม่เกี่ยวข้องกับตัวควบคุมเป้าหมายอย่างสมบูรณ์)

ฉันเคยเห็นคำถามอื่น ๆ สองสามข้อที่นี่

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

จะดึงขอบเขตจากองค์ประกอบ DOM แต่ความพยายามของฉันในขณะนี้ไม่ได้ผลลัพธ์ที่เหมาะสม

นี่คือ jsfiddle: http://jsfiddle.net/sXkjc/5/

ฉันกำลังจะเปลี่ยนจาก JS ธรรมดาไปเป็น Angular เหตุผลหลักที่ฉันพยายามทำให้สำเร็จคือการรักษารหัสห้องสมุดเดิมของฉันให้สมบูรณ์มากที่สุด ประหยัดความจำเป็นสำหรับฉันในการเพิ่มแต่ละฟังก์ชันลงในคอนโทรลเลอร์

มีความคิดเห็นเกี่ยวกับวิธีที่ฉันจะบรรลุเป้าหมายนี้ได้อย่างไร ยินดีรับฟังความคิดเห็นเกี่ยวกับซอข้างต้นด้วย


FYI ตามเอกสารที่ใช้.scope()ต้องการให้เปิดใช้งานข้อมูลการดีบักแต่ไม่แนะนำให้ใช้ข้อมูลการแก้ปัญหาในการผลิตเนื่องจากเหตุผลด้านความเร็ว คำตอบด้านล่างดูเหมือนจะหมุนรอบscope()
rtpHarry

@rtpHarry พูดถูก คำตอบด้านล่างซึ่งต้องใช้ขอบเขต () ถูกเลิกใช้แล้ว ดูคำตอบของฉันที่นี่stackoverflow.com/a/34078750/319302
Cagatay Kalan

คำตอบ:


223

คุณต้องใช้$ scope $ apply ()หากคุณต้องการเปลี่ยนแปลงค่าขอบเขตจากภายนอกการควบคุม angularjs เช่นตัวจัดการเหตุการณ์ jquery / javascript

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

การสาธิต: Fiddle


2
@ dk123 angular.element("#scope")ไม่ทำงานแม้ว่าangular.element($("#scope"))จะใช้งานได้คุณต้องมี jquery ด้วย
Arun P Johny

1
ฉันรู้มาระยะหนึ่งแล้ว แต่ฉันหวังว่าจะมีบางคนตอบฉันได้ในเรื่องนี้ ... ทำไม var scope = angular.element ($ ("# outer")) ขอบเขต (); ต้องประกาศภายในฟังก์ชันการเปลี่ยนแปลงหรือไม่ ถ้าฉันย้ายไปยังอวกาศทั่วโลกก็ไม่ต้องไป?
Marc M.

1
@MarcM ฉันคิดว่ามันเกี่ยวข้องกับขอบเขตการพักผ่อนหย่อนใจของ Angular เมื่อคุณใช้ฟังก์ชันการเปลี่ยนแปลงขอบเขตก่อนหน้านี้ที่ global var ชี้ไปอาจไม่มีอยู่อีกต่อไป (เนื่องจากการพักผ่อนหย่อนใจ)
dk123

1
angular.element ($ ( "div [ng คอนโทรลเลอร์ = 'myCtrl']")) ขอบเขต (). ดีกว่า #outer เพิ่มเติมในองค์ประกอบ div ฉันเดา
wyverny

1
ขอบเขต () ไม่ได้กำหนดเมื่อเราทำ: $ compileProvider.debugInfoEnabled (false); ในเชิงมุม แล้วเราจะทำให้มันทำงานกับ debuginfoEnabled false ได้อย่างไร?
Agnosco

26

เป็นเวลานานแล้วที่ฉันโพสต์คำถามนี้ แต่เมื่อพิจารณาถึงมุมมองที่ดูเหมือนว่าจะได้รับนี่เป็นวิธีแก้ปัญหาอื่นที่ฉันพบในช่วงสองสามเดือนที่ผ่านมานี้:

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

รหัสข้างต้นโดยทั่วไปสร้างฟังก์ชั่นที่เรียกว่าsafeApplyที่ Calles $applyฟังก์ชั่น (ตามที่ระบุไว้ในคำตอบของอรุณ) ถ้าและเพียงเชิงมุมในขณะนี้จะไม่ผ่าน$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/


1
เหตุใดฟังก์ชัน safeApply ของคุณจึงใช้งานได้ ดูเหมือนว่าสิ่งที่คุณกำลังพูดคือ "เรียกใช้ฟังก์ชันด้วยตัวเองหาก Angular อยู่ในขั้นตอน $ ใช้หรือ $ แยกย่อยหรือใช้ $ apply () เพื่อใช้ฟังก์ชัน" .... แต่ถ้าคุณเรียกใช้ฟังก์ชันด้วยตัวเอง .. .. ว่าจะอัพเดตรุ่นใดบ้าง? ดูเหมือนว่าจะไม่เป็นพฤติกรรมที่ดีเว้นแต่จะมีบางอย่างเกิดขึ้นที่ฉันไม่รู้ กลไกบางอย่างใน Angular ไปสำรวจขอบเขต $ สำหรับการเปลี่ยนแปลงที่อาจเกิดขึ้นโดยตรงกับมันหรือไม่ ???
trusktr

นอกจากนี้หากคุณต้องการป้องกันรัฐเหล่านั้นฉันจะพิจารณาว่าข้อบกพร่องของวิธี $ ใช้ () ที่ต้องได้รับการแก้ไข
trusktr

@trusktr จากสิ่งที่ฉันเข้าใจการเรียกใช้ฟังก์ชันตามปกติจะถูกจับโดยเชิงมุมหากฟังก์ชันเปลี่ยนรูปแบบใด ๆ และด้วยเหตุนี้เชิงมุมจะอัปเดตในขั้นตอนการย่อยถัดไป
dk123

@trusktr ฉันยอมรับว่าหากสามารถใช้ $ สมัคร () ปกติได้โดยไม่มีการป้องกันก็จะไม่มีอะไรดีไปกว่า โดยพื้นฐานแล้วจุดประสงค์เดียวของ safeApply คือเพื่อป้องกันข้อผิดพลาด $ apply () ไม่แน่ใจว่านี่เป็นปัญหาที่ได้รับการรายงานและได้รับการแก้ไขแล้วหรือยังคงเป็นปัญหาต่อเนื่อง
dk123

1
เพียงเพราะฉันสะดุดมันgithub.com/angular/angular.js/wiki/When-to-use-$scope.$apply () _ หากคุณกำลังทำ if (! $ scope. $$ phase) $ scope $ apply () เป็นเพราะคุณไม่สูงพอใน call stack _
scheffield

17

อีกวิธีที่ทำได้คือ:

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
ฉันยังไม่เข้าใจว่าทำไมความคิดเห็นนี้จึงไม่ใช่คำตอบที่ดีที่สุดสำหรับเรื่องนี้ หลังจากขุดอินเทอร์เน็ตมาสองสามวันด้วยความหงุดหงิดและโกรธในที่สุดนี่คือสิ่งที่แก้ปัญหาของฉันได้ ขอบคุณ @Charleston คุณเยี่ยมมากครับ!
Rajkumar

13

เราสามารถเรียกมันได้หลังจากโหลดแล้ว

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

เป็นเวลานานแล้วที่ฉันถามคำถามนี้ แต่นี่คือคำตอบที่ไม่ต้องใช้ jquery:

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

3

นี่คือวิธีแก้ปัญหาที่ใช้ซ้ำได้: 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

คุณยังสามารถลอง:

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

@ dk123 ขนาดนี้ยังไม่ต้องใช้ JQuery
harish sharma

1

คำตอบที่ได้รับการยอมรับนั้นยอดเยี่ยมมาก ฉันต้องการดูว่าเกิดอะไรขึ้นกับขอบเขตเชิงมุมในบริบทของng-repeat. สิ่งนี้คือ Angular จะสร้างขอบเขตย่อยสำหรับแต่ละรายการที่ทำซ้ำ เมื่อเรียกใช้เมธอดที่กำหนดไว้ในต้นฉบับ$scopeนั้นจะยังคงรักษาค่าเดิมไว้ (เนื่องจากการปิดจาวาสคริปต์) อย่างไรก็ตามthisหมายถึงขอบเขตการเรียก / วัตถุ นี้ทำงานออกมาได้ดีตราบใดที่คุณชัดเจนเมื่อ$scopeและthisที่เหมือนกันและเมื่อพวกเขาจะแตกต่างกัน HTH

นี่คือซอที่แสดงให้เห็นถึงความแตกต่าง: https://jsfiddle.net/creitzel/oxsxjcyc/


1

ฉันเป็นมือใหม่ขออภัยหากเป็นการปฏิบัติที่ไม่ดี จากคำตอบที่เลือกฉันทำหน้าที่นี้:

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

ฉันใช้วิธีนี้:

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

ขอโทษสำหรับภาษาอังกฤษของฉัน


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

เข้าถึงค่าขอบเขต

สมมติว่า programRow.StationAuxiliaryTime เป็นอาร์เรย์ของวัตถุ

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

เราจำเป็นต้องใช้ Angular Js ที่สร้างขึ้นในฟังก์ชัน$ ใช้กับตัวแปรขอบเขต acsess หรือฟังก์ชันภายนอกฟังก์ชันคอนโทรลเลอร์

สามารถทำได้สองวิธี:

| * | วิธีที่ 1: การใช้ 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>

| * | วิธีที่ 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>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.