Skip to content
This repository has been archived by the owner on Jul 8, 2020. It is now read-only.

Dialogs and Action Sheet (The M Project 1.x)

hano edited this page Dec 3, 2013 · 1 revision

Introduction

Dialogs give you the opportunity to give the user visual feedback about things going on in your application. For example, you can display an error message in an alert dialog when a request to a remote machine fails because of a missing internet connection. Basically, we divide between two kinds of dialogs: an alert dialog and a confirm dialog. While the alert dialog just transports a message to the user, the confirm dialog can prompt the user to come to a decision, like: "Do you really want to delete this entry?" => YES/NO. Action Sheets came to fame with the rise of iOS devices and apps. It's another dialog form, that can contain multiple buttons that offer different decisions to the user.

All views are designed by calling the actual method on the M.DialogView object:

  • alert for showing an alert dialog
  • confirm for showing a confirm dialog
  • actionSheet for showing an action sheet

All methods take an object as parameter that contains all parameters for the actual dialog.

The alert dialog: M.AlertDialogView

The alert dialog view is a simple view that has two mandatory and two optional parameters:

  • title : (default: 'Alert') Defines the title of the confirm dialog
  • message : Defines the message of the alert dialog
  • confirmButtonValue : (default: 'Ok') (optional) The value of the close button
  • callbacks: (optional) The object defining the confirm callback

The dialog is similar to the alert dialog that JavaScript offers with the alert('Hello World') call, except that the TMP alert dialog does not block the application. In addition it can show a much more customized title than the native JavaScript alert dialog (this one usually shows something strange like "Die Seite auf www.the-m-project.net says:" in the title bar). It is also possible to pass a callback to the dialog, that is executed after the user clicked the confirm button in the dialog. Therefore we pass the callback object with a nested object named confirm to the call. In this confirm object we define target and action. (Note: It is also possible to pass a function as action instead of a string (this is possible throughout every callback passing). It is executed in the scope of the target.)

Here's a complete example:

  M.DialogView.alert({
    title: 'No Connection',
    message: 'No Connection available. Request failed.'
    confirmButtonValue: 'Sad.',
    callbacks: {
      confirm: {
        target: myApp.myController,
        action: function() {
          console.log('Sad.');
        }
      }
    }
  });

Of course you can use the M.I18N localization object to localize your alerts!

The confirm dialog: M.ConfirmDialogView

The confirm dialog is a little more complex than the alert dialog. It also takes the two parameters of the alert dialog but additionaly has another mandatory parameter (callbacks) and two optional parameters. Here's all five:

  • title : (default: 'Confirm') Defines the title of the confirm dialog
  • message : Defines the message of the confirm dialog
  • callbacks : The object defining the callbacks for the buttons
  • confirmButtonValue (optional) : Defines the value on the confirm button
  • cancelButtonValue (optional) : Defines the value on the cancel button

If the last two optional parameters are not passed, the buttons will have "Ok" and "Cancel" as their value. As the name "callback" indicates, this parameter defines the callback function of the dialog. You might ask yourself "Why do I need callbacks for a confirm dialog?". A confirm dialog marks a fork in your application flow. You want the user to make a decision. And for every decision the application continues in different directions. For this purpose, you pass callbacks that define where to go after the user made a decision.

The confirm dialog callbacks

The way of passing callbacks to the dialog is the same as passing callback functions that are binded to events, e.g. in a view. You pass a target and an action as usual. But you have to pass them inside another two objects named confirm and cancel. Here's an example:

callbacks: {
  confirm: {
    target: myController,
    action: 'myActionForConfirm'
  },
  cancel: {
    target: myController,
    action: 'myActionForCancel'
  }
}

The complete call to open a confirm dialog looks like this:

M.DialogView.confirm({
  title: 'Remove a Task',
  message: 'Do you really want to get rid of this task?',
  confirmButtonValue: 'Kick it!',
  cancelButtonValue: 'NOT!',
  callbacks: {
    confirm: {
      target: myApp.myController,
      action: 'myActionForConfirm'
    },
    cancel: {
      target: myApp.myController,
      action: 'myActionForCancel'
    }
  }
});

The action sheet dialog: M.ActionSheetDialogView

