5

I'm building a HTML-app with the AngularJS framework. I have some legacy JavaScript actions that needs to access a function within the Angular-object, and I can't get it to work.
This is the Angular-object (function I need to access is the $scope.info()):

function content($scope) {
    $scope.info = function (id) {
        console.log('Got a call from '+id);
        $scope.text = "Hello, "+id;
    };
}

I have attempted to access it through angular.element('content').scope().info('me'), but with no result (console says undefined). I attempted to dump the result of angular.element('content').scope(), and I got the full object list and everything. Theoretically, my first example should work, however it does not.

Any guidance as to how I can achieve this is much appreciated!
(PS: Call Angular JS from legacy code did not resolve this).


When I was finally able to access the function, it didn't work as expected – the value of $scope.text is technically modified, but the expressions used in the HTML are not updated! For example, <p>{{text}}</p>does not get updated after this function is called from an external function.

Is there any way to fix this?

Community
  • 1
  • 1
Emil
  • 7,220
  • 17
  • 76
  • 135

2 Answers2

24

angular.element() expects a DOM element, so if you have this html:

<div ng-controller="content">
</div>

and you want to access its DOM element, use an id:

<div id="myDiv" ng-controller="content">
</div>

Then

angular.element($('#myDiv')).scope().info('me')

or without jQuery:

angular.element(document.getElementById('myDiv')).scope().info('me')

should work.

Edit:

If you changed something on the scope, you will probably need to use $apply():

angular.element(document.getElementById('myDiv')).scope().$apply();
Maximilian Riegler
  • 22,720
  • 4
  • 62
  • 71
asgoth
  • 35,552
  • 12
  • 89
  • 98
  • That did work indeed! Though something unexpected happens: the function runs, but if I the function accesses one of the scope's expressions, it does not get updated in the controller. – Emil Jan 12 '13 at 22:38
  • Also, is there any reason this would return `Uncaught ReferenceError: $ is not defined` when called within a function? – Emil Jan 12 '13 at 22:48
  • Do you have jQuery in your page? – asgoth Jan 12 '13 at 22:49
  • if you don't have jquery, try angular.element(document.getElementById('#myDiv')).scope().info('me') – asgoth Jan 12 '13 at 22:52
  • Ah, I don't have jQuery, no. For some reason, it does not work without jQuery, guess I'll have to implement it :) – Emil Jan 12 '13 at 23:01
  • There still is one problem however – the Angular-function's expressions are not updated if the function change their values when called from the outside. I'll update the question. – Emil Jan 12 '13 at 23:06
  • Ah, great! I'm really new to all of this, I am seriously building my first Angular website today. My first website in general really. Oh well, thank you so much! – Emil Jan 12 '13 at 23:19
  • @catwoman make sure you are doing `angular.element($('#myDiv')).scope().$apply();` and not `angular.element($('#myDiv')).scope().info('me').$apply();` – bbodenmiller Apr 28 '14 at 08:44
  • 2
    For the non jquery examples, there should be no hash in getElementById('#myDiv') – KevInSol Jan 08 '15 at 13:42
  • Thanks, I was missing controller declaration. – Krishan Kumar Nov 23 '20 at 06:52
0

For me, I was trying to access/set angular's values from a callback (in another Window); the solution was to use jQuery's data methods. The data API allows you to attach object literals to DOM nodes. So instead of resorting to something like global variables (which would also work), I just do something like:

/**
 * Listen to a global "lookupTemplate" event
 */
$j(document).on("lookupTemplate", function(event, template) {
        $j(document).data("template", template);
        window.open("/callbackURL", 'Callback Window', 'status=0,toolbar=0,height=230,width=358');
    });

/**
* Callback from other window, to change template ID and name (it's global)
* @param {String} template_id the ID for the selected template from the other window
* @param {String} template_name the name for the selected template from the other window
*/
function templateChosen(template_id, template_name) {
    var template = $(document).data("template");
    var appendedSelector = "[" + template.index + "]";
    $('[name="templateId' + appendedSelector + '"').val(template_id);
    $('[name="templateName' + appendedSelector + '"').val(template_name);
    // Update angular vars just in case
    template.id = template_id;
    template.name = template_name;
}

var app = angular.module("app", []).controller("ActionsController", function($scope) {
        $scope.actions = [];
        $scope.lookupTemplate = function(index) {
            $scope.actions[index].template.index = index;
            $(document).trigger("lookupTemplate", $scope.actions[index].template);
        }
    }
);

Where I increment the name attribute of each new action with the {{index}} helper, included in Angular.

user1429980
  • 6,872
  • 2
  • 43
  • 53