locked
JavaScript runtime error: NotFoundError when quitting a page containg a ListView too fast.

    Question

  • When I use a custom data source to fetch some datas from a web service and display the results in a WinJS.UI.ListView, my application crash when I go back from the page fetching the data before I get any results. An error "0x800a139e - JavaScript runtime error: NotFoundError" is thrown in "ui.js" at line 16807 (in function _LayoutCommon_measureItems).

    I didn't see anywhere to handle this exception gracefully. Is there anything I can do, or I should try to catch it in the WinJS.Application.onerror? Do a fix exists for this bug?

    Here is a sample code to reproduce the problem :

    1) Create a new "Javascript > Windows Metro App > Navigation App"

    2) In the home.html, add this buttion:

    <button id="goToPage2">go to page 2</button>

    3) In home.js, add this code to go to the page 2 :

    ready: function (element, options) {
                goToPage2.addEventListener("click", function () {
                    WinJS.Navigation.navigate("pages/home/page2.html", {});
                });
            }

    4) Create page2.html next to home.html :

    <!DOCTYPE html>
    <html>
    <head>
    	<meta charset="utf-8" />
    	<title>homePage</title>
    
    	<!-- WinJS references -->
    	<link href="//Microsoft.WinJS.1.0.RC/css/ui-dark.css" rel="stylesheet" />
    	<script src="//Microsoft.WinJS.1.0.RC/js/base.js"></script>
    	<script src="//Microsoft.WinJS.1.0.RC/js/ui.js"></script>
    
    	<link href="/css/default.css" rel="stylesheet" />
    	<link href="/pages/home/home.css" rel="stylesheet" />
    	<script src="/pages/home/page2.js"></script>
    </head>
    <body>
    	<!-- The content that will be loaded and displayed. -->
    	<div class="fragment homepage">
    		<header aria-label="Header content" role="banner">
    			<button class="win-backbutton" aria-label="Back" disabled></button>
    			<h1 class="titlearea win-type-ellipsis">
    				<span class="pagetitle">Page 2!</span>
    			</h1>
    		</header>
    		<section aria-label="Main content" role="main">
    			<div id="singleRecipeTemplate" data-win-control="WinJS.Binding.Template">
    				An Item
    			</div>
    
    			<div id="ctlList" data-win-bind="winControl.itemDataSource: data;"
    				data-win-control="WinJS.UI.ListView" data-win-options="{
    								itemTemplate: select('#singleRecipeTemplate'),
    								selectionMode: 'none', 
    								tapBehavior: 'none',
    								swipeBehavior: 'none',
    								reorderable: false, 
    								layout: { type: WinJS.UI.GridLayout, maxRows: 7 },
    
    								loadingBehavior : 'incremental',
    								automaticallyLoadPages  : true,
    								pagesToLoadThreshold : 1,
    								pagesToLoad : 1
    								}">
    			</div>
    		</section>
    	</div>
    </body>
    </html>
    

    5) Add the page2.js file with this code :

    (function () {
        "use strict";
    
        var paginableDataSourceAdapter = WinJS.Class.define(
            function (query) {
                this._minPageSize = 10;
                this._maxPageSize = 190;
                this._maxCount = 10000;
            },
            {
                itemsFromIndex: function (requestIndex, countBefore, countAfter) {
                    var that = this;
                    if (requestIndex >= that._maxCount) {
                        return Promise.wrapError(new WinJS.ErrorFromName(UI.FetchError.doesNotExist));
                    }
    
                    var fetchSize, fetchIndex;
    
                    // See which side of the requestIndex is the overlap.
                    if (countBefore > countAfter) {
                        // Limit the overlap
                        countAfter = Math.min(countAfter, 10);
    
                        // Bound the request size based on the minimum and maximum sizes.
                        var fetchBefore = Math.max(
                            Math.min(countBefore, that._maxPageSize - (countAfter + 1)),
                            that._minPageSize - (countAfter + 1)
                            );
                        fetchSize = fetchBefore + countAfter + 1;
                        fetchIndex = requestIndex - fetchBefore;
                    } else {
                        countBefore = Math.min(countBefore, 10);
                        var fetchAfter = Math.max(Math.min(countAfter, that._maxPageSize - (countBefore + 1)), that._minPageSize - (countBefore + 1));
                        fetchSize = countBefore + fetchAfter + 1;
                        fetchIndex = requestIndex - countBefore;
                    }
    
                    // TODO: passe page index to the query...
                    return WinJS.Promise.timeout(2000)
                        .then(function (response) {
                            var results = [];
                            var count = fetchSize;
                            // Create an array of IItem objects:
                            for (var idx = 0; idx < fetchSize; idx++) {
                                results.push({
                                    key: (fetchIndex + "_" + idx).toString(),
                                    data: idx * Math.random(),
                                });
                            }
    
                            var resultContract = {
                                items: results,
                                offset: requestIndex - fetchIndex,
                                totalCount: 10000,
                            };
                            return WinJS.Promise.as(resultContract);
                        }, function (ex) {
                            return WinJS.UI.FetchError.noResponse;
                        });
                },
                getCount: function () {
                    return WinJS.Promise.as(10000);
                }
            });
    
        var bingImageSearchDataSource = WinJS.Class.derive(WinJS.UI.VirtualizedDataSource, function () {
            this._baseDataSourceConstructor(new paginableDataSourceAdapter());
        });
    
        WinJS.UI.Pages.define("/pages/home/page2.html", {
            // 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) {
                document.getElementById("ctlList").winControl.itemDataSource = new bingImageSearchDataSource();
            }
        });
    })();
    
    6) Now simply navigate to page 2, and go back to home before the results are displayed.
    Thursday, August 02, 2012 10:56 PM

Answers

All replies