locked
Conflict with HTML Page control lifecycle and declarative binding

    Question

  • I have a strange behavior. When using HTML Page controls, the page "ready" event is raised then the Page control "ready" is raised (the first time I enter the page), BUT when going back to the main page (after navigating to an other page), the page control "ready" event is raised BEFORE the page ready event.

    This behavior cause me a big troubles when trying to use declarative binding. I'm using WinJS.Binding.processAll in the ready event to apply the current datacontext to my Page control, but I don't have the datacontext at this time when navigating back.

     

    Here is how to to reproduce the problem:

    1) Create a new JavaScript "Navigation App" project

    2) Use this code into generated "home.js" file. It contains controls for the main page, it's HTML Page control, and the page we will navigate to (Page2).

    (function () {
        "use strict";
    
        var MainPage = WinJS.UI.Pages.define("/pages/home/home.html", {
            ready: function (element, options) {
                console.log("MainPage.ready;");
                WinJS.Binding.processAll(element, { someViewModel: { toBind: "Binded" } }).done();
    
                document.getElementById("ctlGoToPage2").addEventListener("click", function (ev) {
                    WinJS.Navigation.navigate('/pages/home/page2.html');
                });
            }
        });
    
        var MyUserControl = WinJS.UI.Pages.define("/pages/home/myUserControl.html", {
            ready: function (element, options) {
                console.log("MyUserControl.ready;");
                WinJS.Binding.processAll(element, this.dataContext).done();
            }
        });
    
        var Page2 = WinJS.UI.Pages.define("/pages/home/page2.html", {
            ready: function (element, options) {
            }
        });
    
        WinJS.Namespace.define("MyNamespace", {
            MainPage: MainPage,
            Page2: Page2,
            MyUserControl: MyUserControl
        });
    })();

    3) Add the page control in the a new file "pages/home/myUserControl.html" with this content :

    <!DOCTYPE html>
    <html>
    <head></head>
    <body>
    	<p>Here is my user control</p>
    	Here I must see the binded value : <span data-win-bind="innerText: toBind"></span>
    </body>
    </html>

    4) Add a simple page to navigate to :"pages/home/page2.html" with this content :

    <!DOCTYPE html>
    <html>
    <head>
    	<meta charset="utf-8" />
    	<title></title>
    	<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/home.js"></script>
    </head>
    <body>
    	<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>
    	</div>
    </body>
    </html>

    5) Finally, add the user control to the main page and a button to navigate to the second page:

    <!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/home.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 1</span>
                </h1>
            </header>
            <section aria-label="Main content" role="main">
    			<div data-win-control="MyNamespace.MyUserControl" data-win-bind="winControl.dataContext: someViewModel"></div>
    
    			<button id="ctlGoToPage2">go to page 2</button>
            </section>
        </div>
    </body>
    </html>

    Is there any way I can scope the Page control datacontext to it's viewmodel without this lifecycle problem? There is the data-win-bindsource that seems to do what I needed to, but it's deprecated (http://msdn.microsoft.com/en-us/library/windows/apps/hh440967.aspx) and it didn't work when I tryied it. I also tryied to execute the Page control WinJS.Binding.processAll at the moment the dataContext property is set (so it occurs on WinJS.Binding.processAll of the main page), but without success.

    So, any ideas?


    • Edited by Instriker Monday, June 18, 2012 10:04 PM
    Monday, June 18, 2012 9:59 PM

Answers

  • Hi Striker,

    You cannot guarantee which page will render first so you cannot guarantee the order that these ready: events will be received.

    -Jeff


    Jeff Sanders (MSFT)

    • Marked as answer by Instriker Tuesday, June 26, 2012 2:43 PM
    Friday, June 22, 2012 7:03 PM
    Moderator

All replies

  • Hi Striker,

    Have you tried to do your binding in code?  That sounds like what you need to do in this situation.

    -Jeff


    Jeff Sanders (MSFT)

    Friday, June 22, 2012 11:26 AM
    Moderator
  • I already call the WinJS.Binding.processAll in the code (in the ready function in fact). Else I'm not sure what you would mean. If it's to put binding code in the ViewModel, I have a design problem with the pattern. In a MVVM, the ViewModel should never have binding code, but must rather must expose bindable properties. So I just want to be able to do it like I'm used to in c#/xaml. And it works well on the initial hit, I only have problems with navigating back to the page because the sequence of events are not the same (I'm don't think the ready event of child controls should be call before their parents).

    Friday, June 22, 2012 1:37 PM
  • Hi Striker,

    You cannot guarantee which page will render first so you cannot guarantee the order that these ready: events will be received.

    -Jeff


    Jeff Sanders (MSFT)

    • Marked as answer by Instriker Tuesday, June 26, 2012 2:43 PM
    Friday, June 22, 2012 7:03 PM
    Moderator
  • Ok, so I'll change my strategy. I have been able to make it work using the WinJS.Promise.timeout to free the current thread and not interfer with the actual processing.

    Thanks.

    Tuesday, June 26, 2012 2:45 PM