Skip to content

Special Levels: Error Messages

What are we learning here?

  • How to block a stage with an error message
  • Using the helper method block(Type, Message)

Now let's look at the layer error. This layer is also a blocking layer like block and have a higher z-index as as block. It's semi-transparent background is redder.

Here is another special feature of blocking layers. All blocking layers hide all underlying blocking layers, of course including all components loaded there. As soon as these are no longer used, they are removed and the highest underlying blocking layer is shown again. So there is always only one blocking layer to see.

The code of loading an error message manually in contrast to the code of loading an normal message is almost identical. The only difference would be the option level which value is in the one case block and in the other error.

We will use now a shortcut which is available for every component this.block(type,text,id) and unblock(id). type can be info or error. info will load the message into the level block like in the chapter before.

The shortcut will load the component Message into the level block like in the chapter before (setting type to info) or error (setting type to error) of the root stage.

Why using the shortcuts

The shortcut takes into account a few important points in cases where an application block and unblock a component especially if you have many parallel tasks which blocks and unblocks a component in a unpredictible manner.

The shortcut takes care of blocking the root stage and if not possible the stage of the component. This is important in cases where a hint should be given before a component is initialized. The shortcut remembers the stage in which the block was applied in order to destroy it correctly.

And finally the function tries to avoid race conditions between block and unblock:

  • Multiple parallel loads will be handled correctly.
  • Multiple parallel destroying and destroying of components that are not yet initialized will be handled correctly.

Let's add one button into our HTML structure:

src/demo/components/loading-components/index.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<div class="border rounded d-inline-block p-1 mr-2 my-1 bg-white text-dark">
  Block
  <button class="btn btn-xs btn-info" data-role="blockMessage">
    <i style="pointer-events: none" class="fas fa-check-circle"></i>
  </button>
  <button class="btn btn-xs btn-danger" data-role="blockError">
    <i style="pointer-events: none" class="fas fa-exclamation-circle"></i>
  </button>
</div>
<div class="border rounded d-inline-block p-1 mr-2 my-1 bg-white text-dark">
  Modal
  <button class="btn btn-xs btn-info" data-role="modalApp">
    <i style="pointer-events: none" class="fas fa-check-circle"></i>
  </button>
  <button class="btn btn-xs btn-info" data-role="modalMultiApp">
    <i style="pointer-events: none" class="fas fa-play-circle"></i>
  </button>
</div>
<div class="border rounded d-inline-block p-1 mr-2 my-1 bg-white text-dark">
  Hint
  <button class="btn btn-xs btn-info" data-role="hintInfo">
    <i style="pointer-events: none" class="fas fa-info-circle"></i>
  </button>
  <button class="btn btn-xs btn-success" data-role="hintSuccess">
    <i style="pointer-events: none" class="fas fa-check-circle"></i>
  </button>
  <button class="btn btn-xs btn-danger" data-role="hintError">
    <i style="pointer-events: none" class="fas fa-exclamation-circle"></i>
  </button>
</div>
<div class="border rounded d-inline-block p-1 mr-2 my-1 bg-white text-dark">
  Note
  <button class="btn btn-xs btn-info" data-role="hintInfoP">
    <i style="pointer-events: none" class="fas fa-info-circle"></i>
  </button>
  <button class="btn btn-xs btn-success" data-role="hintSuccessP">
    <i style="pointer-events: none" class="fas fa-check-circle"></i>
  </button>
  <button class="btn btn-xs btn-danger" data-role="hintErrorP">
    <i style="pointer-events: none" class="fas fa-exclamation-circle"></i>
  </button>
</div>
<div class="border rounded d-inline-block p-1 mr-2 my-1 bg-white text-dark">
  Splash
  <button class="btn btn-xs btn-info" data-role="hintSplash">
    <i style="pointer-events: none" class="fas fa-exclamation-circle"></i>
  </button>
</div>
<div class="border rounded d-inline-block p-1 mr-2 my-1 bg-white text-dark">
  App
  <button class="btn btn-xs btn-info" data-role="appNoId">
    <i style="pointer-events: none" class="fas fa-times-circle"></i>
  </button>
  <button class="btn btn-xs btn-info" data-role="appId">
    <i style="pointer-events: none" class="pe-none fas fa-check-circle"></i>
  </button>
</div>

And add a handler:

src/demo/components/loading-components/index.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import { Canvas, Hint, Message } from "@codecoupler/cc-ui";
import Mockup from "../../apps/mockup";
import { toRaw } from "vue";
import template from "./index.html";
import modalMultiApp from "./modal-multi-app";
export default class extends Canvas {
  static defaults = { target: null };
  async start() {
    this.element.innerHTML = template;
    this.element.addEventListener("click", (e) => {
      if (e.target.dataset.role) this[e.target.dataset.role]();
    });
    this.target = toRaw(this.options.target) ?? this.env.parent;
  }
  async blockError() {
    await this.target.block("info", "Normal Message", "A");
    await new Promise((r) => setTimeout(() => r(), 2000));
    await this.target.block("error", "Error Message", "B");
    await new Promise((r) => setTimeout(() => r(), 2000));
    this.target.unblock("B");
    await new Promise((r) => setTimeout(() => r(), 2000));
    this.target.unblock("A");
  }
  async blockMessage() {
    let message = await this.target.getStage("root").load({
      component: Message,
      options: { text: "You are blocked!" },
      level: "block"
    });
    for (let x = 0; x <= 100; x += 25) {
      await new Promise((r) => setTimeout(() => r(), 750));
      message.text = `Please Wait\n${x}% Progress`;
    }
    await new Promise((r) => setTimeout(() => r(), 2000));
    message.destroy();
  }
  modalMultiApp() {
    modalMultiApp(this.target, Mockup);
  }
  modalApp() {
    this.target.getStage("root").load({ component: Mockup, level: "block" });
  }
  hintInfo() {
    this.target.getStage("root").load(Hint, { type: "info", text: "Hint!" });
  }
  hintSuccess() {
    this.target.hint("success", "Hint!");
  }
  hintError() {
    this.target.hint("error", "Hint!");
  }
  hintInfoP() {
    this.target.hint("info-permanent", "Permanent Hint!");
  }
  hintSuccessP() {
    this.target.hint("success-permanent", "Permanent Hint!");
  }
  hintErrorP() {
    this.target.hint("error-permanent", "Permanent Hint!");
  }
  async hintSplash() {
    let splash = await this.target.hint("splash", "Splash!");
    for (let x = 0; x <= 100; x += 25) {
      await new Promise((r) => setTimeout(() => r(), 750));
      splash.text = `Please Wait\n${x}% Progress`;
    }
    await new Promise((r) => setTimeout(() => r(), 2000));
    splash.destroy();
  }
  appNoId() {
    this.target.stage.load(Mockup);
  }
  appId() {
    this.target.stage.load(Mockup, "fixed-id");
  }
}

Now click on the new button to start the show:

  • A normal message will be loaded into the layer block. As a result, the widget will be blocked.
  • After 2 seconds an error message will be loaded into the layer error. As a result, the layer block will be hidden.
  • After 2 seconds the error message component will be destroyed. As a result, the layer block appears again.
  • After 2 seconds the normal message component will be destroyed. As a result, the widget will be unblocked.