locked
No search results for JavaScript search contract

    Question

  • Hi,

    I'm still new to JavaScript, but have an app that's working well, for the most part. I want to implement the search contract, and have looked at the docs and followed a few tutorials, but can't figure out why I'm not getting search results. All of the items show up when there's no search term, but no items when a search term is entered. I've searched for a solution, but to no avail.

    I'm hoping someone help me figure out what the problem is....

    // For an introduction to the Search Contract template, see the following documentation:
    // [URL removed]

    // TODO: Add the following script tag to the start page's head to
    // subscribe to search contract events.
    // 
    // <script src="/pages/search/search.js"></script>

    (function () {
        "use strict";

        WinJS.Binding.optimizeBindingReferences = true;

        var appModel = Windows.ApplicationModel;
        var appViewState = Windows.UI.ViewManagement.ApplicationViewState;
        var nav = WinJS.Navigation;
        var ui = WinJS.UI;
        var utils = WinJS.Utilities;
        var searchPageURI = "/pages/search/search.html";

        ui.Pages.define(searchPageURI, {
            _filters: [],
            _lastSearch: "",

            // This function is called whenever a user navigates to this page. It
            // populates the page elements with the app's data.
            ready: function (element, options) {
                var listView = element.querySelector(".resultslist").winControl;
                listView.itemTemplate = element.querySelector(".itemtemplate");
                listView.oniteminvoked = this._itemInvoked;
                this._handleQuery(element, options);
                listView.element.focus();
            },

            // This function updates the page layout in response to viewState changes.
            updateLayout: function (element, viewState, lastViewState) {
                /// <param name="element" domElement="true" />

                var listView = element.querySelector(".resultslist").winControl;
                if (lastViewState !== viewState) {
                    if (lastViewState === appViewState.snapped || viewState === appViewState.snapped) {
                        var handler = function (e) {
                            listView.removeEventListener("contentanimating", handler, false);
                            e.preventDefault();
                        }
                        listView.addEventListener("contentanimating", handler, false);
                        var firstVisible = listView.indexOfFirstVisible;
                        this._initializeLayout(listView, viewState);
                        if (firstVisible >= 0 && listView.itemDataSource.list.length > 0) {
                            listView.indexOfFirstVisible = firstVisible;
                        }
                    }
                }
            },

            // This function filters the search data using the specified filter.
            _applyFilter: function (filter, originalResults) {
                if (filter.results === null) {
                    filter.results = originalResults.createFiltered(filter.predicate);
                }
                return filter.results;
            },

            // This function responds to a user selecting a new filter. It updates the
            // selection list and the displayed results.
            _filterChanged: function (element, filterIndex) {
                var filterBar = element.querySelector(".filterbar");
                var listView = element.querySelector(".resultslist").winControl;

                utils.removeClass(filterBar.querySelector(".highlight"), "highlight");
                utils.addClass(filterBar.childNodes[filterIndex], "highlight");

                element.querySelector(".filterselect").selectedIndex = filterIndex;

                listView.itemDataSource = this._filters[filterIndex].results.dataSource;
            },

            _generateFilters: function () {
                this._filters = [];
                this._filters.push({ results: null, text: "All", predicate: function (item) { return true; } });

                // TODO: Replace or remove example filters.
    //            this._filters.push({ results: null, text: "Group 1", predicate: function (item) { return item.group.key === "group1"; } });
    //            this._filters.push({ results: null, text: "Group 2+", predicate: function (item) { return item.group.key !== "group1"; } });
            },

            // This function executes each step required to perform a search.
            _handleQuery: function (element, args) {
                var originalResults;
                this._lastSearch = args.queryText;
                WinJS.Namespace.define("search", { markText: WinJS.Binding.converter(this._markText.bind(this)) });
                this._initializeLayout(element.querySelector(".resultslist").winControl, Windows.UI.ViewManagement.ApplicationView.value);
                this._generateFilters();
                originalResults = this._searchData(args.queryText);
                if (originalResults.length === 0) {
                    document.querySelector('.filterarea').style.display = "none";
                } else {
                    document.querySelector('.resultsmessage').style.display = "none";
                }
                this._populateFilterBar(element, originalResults);
                this._applyFilter(this._filters[0], originalResults);
            },

            // This function updates the ListView with new layouts
            _initializeLayout: function (listView, viewState) {
                /// <param name="listView" value="WinJS.UI.ListView.prototype" />

                if (viewState === appViewState.snapped) {
                    listView.layout = new ui.ListLayout();
                    document.querySelector(".titlearea .pagetitle").textContent = '“' + this._lastSearch + '”';
                    document.querySelector(".titlearea .pagesubtitle").textContent = "";
                } else {
                    listView.layout = new ui.GridLayout();

                    // TODO: Change "App Name" to the name of your app.
                    document.querySelector(".titlearea .pagetitle").textContent = "My app";
                    document.querySelector(".titlearea .pagesubtitle").textContent = "Results for “" + this._lastSearch + '”';
                }
            },

            _itemInvoked: function (args) {
                args.detail.itemPromise.done(function itemInvoked(item) {
                    // TODO: Navigate to the item that was invoked.
        nav.navigate("/pages/itemDetail/itemDetail.html ", { item: Data.getItemReference(item.data) });
                });
            },

            // This function colors the search term. Referenced in /pages/search/search.html
            // as part of the ListView item templates.
            _markText: function (text) {
                return text.replace(this._lastSearch, "<mark>" + this._lastSearch + "</mark>");
            },

            // This function generates the filter selection list.
            _populateFilterBar: function (element, originalResults) {
                var filterBar = element.querySelector(".filterbar");
                var listView = element.querySelector(".resultslist").winControl;
                var li, option, filterIndex;

                filterBar.innerHTML = "";
                for (filterIndex = 0; filterIndex < this._filters.length; filterIndex++) {
                    this._applyFilter(this._filters[filterIndex], originalResults);

                    li = document.createElement("li");
                    li.filterIndex = filterIndex;
                    li.tabIndex = 0;
                    li.textContent = this._filters[filterIndex].text + " (" + this._filters[filterIndex].results.length + ")";
                    li.onclick = function (args) { this._filterChanged(element, args.target.filterIndex); }.bind(this);
                    li.onkeyup = function (args) {
                        if (args.key === "Enter" || args.key === "Spacebar")
                            this._filterChanged(element, args.target.filterIndex);
                    }.bind(this);
                    utils.addClass(li, "win-type-interactive");
                    utils.addClass(li, "win-type-x-large");
                    filterBar.appendChild(li);

                    if (filterIndex === 0) {
                        utils.addClass(li, "highlight");
                        listView.itemDataSource = this._filters[filterIndex].results.dataSource;
                    }

                    option = document.createElement("option");
                    option.value = filterIndex;
                    option.textContent = this._filters[filterIndex].text + " (" + this._filters[filterIndex].results.length + ")";
                    element.querySelector(".filterselect").appendChild(option);
                }

                element.querySelector(".filterselect").onchange = function (args) { this._filterChanged(element, args.currentTarget.value); }.bind(this);
            },

            // This function populates a WinJS.Binding.List with search results for the
            // provided query.
            _searchData: function (queryText) {
                var originalResults;
                // TODO: Perform the appropriate search on your data.
                if (window.Data) {
                    originalResults = Data.items.createFiltered(function (item) {
                        return (item.title.indexOf(queryText) >= 0 || item.content.indexOf(queryText) >= 0);
                    });
                } else {
                    originalResults = new WinJS.Binding.List();
                }
                return originalResults;
            }
        });

        WinJS.Application.addEventListener("activated", function (args) {
            if (args.detail.kind === appModel.Activation.ActivationKind.search) {
                args.setPromise(ui.processAll().then(function () {
                    if (!nav.location) {
                        nav.history.current = { location: Application.navigator.home, initialState: {} };
                    }

                    return nav.navigate(searchPageURI, { queryText: args.detail.queryText });
                }));
            }
        });

        appModel.Search.SearchPane.getForCurrentView().onquerysubmitted = function (args) { nav.navigate(searchPageURI, args); };
    })();

    Any help would be much appreciated!

    Thanks!

    Saturday, April 20, 2013 9:16 PM

