2

Ok.. I've tried angular.js. It is awesome. I'm impressed. I can get bindings and stuff.. Cool. Now what if I need to access to my data from outside of the $scope? Let's say I have a signalR hub that sends some data and function that intercepts that and should add a new item or modify existing. How do I do that? Can you show me on this example how can I access $scope.twitterResult from click handle?

<script>
    angular.module('Twitter', ['ngResource'])

    function TwitterCtrl($scope, $resource){
        $scope.twitter = $resource('http://search.twitter.com/:action',
        {action: 'search.json', q: 'obama', callback:'JSON_CALLBACK'},
        {get:{method:'JSONP'}});
        $scope.doSearch = function(){
        $scope.twitterResult = $scope.twitter.get();
      }
    }

    $(function(){
      $('#addItem').click(function(){
           // add a row to $scope.twitterResult
      });
   });
</script>

<body>
   <div data-loading></div>
    <div ng-controller='TwitterCtrl' ng-init="doSearch()">
        <ul>
           <li ng-repeat='tweet in twitterResult.results'><p> {{tweet.text}}</p></li>
         </ul>
    </div>
</body>
Shmiddty
  • 13,847
  • 1
  • 35
  • 52
iLemming
  • 34,477
  • 60
  • 195
  • 309
  • 1
    The function that binds the click function of #addItem should be in a directive. The directive has all kinds of ways of interacting with scope. See http://docs.angularjs.org/guide/directive – Roy Truelove Nov 08 '12 at 01:21
  • Could you clarify what "outside of the $scope" means in your case? Could you share some markup so we can see an element on which you are trying to add the `click` handler? While it is possible to access $scope object from the outside of the AngularJS world (http://stackoverflow.com/a/10508731/1418796) it is often not needed... – pkozlowski.opensource Nov 08 '12 at 17:51

3 Answers3

2

A better way would be to wrap your "signal hub" in an AngularJS service. Take a look on my blog post about using web sockets with AngularJS, specifically "Interacting with Socket.IO."

Why did you write:

$(function(){
  $('#addItem').click(function(){
       // add a row to $scope.twitterResult
  });
});

And not just use ng-click? Is this some 3rd party code or widget? Pending on these this, I'll try to better advise you and write up some example code.

If you have to register an event handler, you should do so through a directive. Otherwise things will get complicated when you start managing the lifecycles of these outside-of-angular event bindings.

btford
  • 5,631
  • 2
  • 29
  • 26
  • no, it actually has nothing to do with the click... I just wanted to know how can you access the $scope externally... I'm gonna check your post... thanks – iLemming Nov 08 '12 at 15:25
1

General answer is: you don't simply mess with the scopes from the outside.

But the requirement you have is a genuine one.

So in order to do what you want you need to establish a communication between outside of the scope and the scope itself.

The easiest way is to export the $scope to window and just mess with it, breaching into the scope from outside. You should NEVER do this. There be dragons.

The scope should maintain it's internal state.

I'm not exactly familiar with angular but you can do something to the effect of:

function TwitterCtrl($scope, $resource) {
    // ...

    $('body').bind('newTweetsArrived', data) {
         // data contains the new tweets

         // the decision to accept or not new tweets is made within the control
         if (in_the_mood_to_accept_new_tweets) {
             // add new tweets to the $scope.twitterResult
         }

         // optionally notify other components that new tweets are accepted
         // so that they can adjust or whatever
         $('body').trigger('afterNewTweetsArrived');
    }

}

// you add new tweets by triggering global custom event
$(function(){
    $('#addItem').click(function(){
       $('body').trigger('newTweetsArrived', { ...here_are_the_tweets... });
    });
});
Shmiddty
  • 13,847
  • 1
  • 35
  • 52
Marko Dumic
  • 9,848
  • 4
  • 29
  • 33
  • Thanks. I learned that the hard way doing some large web applications. This way the coupling is greatly reduced. – Marko Dumic Nov 07 '12 at 23:30
-1

You could probably do something like this, but I'm not sure if it's the best idea:

var myTwitterScope;
angular.module('Twitter', ['ngResource'])

function TwitterCtrl($scope, $resource){
    $scope.twitter = $resource('http://search.twitter.com/:action',
    {action: 'search.json', q: 'obama', callback:'JSON_CALLBACK'},
    {get:{method:'JSONP'}});
    $scope.doSearch = function(){
        myTwitterScope = $scope;
        $scope.twitterResult = $scope.twitter.get();
    }
}

$(function(){
    $('#addItem').click(function(){
        // add a row to $scope.twitterResult
        myTwitterScope.twitterResult.push(...); // or however you would do this.
    });
});

As others have mentioned, this is not the cleanest solution.

Shmiddty
  • 13,847
  • 1
  • 35
  • 52
  • then I'm gonna need to keep global variables for all the collections I need to watch for. I'm not sure that's the right way. – iLemming Nov 07 '12 at 23:16
  • Yeah, I agree it's not a clean solution, but I'm not familiar enough with angularjs to know a better solution. – Shmiddty Nov 07 '12 at 23:18
  • and this won't automatically notify the View about changes.. correction: it seems you can call myTwitterScope.$apply() after the changes! Works for me – iLemming Nov 07 '12 at 23:29
  • 2
    This is not the best way to do this. If you need a custom event handler, consider using an AngularJS service or writing a directive. – btford Nov 08 '12 at 05:58