27

I have a service called 'player' and I need to update the service when a flash object is finished loading.

mySongPlayer.factory('player', function() {

var isPlayerLoaded = false;
var playerHolder = '';

window.playerReady = function(thePlayer) {
    playerHolder = window.document[thePlayer.id];
    addListeners();
    isPlayerLoaded = true;
}

var flashvars = {
    file:"", 
    autostart:"true",
    skin: "/skins/glow/glow.zip",
}

var params = {
    allowfullscreen:"false", 
    allowscriptaccess:"always"
}

var attributes = {
    id:"player1",  
    name:"player1"                    
}

swfobject.embedSWF("/player.swf", "player_placeholder", "100%", "40", "9.0.115", false, flashvars, params, attributes);

var playObj;
return playObj || (playObj = {
    currentId: 'test', currentUrl: 'url', playerHolder: ''
});
});​

I know how to access the service using

angular.element(DOMElement).injector().get('player')

but it returns a new instance of 'player' while I need to update the instance already created in the module. Is there a way to do this? I only want one instance of the player, but I need to initialize it from outside javascript.

Atomix
  • 2,440
  • 8
  • 36
  • 48

1 Answers1

56

Well, I can't really see all of what you're doing, but you're probably about 1/2 way there.

Here is a working plunk of what I'm about to describe

injector.get() should be returning the same instance of Service as what's in your app. You're probably just seeing an issue that makes you think you have a different instance.

So what you need to do is:

  • Make sure that what you're putting in your scope from your service is an object reference. If it's a primitive type, it won't be the same reference so it won't update.
  • Be sure to get the scope off of your angular element with angular.element(DOMElement).scope() and then call $apply() on it.

Here's the code:

app.controller('MainCtrl', function($scope, myService) {
  // Set a var on the scope to an object reference of the
  // (or from the) service.
  $scope.myService = myService;
});

app.factory('myService', function(){
  return {
    foo: 'bar'
  };
});

//do a little something to change the service externally.
setTimeout(function(){
  //get your angular element
  var elem = angular.element(document.querySelector('[ng-controller]'));

  //get the injector.
  var injector = elem.injector();

  //get the service.
  var myService = injector.get('myService');

  //update the service.
  myService.foo = 'test';

  //apply the changes to the scope.
  elem.scope().$apply();
}, 2000)

Other thoughts:

  • You probably want to inject $window into your service, rather than use the window object, to maintain the testability of your service.
  • A directive is probably a better choice for DOM manipulation such as the creation of a Flash movie player.
Onur Yıldırım
  • 32,327
  • 12
  • 84
  • 98
Ben Lesh
  • 107,825
  • 47
  • 247
  • 232
  • why can't it be applied to `scope().myService` directly? what's the difference of using `injector().get` to `scope().myService` – pocesar Apr 19 '13 at 21:23
  • 6
    In this particular example, you could. However, that would only work if the service has been added as a property of a scope, which isn't always going to be the case. So `injector.get()` is what you'd have to use if you wanted this to work in *all* cases. – Ben Lesh Apr 22 '13 at 03:10
  • what do you gain from using `document.querySelector('[ng-controller]')`? just using `'[ng-controller]'` or `'[ng-app]'` as argument to `angular.element()` seems to work just as good? – Superole Sep 01 '17 at 11:44