Answers

  • Thank you so much for trying to help, Steven!

    As it turns out, it was a simple (if you know what you're doing) fix. Someone walked me through debugging, and as it turns out, I wasn't getting hits because the terms I was using were all proper names (search terms that I *knew* were in my app), and started with upper case letters in the app, but I was using lower case letters in my search.

    The fix was to make sure that case didn't matter.

    The code fix was, in the _searchData function (above) changing this:

    return (item.title.indexOf(queryText) >= 0 || item.content.indexOf(queryText) >= 0);

    to this:

    return (item.title.toLowerCase().indexOf(queryText.toLowerCase()) >= 0 || item.content.toLowerCase().indexOf(queryText.toLowerCase()) >= 0);

    Now it works like a charm! (No pun intended!)

    • Marked as answer by EuryaleP Thursday, May 02, 2013 6:00 AM
    Thursday, May 02, 2013 6:00 AM

All replies

  • Hi EuryaleP,

    From your description, I understand that you find the search result (by using the built-in search contract) doesn't show correct query result items.

    For the built-in search contract, the query code logic should be executed in the "_handleQuery" function below:

     _handleQuery: function (element, args) {
    ....
    }

    therefore, you can add breakpoint there to inspect the query result items to see if that match your expecation. If not, you'd check the certain function which called to perform detailed query logic. If the result returned there matches your expactation, then we need to check the filtering and UI displaying related code and markup to see if there is anything incorrect there.


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by Song Tian Friday, April 26, 2013 8:25 AM
    • Unmarked as answer by EuryaleP Thursday, May 02, 2013 5:48 AM
    Monday, April 22, 2013 2:43 AM
    Moderator
  • Thank you so much for trying to help, Steven!

    As it turns out, it was a simple (if you know what you're doing) fix. Someone walked me through debugging, and as it turns out, I wasn't getting hits because the terms I was using were all proper names (search terms that I *knew* were in my app), and started with upper case letters in the app, but I was using lower case letters in my search.

    The fix was to make sure that case didn't matter.

    The code fix was, in the _searchData function (above) changing this:

    return (item.title.indexOf(queryText) >= 0 || item.content.indexOf(queryText) >= 0);

    to this:

    return (item.title.toLowerCase().indexOf(queryText.toLowerCase()) >= 0 || item.content.toLowerCase().indexOf(queryText.toLowerCase()) >= 0);

    Now it works like a charm! (No pun intended!)

    • Marked as answer by EuryaleP Thursday, May 02, 2013 6:00 AM
    Thursday, May 02, 2013 6:00 AM