0251 / 590 837 15
info@a-coding-project.de

JSON Abfrage auf dem Samsung Smart TV

Im TV App Tutorial werden wir heute eine AJAX-Abfrage an einen Server schicken. Dieser liefert einen JSON-String zurück, der dann auf dem Samsung Smart TV empfangen wird. Das Ganze machen wir, um die einzelnen Videos online vom Server abzuholen.

Ich werde die Videos erstmal relativ statisch mit PHP als JSON ausgeben lassen, hier könnt ihr das natürlich beliebig erweitern. Fangen wir doch einfach mal mit zwei kleinen Videos an:

<?php
  $videos = array(
              array("title"  => "How will Google interpret links to URLs ending with a campaign tag?",
                    "author" => "GoogleWebmasterHelp",
                    "player" => "youtube",
                    "id"     => "qr2Rg8sJRUU",
                    "thumb"  => "http://smart-tv.stevieswebsite.de/thumbs/matt-cutts-url-ending.jpg"),
              array("title"  => "'Not' Venice Update | Alpha9 Talk",
                    "author" => "alpha9marketing",
                    "player" => "youtube",
                    "id"     => "qjUGbQIdJtk",
                    "thumb"  => "http://smart-tv.stevieswebsite.de/thumbs/not-venise.jpg"));
  echo json_encode($videos);
?>

Ich gebe hier einfach folgende Daten an:

  • title Titel des Videos
  • author Autor
  • player Erstmal unterstützen wir nur YouTube, später können hier auch andere rein.
  • id Die ID bei dem Video-Anbieter (aus der Url bei YouTube entnommen)
  • thumb Adresse eines Bildausschnitts des Videos

Bevor wir jetzt anfangen die JSON Abfrage zu machen, müssen wir noch eine neue Klasse im Projekt anlegen. Diese ist unter /app/javascript/Category.js gesperichert und repräsentiert wie zu erwarten eine einzelne Kategorie. Auch enthalten ist die Funktion loadVideos, die aus der Menu.js kopiert wurde (dort hieß sie loadDummyVideos):

function Category()
{
	this.title = "";
	this.tag = "";
	this.menuEntry = false;
	
	//Lädt die Videos in den Screen
	this.loadVideos = function()
	{
		document.getElementById('videolist').innerHTML = "";
		
		//6 Videos hinzufügen
		for(var i = 1;i<=6;i++)
		{
			//Video erstellen
			var video = new Video();
			video.title = this.title + " " + i;
			video.author = "Stefan Wienströer";
			video.playUrl = "/tutorial-smart-tv-app-entwickeln/";
			video.previewImage = "http://www.contentlion.de/content/uploads/doku/seite-anlegen-525.jpg";
	
			document.getElementById('videolist').innerHTML += video.GetTeaserCode();
		}
	};
	
	//Liefert den Menüeintrag zurück
	this.GetMenuEntry = function()
	{
		if(!this.menuEntry)
		{
			//Nachladen
			this.menuEntry= new MenuEntry();
			this.menuEntry.OnActivate = this.loadVideos;	
		}
		
		//Titel kann sich geändert haben, also immer neu setzen
		this.menuEntry.title = this.title;
		
		//Weg damit
		return this.menuEntry;
	};
}

Ich habe auch die Funktion GetMenuEntry hinzugefügt, die den Menüeintrag zurückliefert. Dieser wurde ja bisher in der Menu.js erstellt. Und genau diese können wir nun so verändern, dass auch hier die Category-Klasse genutzt wird:

//----- Gekürzt -----
		document.body.appendChild(a);
		//und fokussieren...
		a.focus();
	};
	
	var seo = new Category();
	seo.title = "SEO";
	seo.tag = "seo";
	this.AddEntry(seo.GetMenuEntry());
	
	//Social Media
	var socialmedia = new Category();
	socialmedia.title = "Social Media";
	socialmedia.tag = "social-media";
	this.AddEntry(socialmedia.GetMenuEntry());
	
	//Entwickler
	var developer = new Category();
	developer.title = "Entwickler";
	developer.tag = "developer";
	this.AddEntry(developer.GetMenuEntry());
	
	//CMS
	var cms = new Category();
	cms.title = "CMS";
	cms.tag = "cms"; 
	this.AddEntry(cms.GetMenuEntry());

	//Als Default werden die Neuvorstellungen gewählt
	seo.GetMenuEntry().Activate();
	
	//Versteckten Fokus hinzufügen
	this.AddFocus();
};

Zu guter letzt müssen wir unsere neue Category.js auch in die index.html laden. Das geht so:

<!-- gekürzt -->
		<script language="javascript" type="text/javascript" 
				src="app/javascript/Video.js"></script>
		<script language="javascript" type="text/javascript" 
				src="app/javascript/Category.js"></script>
				

		<link rel="stylesheet" href="app/stylesheets/Main.css" type="text/css">
<!-- gekürzt -->

