Dialogs

From WebOS101

Jump to: navigation, search

Contents

Error Dialog

Normally, you can call a simple error dialog with Mojo.Controller.errorDialog("My error message");

However, in a Multi-stage application, the errorDialog function is broken. The workaround is to pass a reference to the window of the active scene, like so:

var window = Mojo.Controller.getAppController().getActiveStageController().activeScene().window;
Mojo.Controller.errorDialog("There was an error. This is the message!", window);

Note: errorDialog() does not work from the setup() method of a scene.

Custom Dialogs

This example demonstrates how to use the Mojo.Controller.SceneController.showDialog method to create a custom dialog that will allow the user to adjust a date and time, using a DatePicker and a TimePicker.

Create a scene file for the dialog

Create an html file with the widgets you'd like to use. In this example, we'll add a DatePicker, a TimePicker and two buttons. The first button will use the date selected in the pickers. The second button will use the current date/time. Performing a back gesture in the dialog will not return a date (i.e. the user decided not to change an existing date in the originating scene).

The #{text} field in the dialog demonstrates how to pass information from the originating scene into the dialog's html using the showDialog method.

<div id="palm-dialog-content" class="palm-dialog-content">
<div id="dialog-title" class="dialog-title" x-mojo-loc="">
#{text}
</div>
<div class="palm-dialog-separator"></div>
<div class="dialog-message">
<div id="editdate-picker" x-mojo-element="DatePicker"></div>
<div id="edittime-picker" x-mojo-element="TimePicker"></div>
</div>
</div>
 
<div class="palm-dialog-buttons">
<div id='useDateTime' x-mojo-element="Button"></div>
<div id='useNow' x-mojo-element="Button"></div>
</div>


Calling the dialog from a scene

You call the dialog from your SceneAssistant, using the showDialog() function. The template property gives the location (under app/views) of the dialog's scene html file, in this case, app/views/myscene/editdate.html. We'll also use a myText variable to pass along a string to use in the dialog's template. Additional strings can be passed in the same manner by adding more properties to the showDialog function (text1: myOtherText, etc) and to the html template (#{text1}).

The assistant property defines the assistant for the dialog, and any parameters to be passed to the dialog's assistant. In this example, we'll use EditDateAssistant as the dialog assistant. The first parameter to be passed is a reference to the originating scene's assistant ("this") - as noted below, a dialog does not have it's own controller, so we'll need to use the originating scene's controller in order to setup widgets in the dialog.

The next parameter is a date object being passed to the dialog - if you're wanting to modify an existing date, we need to tell the dialog what that date/time is so that the Date & TimePickers will be created showing that existing date. Here, the existing date is a parameter passed to the editDate function in the originating scene assistant.

Finally, we can pass a callback function as a parameter to the dialog. This is a function in the originating scene assistant that can be called from the dialog assistant. Here, the callback function (MySceneAssistant.prototype.updateDate) simply updates a div in the originating scene with the returned date/time, formatted using Mojo.Format.

MySceneAssistant.prototype.editDate = function(date){
Mojo.Log.info("going to date dialog");
var myText = $L('Edit Date & Time');
this.controller.showDialog({
template: 'myscene/editdate',
assistant: new EditDateAssistant(this, date, this.updateDate.bind(this)),
text: myTtext // in this case, text is a field in the dialog's html template.
});
}
MySceneAssistant.prototype.updateDate = function(date) {
this.controller.get('myDate').innerHTML = Mojo.Format.formatDate(date, {date: 'medium'}) + "<br />" +
Mojo.Format.formatDate(date, {time: 'medium'});
 
// NOTE: there is a currently a bug in webOS that loses your scroll position when calling a customDialog.
// The following lines are a hack to scroll back to the top of the scene.
 
var scroller = this.controller.getSceneScroller();
//call the widget method for scrolling to the top
scroller.mojo.revealTop(0);
 
}

Create an assistant for the dialog

Create an assistant file for the dialog. In this example, we'll create an editdate-assistant.js in our app/assistants directory. In the constructor function for the dialog assistant, we need to store the parameters passed to the dialog so that they can be used in the other functions in the dialog assistant. (Note: if you use the Eclipse or Komodo wizards to create a scene & assistant for the dialog, you will have to remove the "scenes": "mydialog" line from your sources.json, or your assistant will never be loaded.)

