diff --git a/CrossPlatformModules.csproj b/CrossPlatformModules.csproj
index 655640cd46..97a4249d0e 100644
--- a/CrossPlatformModules.csproj
+++ b/CrossPlatformModules.csproj
@@ -80,6 +80,9 @@
data-binding.xml
+
+ modal-page.xml
+
@@ -114,6 +117,9 @@
+
+ Designer
+
Designer
@@ -1992,7 +1998,7 @@
False
-
+
\ No newline at end of file
diff --git a/apps/modal-views-demo/main-page.ts b/apps/modal-views-demo/main-page.ts
index 9b915779c6..d1e1546978 100644
--- a/apps/modal-views-demo/main-page.ts
+++ b/apps/modal-views-demo/main-page.ts
@@ -1,13 +1,25 @@
import observable = require("data/observable");
import pages = require("ui/page");
import labelModule = require("ui/label");
+import frame = require("ui/frame");
var page: pages.Page;
var label: labelModule.Label;
-export function pageLoaded(args: observable.EventData) {
+export function onLoaded(args: observable.EventData) {
+ console.log("main-page.onLoaded");
+ if (args.object !== frame.topmost().currentPage) {
+ throw new Error("args.object must equal frame.topmost().currentPage on page.loaded");
+ }
page = args.object;
- label = page.getViewById("label");
+ label = frame.topmost().getViewById("label");
+ if (!label) {
+ throw new Error("Could not find `label`");
+ }
+}
+
+export function onNavigatedTo(args: observable.EventData) {
+ console.log("main-page.onNavigatedTo");
}
export function onTap(args: observable.EventData) {
diff --git a/apps/modal-views-demo/main-page.xml b/apps/modal-views-demo/main-page.xml
index d262d89373..f2b105846e 100644
--- a/apps/modal-views-demo/main-page.xml
+++ b/apps/modal-views-demo/main-page.xml
@@ -1,4 +1,4 @@
-
+
diff --git a/apps/tests/ui/page/modal-page.ts b/apps/tests/ui/page/modal-page.ts
new file mode 100644
index 0000000000..8a619d444f
--- /dev/null
+++ b/apps/tests/ui/page/modal-page.ts
@@ -0,0 +1,8 @@
+import {ShownModallyData} from "ui/page";
+import TKUnit = require("../../TKUnit");
+
+export function onShownModally(args: ShownModallyData) {
+ TKUnit.wait(0.350);
+ args.context.shownModally = true;
+ args.closeCallback("return value");
+}
\ No newline at end of file
diff --git a/apps/tests/ui/page/modal-page.xml b/apps/tests/ui/page/modal-page.xml
new file mode 100644
index 0000000000..e049008a4d
--- /dev/null
+++ b/apps/tests/ui/page/modal-page.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/apps/tests/ui/page/page-tests-common.ts b/apps/tests/ui/page/page-tests-common.ts
index 9bd3e3e9de..5e6f97dd74 100644
--- a/apps/tests/ui/page/page-tests-common.ts
+++ b/apps/tests/ui/page/page-tests-common.ts
@@ -27,6 +27,7 @@ import LabelModule = require("ui/label");
import stackLayoutModule = require("ui/layouts/stack-layout");
import helper = require("../helper");
import view = require("ui/core/view");
+import platform = require("platform");
export function addLabelToPage(page: PageModule.Page, text?: string) {
var label = new LabelModule.Label();
@@ -368,6 +369,31 @@ export function test_page_backgroundColor_is_white() {
});
}
+export function test_WhenPageIsLoadedFrameCurrentPageIsTheSameInstance() {
+ var page;
+ var loadedEventHandler = function (args) {
+ TKUnit.assert(FrameModule.topmost().currentPage === args.object, `frame.topmost().currentPage should be equal to args.object page instance in the page.loaded event handler. Expected: ${args.object.id}; Actual: ${FrameModule.topmost().currentPage.id};`);
+ }
+
+ var pageFactory = function (): PageModule.Page {
+ page = new PageModule.Page();
+ page.id = "newPage";
+ page.on(view.View.loadedEvent, loadedEventHandler);
+ var label = new LabelModule.Label();
+ label.text = "Text";
+ page.content = label;
+ return page;
+ };
+
+ try {
+ helper.navigate(pageFactory);
+ page.off(view.View.loadedEvent, loadedEventHandler);
+ }
+ finally {
+ helper.goBack();
+ }
+}
+
//export function test_ModalPage_Layout_is_Correct() {
// var testPage: PageModule.Page;
// var label: LabelModule.Label;
diff --git a/apps/tests/ui/page/page-tests.ios.ts b/apps/tests/ui/page/page-tests.ios.ts
index f1691d7d8e..3189b3002a 100644
--- a/apps/tests/ui/page/page-tests.ios.ts
+++ b/apps/tests/ui/page/page-tests.ios.ts
@@ -3,6 +3,7 @@ import PageModule = require("ui/page");
import TKUnit = require("../../TKUnit");
import LabelModule = require("ui/label");
import helper = require("../helper");
+import view = require("ui/core/view");
global.moduleMerge(PageTestCommon, exports);
@@ -23,3 +24,42 @@ export function test_NavigateToNewPage_InnerControl() {
TKUnit.assert(label.android === undefined, "InnerControl.android should be undefined after navigate back.");
TKUnit.assert(label.isLoaded === false, "InnerControl.isLoaded should become false after navigating back");
}
+
+export function test_WhenPageIsLoadedItCanShowAnotherPageAsModal() {
+ var masterPage;
+ var ctx = {
+ shownModally: false
+ };
+
+ var modalClosed = false;
+ var modalCloseCallback = function (returnValue: any) {
+ TKUnit.assert(ctx.shownModally, "Modal-page must be shown!");
+ TKUnit.assert(returnValue === "return value", "Modal-page must return value!");
+ TKUnit.wait(0.350);
+ modalClosed = true;
+ }
+
+ var loadedEventHandler = function (args) {
+ var basePath = "ui/page/";
+ args.object.showModal(basePath + "modal-page", ctx, modalCloseCallback, false);
+ };
+
+ var masterPageFactory = function (): PageModule.Page {
+ masterPage = new PageModule.Page();
+ masterPage.id = "newPage";
+ masterPage.on(view.View.loadedEvent, loadedEventHandler);
+ var label = new LabelModule.Label();
+ label.text = "Text";
+ masterPage.content = label;
+ return masterPage;
+ };
+
+ try {
+ helper.navigate(masterPageFactory);
+ TKUnit.waitUntilReady(() => { return modalClosed; });
+ masterPage.off(view.View.loadedEvent, loadedEventHandler);
+ }
+ finally {
+ helper.goBack();
+ }
+}
\ No newline at end of file
diff --git a/ui/frame/frame.ios.ts b/ui/frame/frame.ios.ts
index 2b285b3be7..0f0d9f42f8 100644
--- a/ui/frame/frame.ios.ts
+++ b/ui/frame/frame.ios.ts
@@ -309,6 +309,14 @@ class UINavigationControllerImpl extends UINavigationController implements UINav
frame._currentEntry = newEntry;
var newPage = newEntry.resolvedPage;
+
+ // In iOS we intentionally delay the raising of the 'loaded' event so both platforms behave identically.
+ // The loaded event must be raised AFTER the page is part of the windows hierarchy and
+ // frame.topmost().currentPage is set to the page instance.
+ // https://github.com/NativeScript/NativeScript/issues/779
+ (newPage)._delayLoadedEvent = false;
+ newPage._emit(view.View.loadedEvent);
+
frame._updateActionBar(newPage);
// notify the page
diff --git a/ui/page/page.ios.ts b/ui/page/page.ios.ts
index 38f218ed98..90fc227a8d 100644
--- a/ui/page/page.ios.ts
+++ b/ui/page/page.ios.ts
@@ -6,6 +6,7 @@ import uiUtils = require("ui/utils");
import utils = require("utils/utils");
import {device} from "platform";
import {DeviceType} from "ui/enums";
+import observable = require("data/observable");
global.moduleMerge(pageCommon, exports);
@@ -94,6 +95,15 @@ class UIViewControllerImpl extends UIViewController {
public viewWillAppear() {
trace.write(this._owner + " viewWillAppear", trace.categories.Navigation);
this._owner._enableLoadedEvents = true;
+
+ // In iOS we intentionally delay the raising of the 'loaded' event so both platforms behave identically.
+ // The loaded event must be raised AFTER the page is part of the windows hierarchy and
+ // frame.topmost().currentPage is set to the page instance.
+ // https://github.com/NativeScript/NativeScript/issues/779
+ if (!this._owner._isModal) {
+ this._owner._delayLoadedEvent = true;
+ }
+
this._owner.onLoaded();
this._owner._enableLoadedEvents = false;
}
@@ -111,6 +121,7 @@ export class Page extends pageCommon.Page {
public _enableLoadedEvents: boolean;
public _isModal: boolean = false;
public _UIModalPresentationFormSheet: boolean = false;
+ public _delayLoadedEvent;
constructor(options?: definition.Options) {
super(options);
@@ -137,6 +148,18 @@ export class Page extends pageCommon.Page {
}
}
+ public notify(data: T) {
+ // In iOS we intentionally delay the raising of the 'loaded' event so both platforms behave identically.
+ // The loaded event must be raised AFTER the page is part of the windows hierarchy and
+ // frame.topmost().currentPage is set to the page instance.
+ // https://github.com/NativeScript/NativeScript/issues/779
+ if (data.eventName === View.loadedEvent && this._delayLoadedEvent) {
+ return;
+ }
+
+ super.notify(data);
+ }
+
public onUnloaded() {
// loaded/unloaded events are handled in page viewWillAppear/viewDidDisappear
if (this._enableLoadedEvents) {