The action sheet dialog is mostly known from iOS, where it is used in a variety of applications. It presents a dialog that offers multiple options to the user. One of these options often is a destructive action, e.g. for removing something from a collection. Another option is a 'Cancel'-Option that is used to not make a choice, but cancel it. In difference to the other two dialogs, the action sheet does not show a message, it only shows a title and the choices represented by buttons. The action sheet's behaviour and look is defined by the following properties:

  • title : (default: 'Confirm') Defines the title of the confirm dialog
  • `destructiveButtonValue' : (optional) Defines the value shown on the destructive button
  • cancelButtonValue : (optional) Defines the value shown on the cancel button
  • otherButtonValues: (optional) An array of strings defining the values of the other shown buttons. Each string represents one button
  • otherButtonTags : (optional) An array of strings defining a tag for each of the buttons defined by the previously mentioned values. The number of strings in this array must match the number of values defined in otherButtonValues. If not, these tags are skipped and the values are also used as tags of the buttons. The tags are used to identify which button was pressed in the callback (see below).
  • callbacks : The object defining the callbacks for the buttons

The action sheet callbacks

The callbacks object of the action sheet dialog differs from the one used for the confirm dialogs. In the confirm dialog, we can be sure that there are two callbacks necessary (no more, no less). The action sheet dialog is able to show any number of buttons besides the destructive and the cancel button. This is the reason, why the callbacks for every other button besides the two mentioned are not defined individually in this callback. There is one callback for all other buttons. That means we have three callbacks in total:

  • destruction
  • cancel
  • other
callbacks: {
  destruction: {
    target: myApp.myController,
    action: 'myActionForDestruction'
  },
  cancel: {
    target: myApp.myController,
    action: 'myActionForCancel'
  },
  other: {
    target: myApp.myController,
    action: 'myActionForOther'
  }
}

The callback object destruction and cancel are straightforward. Their meaning is self-explaining. But what about the callback object other? Here, all callbacks of the "other" buttons are unified. But how can you decide which button was pressed? Now, this is the reason, why you might wanted to pass tags to the "other" buttons in the array otherButtonTags. The tag of the button that was pressed is passed to the callback function (here myActionForOther). In this callback function you can decide what to do next on basis of the tag value. If the number of tag values passed to the action sheet call does not match the number of values defined (means the number of other buttons defined) or if no tags are passed numbers are used instead of the tags. The following snippet shows such a case:

...
otherButtonValues: ['Add', 'Edit', 'Copy'], // no otherButtonTags array is passed
...

In this case, a button number is passed to the callback function. The numbers start by 0 and increment by 1 for each button. The number represent the index that these values have in the array. In this example this results in the button with the value "Add" having the number 0, the "Edit" button having the number 1 and the "Copy" button having the number 2.

The following code snippets shows a possible definition of an action sheet and the use of the other callback with given tags.

M.DialogView.actionSheet({
  title: 'What time is it?',
  destructiveButtonValue: 'Crunch Time!',
  cancelButtonValue: 'Time to cancel',
  otherButtonValues: ['Tea Time', 'Beer Time', 'Party Time'],
  otherButtonTags: ['tea', 'beer', 'party'],
  callbacks: {
    destruction: {
      target: myApp.myController,
      action: 'myActionForDestruction'
    },
    cancel: {
      target: myApp.myController,
      action: 'myActionForCancel'
    },
    other: {
      target: myApp.myController,
      action: 'myActionForOther'
    }
  }
});
...
myActionForOther: function(buttonTag) {
  switch(buttonTag) {
    case 'tea':
      console.log("Five O'Clock in Britain...");
      break;
    case 'beer':
      console.log("It's beer o'clock... ");
      break;
    case 'party':
      console.log("Paaarrrttteeeyy");
      break;
    default:
      console.log("It's always party time");
      break;
  }
}

The Dialog's CSS properties

The styling of the dialogs is written down in a CSS file named tmp.css located in modules/tmp_themes/ in the framework's directory. All relevant styling properties are written down here. They are prefixed in the following manner:

  • tmp-dialog : for all dialog relevant stylings
  • tmp-actionsheet : for the additional stylings of the actionsheet

The CSS should be self-explanatory. The animations are used from jQuery Mobile's CSS. It is pop for the action and confirm dialog and slideup for the action sheet. These animations are non-configurable. We defined them as being the ones for the dialogs (give us some feedback if you don't agree with this decision).