Wenn du nun die App erneut starten, wird dir bestimmt etwas ganz cooles auffallen: Es hat sich nichts verändert. Aber wir haben jetzt die Struktur so umgebaut, dass wir nun tatsächlich mit dem Auslesen des JSONs beginnen können. Jede Kategorie hat bei mir ein eigenes JSON-File auf dem Server. Euch ist eben vielleicht aufgefallen, dass es eine Eigenschaft namens „tag“ gab. In dieser wird der Name gespeichert, mit dem wir die Url aufbauen.

Im nächsten Schritt fragen wir die Videos per JSON vom Server ab. Das funktioniert so:

function Category()
{
	this.title = "";
	this.tag = "";
	this.menuEntry = false;
	
	//Lädt die Videos in den Screen
	this.loadVideos = function()
	{
		document.getElementById('videolist').innerHTML = "";
		
		this.GetVideos(function(videos){
			//Videos hinzufügen
			for(var i = 0;i<=videos.length;i++)
			{
				document.getElementById('videolist').innerHTML += videos[i].GetTeaserCode();
			}
		});
	};
	
	//Liefert den Menüeintrag zurück
	this.GetMenuEntry = function()
	{
		if(!this.menuEntry)
		{
			//Nachladen
			this.menuEntry= new MenuEntry();
			this.menuEntry.tag = this;
			this.menuEntry.OnActivate = function(){ this.tag.loadVideos(); };	
		}
		
		//Titel kann sich geändert haben, also immer neu setzen
		this.menuEntry.title = this.title;
		
		//Weg damit
		return this.menuEntry;
	};
	
	this.GetVideos = function(callback)
	{
		var res = new Array();
		
		 var xmlhttp = null;
		 // Mozilla
		 if (window.XMLHttpRequest)
		 {
		     xmlhttp = new XMLHttpRequest();
		 }
		 // IE
		 else if (window.ActiveXObject)
		 {
		     xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
		 }
	
		 //Kategorie abfragen
		 xmlhttp.open("GET", 'http://smart-tv.stevieswebsite.de/' + this.tag + '.php', true);
		 xmlhttp.onreadystatechange = function()
		 {
		     if(xmlhttp.readyState == 4 && xmlhttp.status == 200)
		     {
		    	 //Abfrage erfolgreich. Parsen wir das JSON!
		     	obj = JSON.parse(xmlhttp.responseText);
		     	for(var i = 0;i < obj.length; i++)
		     	{
				//Videos erstellen
				var video = new Video();
				video.title = obj[i].title;
				video.author = obj[i].author;
				video.previewImage = obj[i].thumb;
					
				res[res.length] = video;
		     	}
		     	
		     	//Callback aufrufen
				callback(res);
		     }
		 };
		 
		 //Abfrage starten
		 xmlhttp.send(null);
	};

}

Da wir hier mit einer Serverabfrage arbeiten, müssen wir auch warten, bis diese zu Ende durchgeführt wurde. Deshalb arbeiten wir mit einem Callback, der die Videos nach erfolgreiche Abfrage der Ansicht hinzufügt.

Nach dem Start der App, sehen wir folgendes:

Videos vom Server

Videos vom Server

Wie ihr seht, sind die Titel viel zu lang. Aber das ist kein Problem. Zwei kleine Änderungen an der /app/stylesheets/Main.css und die Sache passt:

.video_teaser {
	font-weight:lighter;
	float:left;
	padding-right:15px;
	height:250px;
	width:200px
}
.video_teaser h2{
	margin-top:5px;
	color:#b00000;
	font-size:1em;
	font-weight:lighter;
}

Das Ergebnis des heutigen Artikels sieht wie folgt aus. Später darf ich mir noch ein paar mehr Videos heraussuchen, die ich anzeigen kann:

Seo Videos

Seo Videos

Hier kann auch wieder mein aktueller Stand heruntergeladen werden.

Kommentare

Eugen schrieb am 08.12.2012:

Hallo, folgender Code funktioniert nicht: obj = JSON.parse(xmlhttp.responseText); Das JSON fehlt. Da muss wohl noch ein weiteres JS geladen werden. Wäre super, wenn du das noch nachtragen würdest.

Stefan Wienströer schrieb am 09.12.2012:

JSON ist fester Bestandteil von JavaScript ;-)

Gajan schrieb am 10.04.2013:

Hallo bekomme folgenden fehler [JS ERROR]: File: file://c/Program%20Files%20(x86)/Samsung/Samsung%20TV%20SDK%204/apps/_temp_20100108_/app/javascript/Category.js Line No: 16 Error Detail: TypeError: 'undefined' is not an object (evaluating 'videos[i].GetTeaserCode') kannst du mir weiterghelfen?

Stefan Wienströer schrieb am 10.04.2013:

Das Objekt videos[i] wird nicht gefunden. Kannst du mal schreiben, was bei dir in der Category.js um Zeile 16 steht?

Gajan schrieb am 11.04.2013:

Habs herausgefunden. Es war ein Loop zuviel und es gab eine leerlauf bzw. keine Daten. Da das Loop/for bei 0 anfängt, sollte es bei Zeile 14 for(var i = 0;i&lt;videos.length;i++) heissen; anstatt ...i&lt;=videos... (gekürzt)