skimemo


skimemo - 日記/2019-04-19/NativeScriptのModal View内で画面遷移する際にcontextを渡す

_ NativeScriptのModal View内で画面遷移する際にcontextを渡す

NativeScriptのModal View内で画面遷移する場合、Frameを作ってその中にModal Viewを展開する必要がありますが、公式ドキュメント通りだとcontextが渡りません。

_ 公式ドキュメント方式

main-page.js

  1
  2
  3
const mainpage = args.object.page;
const context = "some context";
mainpage.showModal("modal-root", context, () => {}, true);    // 全画面でmodal-rootを開く


modal-root.xml

  1
<Frame defaultPage="first-modal-view-page"> 


first-modal-view-page.xml

  1
  2
  3
  4
  5
  6
<Page backgroundColor="green" navigatingTo="onNavigatingTo">
    <StackLayout backgroundColor="lightGreen">
        <Button text="Navigate" tap="onNavigate"/>
        <Button text="Close Modal" tap="onCloseModal"/>
    </StackLayout>
</Page> 


first-modal-view-page.js

  1
  2
  3
  4
function onNavigatingTo(args) {
    console.log(args.context);    // undefined
}
exports.onNavigate = onNavigate;

_ 解決方法

そこで、参考ページの通り、frameを作ってあげてその中のshownModallyイベントからさらにcontextを渡すようにします。

main-page.js

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
const Frame = require("tns-core-modules/ui/frame").Frame;
 
function onTap(args){
    const frame = new Frame();
    frame.on("shownModally",(args)=>{
        const component = args.object;
        if(!component.isLayoutValid){     // 一度backgroundにして再表示した場合は処理しない
            frame.navigate({ 
                moduleName: "first-modal-view-page",
                context: args.context     // showModal()のcontextを次のページへ渡す
            });
        }
    });
    const page = args.object.page;
    const context = "some context";
    page.showModal(frame, context, () => {}, true);
}

modal-root.xmlは不要です。
これでModal Viewの中でnavigateできますし、ActionBarも効くようになりました。

_ 2019/4/23追記

参考ページのままだと、HOMEボタンで一旦アプリを閉じた後再表示させた再に再度Navigateしてしまい、backボタンを押しても再度同じ画面が表示される(二重に画面遷移している)事が分かりました。このため、再表示時はnavigateしないよう、7行目のif文を追加しました。
但し、このisLayoutValidの役割についてはいまいちはっきりしていません。それぞれの操作をした際のプロパティの違いを元に実装していますので、場合によっては期待通り動いてくれない事があるかもしれません。

_ Modalダイアログの戻り値を受け取る(2019/5/6追記)

Modalを閉じた際、Modal内で処理した結果を受け取る方法です。
公式ドキュメント通りcloseCallbackを使いますが、Modal内の遷移先まで渡す必要があります。

まず、呼び出し側では、callback関数に受け取る引数を指定する(14行目)のと、遷移先のページにcontextとしてcloseCallbackを渡します( 7行目)。

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 
 
 
-
|
-
|
-
|
|
!
!
!
-
|
!
    const component = args.object;
    const page = component.page;
    const frame = new Frame();
    frame.on("shownModally",(args)=>{
        const component = args.object;
        if(!component.isLayoutValid){   // 一度backgroundにして再表示した場合は処理しない
            args.context.closeCallback = args.closeCallback;
            frame.navigate({ 
                moduleName: "reserve/reserve-cancel/reserve-cancel-page",
                context: args.context
            });
        }
    });
    page.showModal(frame, context, (result) => {
        console.log('result='+result);
    }, true);


次にModal側では、クラス変数にcloseCallbackを保存しておき(1,4行目)closeModal()の代わりにcloseCallback()を呼び出し、引数に返り値を渡します(11行目)。

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 
 
-
|
|
!
 
 
-
|
|
!
 
let closeCallback;
 
function onNavigatingTo(args) {
    closeCallback = args.context.closeCallback;
              :
}
exports.onNavigatingTo = onNavigatingTo;
 
function onCloseButtonTap(args) {
    const component = args.object;
    closeCallback("返り値");
}
exports.onCloseButtonTap= onCloseButtonTap;


これで、Modalを閉じた際にconsoleにresult=返り値が表示されればOKです。

Category: [NativeScript] - 06:01:53

  • さらに追記。 showModal(name, context, callback, fullscreen) 形式はdeprecatedになっているようなので、const option={...}; showModal(name, option); とやるのが正しいようです。 -- あき? 2019-06-19 (水) 11:34:56


 
Last-modified: 2019-06-19 (水) 11:35:28 (625d)