A very important point: Dialogs are widgets, not scenes. They do not have their own scene controller, so you have to provide the controller from the originating scene. This is done by passing "this" from the originating scene. In this example, we store the passed "this" as this.sceneAssistant, which can then be used to refer to the originating scene controller as this.sceneAssistant.controller for calling setupWidget, etc.

The second parameter is the date that will be used for the initial value of the DatePicker and TimePicker. We'll save it as this.date, to be used later.

The third parameter is the callback function from the originating scene. We'll save it as this.callbackFunc.

function EditDateAssistant(sceneAssistant, date, callBackFunc) {
this.sceneAssistant = sceneAssistant;
this.callBackFunc = callBackFunc;
this.date = new Date(date); //this assumes the date passed was in milliseconds from UNIX epoch.
//if an actual date object, the new Date() would not be needed.
}

Another very important point: A reference to the dialog is passed to its assistant's setup() function. You will need to save this reference for later use (for example, to close the dialog). Here, we'll save it as this.widget.

The rest of setup() is fairly standard setup of widgets and listeners, EXCEPT that we must use the original scene assistant's controller. For example, instead of this.controller.setupWidget(), we use the referenct to the original scene assistant - which we passed in the showDialog() call and saved in the dialog assistant's constructor function - this.sceneAssistant.controller.setupWidget().

EditDateAssistant.prototype.setup = function(widget){
//Note: The following can be used to allow localization of the dialog
//without having multiple versions of the scene .html file.
//this.sceneAssistant.controller.get('dialog-title').innerHTML = $L('Edit Date & Time') + "...";
//however, in this case, we're passing the dialog title in the "text" field, and it can already
//be localized before it's passed to the dialog.
this.widget = widget;
 
this.sceneAssistant.controller.setupWidget('editdate-picker', {
label: $L('Date')
}, this.editDatePickerModel = {
date: this.date
});
 
this.sceneAssistant.controller.setupWidget('edittime-picker', {
label: $L('Time')
}, this.editTimePickerModel = {
time: this.date
});
 
this.sceneAssistant.controller.setupWidget('useDateTime', {}, {
label: $L("Use this Date & Time")
});
this.sceneAssistant.controller.setupWidget('useNow', {}, {
label: $L("Use Now")
});
 
this.useDateTimeHandler = this.useDateTime.bindAsEventListener(this);
this.sceneAssistant.controller.listen('useDateTime', Mojo.Event.tap, this.useDateTimeHandler);
this.useNowHandler = this.useNow.bindAsEventListener(this);
this.sceneAssistant.controller.listen('useNow', Mojo.Event.tap, this.useNowHandler);
 
}

The following two functions essentially both do the same thing, depending on which button is pressed. If the "Use this Date & Time" button, we grab the date & time from the pickers, call the updateDate function from the originating scene assistant, then close the dialog. If the "Use Now" button is pressed, we get the current system date/time, and do the same.

Note that since we used "this.date" as the model date for the DatePicker AND as the model time for the TimePicker, these two widgets automatically change the value of this.date whenever the user changes either the DatePicker or the TimePicker. This is very convenient, since we don't have to worry about combining the values from the two widgets. Thanks, Palm!

EditDateAssistant.prototype.useDateTime = function() {
// this.date is automagically updated since it's the model of the Date & Time pickers
this.callBackFunc(this.date);
this.widget.mojo.close();
}
 
EditDateAssistant.prototype.useNow = function() {
this.callBackFunc(new Date());
this.widget.mojo.close();
}

Finally, don't forget to stopListening in cleanup().

EditDateAssistant.prototype.cleanup = function() {
this.sceneAssistant.controller.stopListening('useDateTime', Mojo.Event.tap, this.useDateTimeHandler);
this.sceneAssistant.controller.stopListening('useNow', Mojo.Event.tap, this.useNowHandler);
}

Notes

When a custom dialog is active, all uses of the 'enter' key are blocked. When making custom dialogs, please do not forget to offer some way for the user to submit the data they are entering. (note: This needs explanation as I have apps that use enter-to-submit in custom dialogs)

Retrieved from "http://webos101.com/Dialogs"
Personal tools