AngularJS access scope from outside js function

AngularjsAngularjs Scope

Angularjs Problem Overview


I'm trying to see if there's a simple way to access the internal scope of a controller through an external javascript function (completely irrelevant to the target controller)

I've seen on a couple of other questions here that

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

would retrieve the scope from a DOM element, but my attempts are currently yielding no proper results.

Here's the jsfiddle: http://jsfiddle.net/sXkjc/5/

I'm currently going through a transition from plain JS to Angular. The main reason I'm trying to achieve this is to keep my original library code intact as much as possible; saving the need for me to add each function to the controller.

Any ideas on how I could go about achieving this? Comments on the above fiddle are also welcome.

Angularjs Solutions


Solution 1 - Angularjs

You need to use $scope.$apply() if you want to make any changes to a scope value from outside the control of angularjs like a jquery/javascript event handler.

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

Demo: Fiddle

Solution 2 - Angularjs

It's been a while since I posted this question, but considering the views this still seems to get, here's another solution I've come upon during these last few months:

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

The above code basically creates a function called safeApply that calles the $apply function (as stated in Arun's answer) if and only Angular currently isn't going through the $digest stage. On the other hand, if Angular is currently digesting things, it will just execute the function as it is, since that will be enough to signal to Angular to make the changes.

Numerous errors occur when trying to use the $apply function while AngularJs is currently in its $digest stage. The safeApply code above is a safe wrapper to prevent such errors.

(note: I personally like to chuck in safeApply as a function of $rootScope for convenience purposes)

Example:

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

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

Solution 3 - Angularjs

Another way to do that is:

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';
})

Solution 4 - Angularjs

we can call it after loaded

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

Solution 5 - Angularjs

It's been a long time since I asked this question, but here's an answer that doesn't require jquery:

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

Solution 6 - Angularjs

Here's a reusable solution: 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';
    });

};

Solution 7 - Angularjs

You can also try:

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

Solution 8 - Angularjs

The accepted answer is great. I wanted to look at what happens to the Angular scope in the context of ng-repeat. The thing is, Angular will create a sub-scope for each repeated item. When calling into a method defined on the original $scope, that retains its original value (due to javascript closure). However, the this refers the calling scope/object. This works out well, so long as you're clear on when $scope and this are the same and when they are different. hth

Here is a fiddle that illustrates the difference: https://jsfiddle.net/creitzel/oxsxjcyc/

Solution 9 - Angularjs

I'm newbie, so sorry if is a bad practice. Based on the chosen answer, I did this function:

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

I'm using it this way:

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

By the way, sorry for my english

Solution 10 - Angularjs

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

accessing scope value

assume that programRow.StationAuxiliaryTime is an array of object

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

Solution 11 - Angularjs

We need to use Angular Js built in function $apply to acsess scope variables or functions outside the controller function.

This can be done in two ways :

|*| Method 1 : Using 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>

|*| Method 2 : Using 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>

Solution 12 - Angularjs

This is how I did for my CRUDManager class initialized in Angular controller, which later passed over to jQuery button-click event defined outside the controller:

In Angular Controller:

        // 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);
            });

In jQuery Save button click event outside the controller:

    $(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.");
            });
    });

This is particularly important and useful when your jQuery events need to be placed OUTSIDE OF CONTROLLER in order to prevent it from firing twice.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questiondk123View Question on Stackoverflow
Solution 1 - AngularjsArun P JohnyView Answer on Stackoverflow
Solution 2 - Angularjsdk123View Answer on Stackoverflow
Solution 3 - AngularjsCharlestonView Answer on Stackoverflow
Solution 4 - AngularjsfallwindView Answer on Stackoverflow
Solution 5 - Angularjsdk123View Answer on Stackoverflow
Solution 6 - AngularjsflobarView Answer on Stackoverflow
Solution 7 - Angularjsharish sharmaView Answer on Stackoverflow
Solution 8 - AngularjsCharlieView Answer on Stackoverflow
Solution 9 - AngularjsMrQwertyView Answer on Stackoverflow
Solution 10 - AngularjsSreerajView Answer on Stackoverflow
Solution 11 - AngularjsSujay U NView Answer on Stackoverflow
Solution 12 - AngularjsAntonio OoiView Answer on Stackoverflow