Próbuję sprawdzić, czy istnieje prosty sposób na uzyskanie dostępu do wewnętrznego zakresu kontrolera za pomocą zewnętrznej funkcji JavaScript (całkowicie nieistotnej dla kontrolera docelowego)
Widziałem to na kilku innych pytaniach
angular.element("#scope").scope();
pobrałby zakres z elementu DOM, ale moje próby obecnie nie przynoszą odpowiednich wyników.
Oto jsfiddle: http://jsfiddle.net/sXkjc/5/
Obecnie przechodzę przez przejście od zwykłego JS do Angular. Głównym powodem, dla którego próbuję to osiągnąć, jest zachowanie mojego oryginalnego kodu biblioteki w jak największym stopniu nienaruszonym; oszczędzając mi potrzeby dodawania każdej funkcji do kontrolera.
Jakieś pomysły, jak mógłbym się do tego zabrać? Mile widziane są również komentarze do powyższych skrzypiec.
źródło
.scope()
wymaga, aby dane debugowania były włączone, ale używanie danych debugowania w środowisku produkcyjnym nie jest zalecane ze względu na szybkość. Poniższe rozwiązania wydają się obracać wokółscope()
Odpowiedzi:
Musisz użyć $ scope. $ Apply (), jeśli chcesz wprowadzić jakiekolwiek zmiany w wartości zasięgu spoza kontroli angularjs, takich jak obsługa zdarzeń jquery / javascript.
function change() { alert("a"); var scope = angular.element($("#outer")).scope(); scope.$apply(function(){ scope.msg = 'Superhero'; }) }
Demo: Fiddle
źródło
angular.element("#scope")
nie działa, chociażangular.element($("#scope"))
działa, musisz mieć również jqueryMinęło trochę czasu, odkąd opublikowałem to pytanie, ale biorąc pod uwagę opinie, które nadal wydaje się mieć, oto kolejne rozwiązanie, na które natknąłem się w ciągu ostatnich kilku miesięcy:
$scope.safeApply = function( fn ) { var phase = this.$root.$$phase; if(phase == '$apply' || phase == '$digest') { if(fn) { fn(); } } else { this.$apply(fn); } };
Powyższy kod tworzy w zasadzie funkcję o nazwie
safeApply
że Calles$apply
funkcyjne (jak wskazano w odpowiedzi na Arun) wtedy i tylko kątowe obecnie nie przeżywa na$digest
scenie. Z drugiej strony, jeśli Angular aktualnie przetrawia rzeczy, po prostu wykona funkcję tak, jak jest, ponieważ wystarczy to, aby zasygnalizować Angularowi, aby wprowadził zmiany.Podczas próby użycia
$apply
funkcji, gdy AngularJs jest obecnie na swoim$digest
etapie, występuje wiele błędów . PliksafeApply
kod jest bezpiecznym opakowaniem, które zapobiega takim błędom.(uwaga: osobiście lubię się wtrącać
safeApply
jako funkcję$rootScope
dla wygody)Przykład:
function change() { alert("a"); var scope = angular.element($("#outer")).scope(); scope.safeApply(function(){ scope.msg = 'Superhero'; }) }
Demo: http://jsfiddle.net/sXkjc/227/
źródło
Innym sposobem na to jest:
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'; })
źródło
możemy to nazwać po załadowaniu
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"); }); }
źródło
Minęło dużo czasu, odkąd zadałem to pytanie, ale oto odpowiedź, która nie wymaga jquery:
function change() { var scope = angular.element(document.querySelector('#outside')).scope(); scope.$apply(function(){ scope.msg = 'Superhero'; }) }
źródło
Oto rozwiązanie wielokrotnego użytku: 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'; }); };
źródło
Możesz też spróbować:
function change() { var scope = angular.element( document.getElementById('outer') ).scope(); scope.$apply(function(){ scope.msg = 'Superhero'; }) }
źródło
Przyjęta odpowiedź jest świetna. Chciałem przyjrzeć się, co dzieje się z teleskopem Angular w kontekście
ng-repeat
. Chodzi o to, że Angular utworzy podzakres dla każdego powtarzającego się elementu. Podczas wywoływania metody zdefiniowanej w oryginale$scope
, która zachowuje swoją pierwotną wartość (z powodu zamknięcia javascript). Jednakthis
odwołuje się do zakresu / obiektu wywołującego. To działa dobrze, o ile masz pewność, kiedy$scope
ithis
są takie same i gdy są one różne. hthOto skrzypce, które ilustrują różnicę: https://jsfiddle.net/creitzel/oxsxjcyc/
źródło
Jestem nowicjuszem, więc przepraszam, jeśli to zła praktyka. Na podstawie wybranej odpowiedzi wykonałem tę funkcję:
function x_apply(selector, variable, value) { var scope = angular.element( $(selector) ).scope(); scope.$apply(function(){ scope[variable] = value; }); }
Używam tego w ten sposób:
x_apply('#fileuploader', 'thereisfiles', true);
Przy okazji, przepraszam za mój angielski
źródło
<input type="text" class="form-control timepicker2" ng-model='programRow.StationAuxiliaryTime.ST88' />
dostęp do wartości zakresu
załóżmy, że programRow.StationAuxiliaryTime jest tablicą obiektów
$('.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); });
źródło
Musimy użyć wbudowanej funkcji Angular Js $ apply do zmiennych zakresu dostępu lub funkcji poza funkcją kontrolera.
Można to zrobić na dwa sposoby:
| * | Metoda 1: użycie identyfikatora:
<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>
| * | Metoda 2: Używanie init kontrolera 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>
źródło
Tak zrobiłem dla mojego
CRUDManager class
zainicjalizowanego w kontrolerze Angulara, który później przeszedł do zdarzenia kliknięcia przycisku jQuery zdefiniowanego poza kontrolerem :W kontrolerze kątowym:
// Note that I can even pass over the $scope to my CRUDManager's constructor. var crudManager = new CRUDManager($scope, contextData, opMode); crudManager.initialize() .then(() => { crudManager.dataBind(); $scope.crudManager = crudManager; $scope.$apply(); }) .catch(error => { alert(error); });
W jQuery Save button click event poza kontrolerem:
$(document).on("click", "#ElementWithNgControllerDefined #btnSave", function () { var ngScope = angular.element($("#ElementWithNgControllerDefined")).scope(); var crudManager = ngScope.crudManager; crudManager.saveData() .then(finalData => { alert("Successfully saved!"); }) .catch(error => { alert("Failed to save."); }); });
Jest to szczególnie ważne i przydatne, gdy zdarzenia jQuery muszą być umieszczone POZA KONTROLEREM , aby zapobiec dwukrotnemu uruchomieniu .
źródło