Область доступу AngularJS з-за функції js


131

Я намагаюся зрозуміти, чи існує простий спосіб отримати доступ до внутрішнього поля контролера через зовнішню функцію javascript (абсолютно не має значення для цільового контролера)

Я бачив у кількох інших питаннях ось це

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

Вам потрібно використовувати $ range. $ 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 range = angular.element ($ ("# external")). Area (); повинні бути оголошені всередині функції зміни? Якщо я переміщу його в глобальний простір, це не піде?
Марк М.

1
@MarcM. Я думаю, що це стосується сфери відпочинку Angular. На той час, коли ви використовуєте функцію зміни, попередня область, на яку вказував глобальний var, вже не може існувати (через рекреацію).
dk123

1
angular.element ($ ("div [ng-controller = 'myCtrl']")). area (); краще, ніж додатковий #outer в елементі div, я здогадуюсь
wyverny

1
domain () стає невизначеним, коли ми робимо: $ compileProvider.debugInfoEnabled (false); у кутовий. Тож як ми можемо змусити його працювати з debuginfoEnabled false?
Агноско

26

Минув час, коли я опублікував це питання, але зважаючи на думки, які, як видається, все ще отримують, ось ще одне рішення, на яке я прийшов протягом цих останніх кількох місяців:

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

Наведений вище код в основному створює функцію з ім'ям , safeApplyщо Кальєс $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 або $ digest, в іншому випадку використовуйте $ apply () для застосування функції" .... Але якщо ви виконуєте функцію самостійно. .. як це оновлення будь-яких моделей? Здається, це не було б сприятливою поведінкою, якщо б там щось не відбувалося, я не знаю про це. Чи працює якийсь механізм у Angular, опитуючи область $ для змін, які можуть відбутися безпосередньо з ним ???
trusktr

Плюс, якщо вам потрібно захиститись від цих станів, то я вважаю, що помилка методу $ apply (), яку потрібно виправити.
trusktr

@trusktr З того, що я розумію, виконання функції зазвичай сприймається кутовим, якщо функція змінює будь-які моделі, а значить, кутова оновлює їх на наступному етапі дайджесту.
dk123

@trusktr Я погоджуюся, що якщо нормальний $ apply () може бути застосований без гарантій, нічого кращого не буде. По суті, єдиною метою SafeApply є захист від помилок $ apply (). Не впевнений, якщо це питання, про який повідомлялося, і тепер виправлено, чи все ще триває.
dk123

1
Просто тому, що я наткнувся на це: github.com/angular/angular.js/wiki/When-to-use-$scope.$apply () . _Якщо ви робите, якщо (! $ Obseg. $$ фаза) $ область. $ Застосовується () це тому, що ви недостатньо високі в стеку викликів._
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, він зберігає своє початкове значення (через закриття javascript). Однак 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 для доступа змінних областей або функцій, що знаходяться поза функцією контролера.

Це можна зробити двома способами:

| * | Спосіб 1: Використання ідентифікатора:

<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-контролера:

<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>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.