2013-08-16 8 views
6

Ich habe zwei AngularJS-Dienste definiert ... einer ist für die YouTube-Player-API und ein anderer für die YouTube iFrame-Daten-API. Sie sehen wie folgt aus:AngularJS-Broadcast von einem Dienst, der keinen Anruf zum zweiten Dienst auslöst

angular.module('myApp.services',[]).run(function() { 
    var tag = document.createElement('script'); 
    tag.src = "//www.youtube.com/iframe_api"; 
    var firstScriptTag = document.getElementsByTagName('script')[0]; 
    firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); 
}) 
.factory('YtPlayerApi', ['$window', '$rootScope', function ($window, $rootScope) { 
    var ytplayer = {"playerId":null, 
    "playerObj":null, 
    "videoId":null, 
    "height":390, 
    "width":640}; 

    $window.onYouTubeIframeAPIReady = function() { 
     $rootScope.$broadcast('loadedApi'); 
    }; 

    ytplayer.setPlayerId = function(elemId) { 
     this.playerId=elemId; 
    }; 

    ytplayer.loadPlayer = function() { 
     this.playerObj = new YT.Player(this.playerId, { 
      height: this.height, 
      width: this.width, 
      videoId: this.videoId 
     }); 
    }; 
    return ytplayer; 
}]) 
.factory('YtDataApi', ['appConfig','$http', function(cfg,$http){ 
    var _params = { 
     key: cfg.youtubeKey 
    }; 
    var api="https://www.googleapis.com/youtube/v3/"; 
    var yt_resource = {"api":api}; 
    yt_resource.search = function(query, parameters) { 
     var config = { 
      params: angular.extend(angular.copy(_params), 
         {maxResults: 10, 
         part: "snippet"}, parameters) 
      }; 
     return $http.get(api + "search?q=" + query, config); 
    }; 
    return yt_resource; 
}]); 

(auch beachten, dass die ‚setPlayerId‘ Funktion von meinem Player Dienst durch eine benutzerdefinierte Richtlinie genannt wird ... aber das ist nicht wichtig für meine Frage).

Also, hier ist das Problem. Ich muss sicherstellen, dass der Player-API-Code geladen wird, bevor ich die Video-ID einstelle und den Player erstelle, weshalb ich die "loadedApi" -Nachricht ausstrahlen lasse. Und das funktioniert großartig, wenn ich dann in mein Controller eine hartcodierte Video-ID übergeben, wie folgt aus:

function ReceiverCtrl($scope,$rootScope,$routeParams,ytplayer,ytdataapi) { 
    $scope.$on('loadedApi',function() { 
    ytplayer.videoId='voNEBqRZmBc'; 
    ytplayer.loadPlayer(); 
    }); 
} 

Allerdings wird meine Video-IDs nicht bestimmt werden, bis ich einen API-Aufruf mit dem Daten api Service machen Daher muss ich auch sicherstellen, dass die Ergebnisse dieses Aufrufs zurückkommen. Und das ist, wo ich in Probleme laufen lasse ... wenn ich so etwas tun:

 $scope.$on('loadedApi',function() { 
     ytdataapi.search("Mad Men", {'topicId':$routeParams.topicId, 
            'type':'video', 
            'order':'viewCount'}) 
     .success(function(apiresults) { // <-- this never gets triggered 
      console.log(apiresults); // <-- likewise, this obviously doesn't either 
     }); 
     }); 

Dann wird die Interaktion mit dem Datendienst nie aus irgendeinem Grund passiert. Ich weiß, dass der Datendienst gut funktioniert, denn wenn ich ihn aus der $ on-Anweisung entstecke, gibt er die api-Ergebnisse zurück. Manchmal sorgt die Latenz dafür, dass die Ergebnisse nicht schnell genug zurückkommen, um sie im Player-Service zu verwenden. Irgendwelche Gedanken darüber, was ich tun kann, um die Daten suchen nach dem Erhalt der Nachricht, dass die Player-API bereit ist, aber immer noch die beiden Dienste als zwei separate Dienste (weil andere Controller nur die eine oder andere verwenden, so will ich nicht sie voneinander abhängig auf der Service-Ebene)?

Antwort

2

Ich habe es herausgefunden; Ich hatte $ Umfang zu nennen $ apply(), wie folgt aus:.

function ReceiverCtrl($scope,$rootScope,$routeParams,ytplayer,ytdataapi) { 
    $scope.$on('loadedApi',function() { 
    ytdataapi.search("",{'topicId':$routeParams.topicId,'type':'video','maxResults':1,'order':'viewCount'}).success(function(apiresults) { 
     ytplayer.videoId=apiresults.items[0].id.videoId; 
     ytplayer.loadPlayer(); 
    }); 
    $scope.$apply(); 
    }); 
} 

Gibt es jemanden, beleuchten könnte, warum das funktioniert, obwohl? $ scope. $ digest() funktioniert auch ... aber ich dachte, diese Methoden würden nur verwendet, wenn Sie Bindings aktualisieren müssen, weil JavaScript-Code Angular nicht bekannt ist. Ist die Verschachtelung, die ich hier habe, das (ich würde nicht denken, dass es sollte, da mein ytdataapi-Dienst $ http verwendet)?

+0

Sieht aus, dass die Suchfunktion keine Änderungen am Umfang einführt, sondern nur eine http-Anfrage auslöst. Es ist komisch. – Diryboy

+0

Hallo, vielen Dank für Ihre Antwort mit uns! Eine Sache, die ich nicht verstehe, ist, wie Sie den You Tube Player an ein DOM Element binden. Und auch, wie können Sie mehrere verschiedene Videos nacheinander laden, ohne das Plugin erneut zu laden –

+0

Hier ist ein Github Repo, das ist die Art der Entwicklung dieser Frage: https://github.com/jlmcdonald/angular-youtube ... Es enthält Angluar-Direktiven zum Binden des Players an DOM-Elemente. Ich habe noch nicht darüber nachgedacht, mehrere Videos zu laden, aber das sollte nicht schwer sein ... vielleicht werde ich es zum Repo-Code hinzufügen. – jlmcdonald

Verwandte Themen