3

I have an AngularJS app using the Angular Material UI framework.

The app has different mechanisms showing dialogs (e.g error and loading spinner) and it would be preferable to only close one specifically chosen in certain scenarios, e.g. when an AJAX request is finished fetching data, I would like my loading spinner to close, but not any error dialog that may be the result of the fetching.

What I can find in documentation and code doesn't agree (though code should win the argument):

  • Documentation says only the latest can be closed, with an optional response
  • The code says the latest, a number of latest or all open can be closed, with an optional reason
  • Example in the documentation says a specific dialog can be closed, with a flag denoting how or why

I have made a demo of my intent, as MCV as possible – these are the highlights:

var dialog = {},
    promise = {};

function showDialogs(sourceEvent) {
    showDialog(sourceEvent, "one");
    showDialog(sourceEvent, "two");
}

function showDialog(sourceEvent, id) {
    dialog[id] = $mdDialog.alert({...});

    promise[id] = $mdDialog.show(dialog[id]);
    promise[id].finally(function() {
        dialog[id] = undefined;
    });
}

function closeDialogs() {
    $mdDialog.hide("Closed all for a reason", {closeAll: true});
}

function closeDialogLatest() {
    $mdDialog.hide("Closed from the outside");
}

function closeDialogReason() {
    $mdDialog.hide("Closed with a reason");
}

function closeDialogSpecific(id) {
    $mdDialog.hide(dialog[id], "finished");
}

EDIT:
I know the code always wins the argument about what happens, but I wasn't entirely sure it was the right code I was looking at.
I have updated the examples to better test and illustrate my point and problem. This shows things to work as the code said.

What I'm really looking for is whether it might still be possible to achieve my goal in some other way that I didn't think of yet.

Community
  • 1
  • 1
Flygenring
  • 3,818
  • 1
  • 32
  • 39
  • 1
    Probably the documentation is just wrong or too old. The documentation could say whatever the authors want to. If the code says that it is impossible, then it is actually impossible. I'm sorry. – RicoBrassers Sep 02 '16 at 12:28
  • I know the code is what matters, but I wasn't entirely sure it was the right code I was looking at. That said the example I made showed things to work as the code said, but it might still be possible to achieve my goal in some other way that I didn't think of yet. – Flygenring Sep 02 '16 at 12:37

2 Answers2

4

Using $mdPanel instead of $mdDialog I was able to achieve the desired effect; I forked my demo to reflect the changes – these are the highlights:

var dialog = {};

function showDialogs() {
    showDialog("one");
    showDialog("two");
}

function showDialog(id) {
    var config = {...};

    $mdPanel.open(config)
        .then(function(panelRef) {
            dialog[id] = panelRef;
        });
}

function closeDialogs() {
    var id;

    for(id in dialog) {
        closeDialogSpecific(id, "Closed all for a reason");
    }
}

function closeDialogSpecific(id, reason) {
    var message = reason || "finished: " + id;

    if(!dialog.hasOwnProperty(id) || !angular.isObject(dialog[id])) {
        return;
    }

    if(dialog[id] && dialog[id].close) {
        dialog[id].close()
            .then(function() {
                vm.feedback = message;
            });
        dialog[id] = undefined;
    }
}
Flygenring
  • 3,818
  • 1
  • 32
  • 39
2

I would suggest having two or more dialogs up at the same time isn't ideal and probably not recommended by Google Material design.

To quote from the docs

Use dialogs sparingly because they are interruptive.

You say:

when an AJAX request is finished fetching data, I would like my loading spinner to close, but not any error dialog that may be the result of the fetching.

My solution here would be to have one dialog which initially shows the spinner. Once the request is finished replace the spinner with any messages.

camden_kid
  • 12,591
  • 11
  • 52
  • 88
  • I agree there shouldn't be too many dialogs and they're built to stack in the framework, so it's okay to a certain degree. The reason I do it is to inform users of errors that will interrupt their work and (as specifically requested) blocking all interaction while loading data (i.e. saving long forms) so the user knows stuff is happening but can't mess up in the meantime. – Flygenring Sep 02 '16 at 12:38
  • @Flygenring Are you sure you can't accomplish all that with one dialog? :-) – camden_kid Sep 02 '16 at 12:58
  • I might be able to, but it would require a restructuring of the whole system as the error handling (including dialogs) are handled centrally by hooking into the built-in exception handling and the loading is applied directly on certain actions. But the suggestions _are_ much appreciated! :-) – Flygenring Sep 02 '16 at 13:08
  • 2
    Whether or not it is the optimal or prefered solution to my problem, I found a way to do it using the material framework in intended ways, demonstrated by my answer :-) – Flygenring Sep 30 '16 at 12:23
  • 1
    I'm developing a realtime app with a websocket connection that looses connection when you loose wifi or unplug the ethernet cable. In that case I want to show a non-dismissable overlay dialog with a backdrop saying "Disconnected. Trying to reconnect...", because the UI won't be interactive without a connection. I may already be showing some other dialog when this happens, and I don't want that to be closed because I want the user to be able to resume their work when the connection comes back. This is a good example case where you can end up having to support multiple dialogs at the same time. – Sámal Rasmussen Jan 14 '19 at 12:07