tvOS: Create a Search TVML Page with TVML SearchTemplate

This is the TVML SearchTemplate (taken from Apple's Docs: https://developer.apple.com/library/prerelease/tvos/documentation/LanguagesUtilities/Conceptual/ATV_Template_Guide/SearchTemplate.html#//apple_ref/doc/uid/TP40015064-CH33-SW1


var Template = function() {
return `<?xml version="1.0" encoding="UTF-8" ?>
<document>
<head>
<style>
.suggestionListLayout {
margin: -150 0;
}
</style>
</head>
<searchTemplate id="tmpl_search">
<searchField/>
<collectionList>
<separator></separator>
</collectionList>
</searchTemplate>
</document>`
}



It's something very basic.


When the template is populated by some items it looks like the following


var Template = function() {
return `<?xml version="1.0" encoding="UTF-8" ?>
<document>
<head>
<style>
.suggestionListLayout {
margin: -150 0;
}
</style>
</head>
<searchTemplate>
<searchField/>
<collectionList>
<shelf>
<header>
<title>Shelf Title</title>
</header>
<section>
<lockup>
<img src="${this.BASEURL}resources/images/movies/movie_520_e1.lcr" width="350" height="520" />
<title>Title 1</title>
</lockup>
<lockup>
<img src="${this.BASEURL}resources/images/movies/movie_520_e2.lcr" width="350" height="520" />
<title>Title 2</title>
</lockup>
<lockup>
<img src="${this.BASEURL}resources/images/movies/movie_520_e3.lcr" width="350" height="520" />
<title>Title 3</title>
</lockup>
</section>
</shelf>
<grid>
<header>
<title>Grid Title</title>
</header>
<section>
<lockup>
<img src="${this.BASEURL}resources/images/music/music_520_e1.lcr" width="350" height="350" />
<title>Title 1</title>
</lockup>
<lockup>
<img src="${this.BASEURL}resources/images/music/music_520_e2.lcr" width="350" height="350" />
<title>Title 2</title>
</lockup>
<lockup>
<img src="${this.BASEURL}resources/images/music/music_520_e3.lcr" width="350" height="350" />
<title>Title 3</title>
</lockup>
</section>
</grid>
</collectionList>
</searchTemplate>
</document>`
}


Now, as soon as you name the template you should be able to get access to it in your Presenter code, that register events for the new Document:


resourceLoader.loadResource(templateURL, function(resource) {
if (resource) {
var doc = self.makeDocument(resource);
self.currentDOMDocument=doc
// DOM Document "onload" event
doc.addEventListener("load", self.dispatch.bind(self));
// DOM element "select" | "highlight" event
doc.addEventListener("select", self.load.bind(self));
doc.addEventListener("highlight", self.load.bind(self));
if (self[presentation] instanceof Function) {
self[presentation].call(self, doc, ele);
} else {
self.defaultPresenter.call(self, doc);
}
}
}
)


So, in this case the event should be a "select" event on the search field:


<searchField/>


and so you will be able to get the featured i.e. the keyboard and to attach events for the input like:


var formTemplate = ele.parentNode.parentNode; // your formTemplate button
var children = formTemplate.childNodes;
var textField = children.item(1); // replace "1" with the index of "textField" element in your template
var keyboard = textField.getFeature("Keyboard"); // get the textField's Keyboard element



and the input text


var userValue = keyboard.text.replace(/-/g,""); // the value entered by the user on the Apple TV keyboard


At the "load" event you can attach events to get input changes like:


var children = ele.childNodes;
var textField = children.item(1); // replace "1" with the index of "textField" element in your template
var keyboard = textField.getFeature("Keyboard"); // get the textField's Keyboard element
keyboard.onTextChange = function () {
console.log("onTextChange "+keyboard.text)
if( keyboard.text.length && !((keyboard.text.length+1) % 5) ) { // every 4 chars
keyboard.text+='-';
}
}
}


At this time you have the query string for your Search API.

As soon as you get a callback from your API (that could make use of sayts - Search As You Type),

we need to dynamically add items to the search results as new


<shelf/>


and inside a list of


<section><lockup/></section>


lockup items. So how to dynamically add now these elements?

First off you will need a reference to the parsed document. (I keep a reference to the current view in a service which is also responsible also parses my xml strings) From my API I get a list of results. Looping through them I add to an xml string and insert it:

var searchResults = builder.getCurrentView().getElementById("searchResults").innerHTML = that.resultsString;

Are you guys having a problem with the app crashing when using search after rendering dynamic results?

I was having a lot of trouble with crashes down inside UICollectionView but code was in Javascript interacting with a <section> in a searchTemplate. The code was dynamically adding and removing nodes (as described above) from a <section>, inside a <grid>, that was inside a <collectionList>. I changed the code to add/remove nodes from the <collectionList> instead and crashing stopped.

tvOS: Create a Search TVML Page with TVML SearchTemplate
 
 
Q