Here’s how it’s done

Here’s how it’s done in Scenario 2 of the Search contract sample (where suggestionList is just a hard-coded list of city names): Windows.ApplicationModel.Search.SearchPane.getForCurrentView().onsuggestionsrequested = function (eventObject) { var queryText = eventObject.queryText; var suggestionRequest = eventObject.request; var query = queryText.toLowerCase(); var maxNumberOfSuggestions = 5; for (var i = 0, len = suggestionList.length; i < len; i++) { if (suggestionList[i].substr(0, query.length).toLowerCase() === query) { suggestionRequest.searchSuggestionCollection.appendQuerySuggestion( suggestionList[i]); if (suggestionRequest.searchSuggestionCollection.size === maxNumberOfSuggestions) { break; } } } }; So if query contains “ba” as it would in Figure 12-10, the first 5 names in suggestionList will be Bangkok, Bangalore, Baghdad, Baltimore, and Bakersfield. Of course, a real app will be drawing suggestions from its own database or from a service (simulated in Scenarios 5 and 6, by the way), but you get the idea. With a service, though, you should also check the suggestionResult.isCanceled property before starting a new request: this flag indicates that the search query hasn’t actually changed from a previous query and it’s not necessary to create new suggestions. Note When the SearchPane.searchHistoryEnabled property is true (the default), a user’s search history will be automatically tracked with prior searches appearing as suggestions when the search charm is first invoked (before the user types any other characters). Setting this property to false will disable the behavior, in which case an app can maintain its own history of previous queryText values. If an app does this, we recommend providing a means to clear the history through the app’s Settings. Apps can also use the SearchPane.searchHistoryContext property to create different histories depending on different contexts. When this value is set prior to the search charm being invoked, automatically managed search terms (searchHistoryEnabled is true) will be saved for that context. This has no effect when an app manages its own history, in which case it can manage different histories directly. Now the eventArgs.request property, a SearchPaneSuggestionsRequest object, has a few features you want to know about. Its searchSuggestedCollection property is unique—it’s not an array or other generic vector but a SearchSuggestionCollection object with a size property and four methods: appendQuerySuggestion (to add a single item to the list, as shown above), appendQuerySuggestions (to add an array of items at once, as you might receive from a query to a service), appendResultSuggestion (see next section) and appendSearchSeparator (which is used to group suggestions). In the latter case, a separator is given a label and appears as follows: 522

The request object also has a getDeferral method if you need to perform an asynchronous operation to retrieve your suggestions. It works like all other deferral’s we’ve seen: before starting the async operation (like WinJS.xhr), call getDeferral to retrieve the deferral object, start the operation, return from the suggestionsrequested method, and call the deferral’s complete method inside the async completed handler. This is demonstrated again in Scenarios 5 and 6 of the sample since this would clearly be needed when querying a service for this purpose (code here derived from js/scenario5.js): Windows.ApplicationModel.Search.SearchPane.getForCurrentView().onsuggestionsrequested = function (eventObject) { var queryText = eventObject.queryText; var suggestionRequest = eventObject.request; var deferral = suggestionRequest.getDeferral(); // Create request to obtain suggestions from service and supply them to the Search Pane. // Depending on design of the service, you might vary URL based on eventObject.language. // You might also compose queryText in the URL to let the service do the filtering. xhrRequest = WinJS.xhr({ url: /* URL to suggestion service */ }); xhrRequest.done( function (request) { if (request.responseText /* or responseXML */) { // Populate suggestionRequest.searchSuggestionCollection based on response } }; deferral.complete(); // Indicate we're done supplying suggestions. }, function (error) { // Call complete on the deferral when there is an error. deferral.complete(); }); You can use any JSON or XML response format you want, but since your app is doing the parsing, there are existing standards for returning search suggestions. For JSON, refer to the OpenSearch Suggestions specification and Scenario 5 in the sample where a JSON response can be directly parsed into an array and passed in one call to appendQuerySuggestions. For XML, refer to the XML Search Suggestions Format Specification and Scenario 6. In the latter case, a function named generate-Suggestions provides a generic parser routine for such a response, and although the sample doesn’t demonstrate using separators, URIs, and images in those suggestions, the generateSuggestions function shows how to parse them and send them onto appendQuerySuggestion[s] as well as appendResultSuggestion, which we’ll see next. 523