1# Global Custom Dialog Box Independent of UI Components (openCustomDialog) (Recommended) 2 3Due to the restrictions of [CustomDialogController](../reference/apis-arkui/arkui-ts/ts-methods-custom-dialog-box.md#customdialogcontroller), such as lack of support for dynamic creation and refresh, for more complex use cases, you are advised to use the [openCustomDialog](../reference/apis-arkui/js-apis-arkui-UIContext.md#opencustomdialog12) API provided by the **PromptAction** object obtained from **UIContext** to implement a custom dialog box. 4 5> **NOTE** 6> 7> There are two ways to create a custom dialog using **openCustomDialog**: 8> - **openCustomDialog** with **ComponentContent**: By encapsulating content using **ComponentContent**, the dialog box can be decoupled from the UI, offering greater flexibility and satisfying needs for encapsulation. This approach provides full customizability of the dialog box style and allows for dynamic updates to dialog box parameters using the **updateCustomDialog** API after the dialog box is opened. 9> - **openCustomDialog** with **builder**: Unlike **ComponentContent**, the builder must be bound to the context and is somewhat coupled with the UI. This approach provides a default dialog box style, suitable for those who want to achieve a look consistent with the system's default dialog box style. 10> 11> This topic focuses on creating custom dialog boxes using **ComponentContent**. For the usage of the builder-based dialog box, see [openCustomDialog](../reference/apis-arkui/js-apis-arkui-UIContext.md#opencustomdialog12-1). 12 13**openCustomDialog** can be configured with [isModal](../reference/apis-arkui/js-apis-arkui-UIContext.md#opencustomdialog12) to create modal and non-modal dialog boxes. When **isModal** is set to **true**, the dialog box is modal. When **isModal** is set to **false**, the dialog box is non-modal. 14 15## Lifecycle 16 17The dialog box provides lifecycle functions to notify users of its lifecycle events. The order in which these lifecycle events are triggered is as follows: **onWillAppear**, **onDidAppear**, **onWillDisappear**, **onDidDisappear**. 18 19| Name |Type| Description | 20| ----------------- | ------ | ---------------------------- | 21| onDidAppear | () => void | Callback invoked when the dialog box appears. | 22| onDidDisappear |() => void | Callback invoked when the dialog box disappears. | 23| onWillAppear | () => void | Callback invoked when the dialog box is about to appear.| 24| onWillDisappear | () => void | Callback invoked when the dialog box is about to disappear.| 25 26## Opening and Closing a Custom Dialog Box 27 28> **NOTE** 29> 30> For details about the variables, see [Example](#example). 31 321. Create a **ComponentContent** instance. 33 34 **ComponentContent** is used to define the content of the custom dialog box. **wrapBuilder(buildText)** encapsulates the custom component, and **new Params(this.message)** is the input parameter for the custom component, which can be omitted or passed in with basic data types. 35 36 ```ts 37 private contentNode: ComponentContent<Object> = new ComponentContent(this.ctx, wrapBuilder(buildText), new Params(this.message)); 38 ``` 392. Open the custom dialog box. 40 41 Call **openCustomDialog** to open the custom dialog box, whose **customStyle** is set to **true** by default, meaning that the dialog box is styled entirely based on the **contentNode** settings you provide. 42 43 ```ts 44 PromptActionClass.ctx.getPromptAction().openCustomDialog(PromptActionClass.contentNode, PromptActionClass.options) 45 .then(() => { 46 console.info('OpenCustomDialog complete.') 47 }) 48 .catch((error: BusinessError) => { 49 let message = (error as BusinessError).message; 50 let code = (error as BusinessError).code; 51 console.error(`OpenCustomDialog args error code is ${code}, message is ${message}`); 52 }) 53 ``` 543. Close the custom dialog box. 55 56 Call **closeCustomDialog**, which requires the ComponentContent corresponding to the dialog box to be closed. To set a close method within the dialog box, follow the complete sample to encapsulate this functionality into a static method. 57 58 To release the corresponding **ComponentContent** after the dialog box is closed, call the [dispose](../reference/apis-arkui/js-apis-arkui-ComponentContent.md#dispose) API of the **ComponentContent**. 59 60 ```ts 61 62 PromptActionClass.ctx.getPromptAction().closeCustomDialog(PromptActionClass.contentNode) 63 .then(() => { 64 console.info('CloseCustomDialog complete.') 65 if (this.contentNode !== null) { 66 this.contentNode.dispose(); // Dispose of contentNode. 67 } 68 }) 69 .catch((error: BusinessError) => { 70 let message = (error as BusinessError).message; 71 let code = (error as BusinessError).code; 72 console.error(`CloseCustomDialog args error code is ${code}, message is ${message}`); 73 }) 74 ``` 75 76## Updating the Content of a Custom Dialog Box 77 78**ComponentContent** has the same usage constraints as [BuilderNode](../reference/apis-arkui/js-apis-arkui-builderNode.md) and does not support custom components using decorators such as [@Reusable](../ui/state-management/arkts-create-custom-components.md#basic-structure-of-a-custom-component), [@Link](../ui/state-management/arkts-link.md), [@Provide](../ui/state-management/arkts-provide-and-consume.md), and [@Consume](../ui/state-management/arkts-provide-and-consume.md) to synchronize the state between the page where the dialog box pops up and the custom component in **ComponentContent**. Therefore, if you need to update the content of the custom component in the dialog box, use the **update** API provided by **ComponentContent**. 79 80```ts 81this.contentNode.update(new Params('update')) 82``` 83 84## Updating the Attributes of a Custom Dialog Box 85 86You can dynamically update the attributes of the dialog box through **updateCustomDialog**. Currently, the following attributes are supported: **alignment**, **offset**, **autoCancel**, and **maskColor**. 87Note that when attributes are updated, those unset will be restored to their default values. For example, if you initially set **{ alignment: DialogAlignment.Top, offset: { dx: 0, dy: 50 } }** and then update it to **{ alignment: DialogAlignment.Bottom }**, the initially set **offset: { dx: 0, dy: 50 }** will not be retained; the offset will be restored to the default value. 88 89```ts 90PromptActionClass.ctx.getPromptAction().updateCustomDialog(PromptActionClass.contentNode, options) 91 .then(() => { 92 console.info('UpdateCustomDialog complete.') 93 }) 94 .catch((error: BusinessError) => { 95 let message = (error as BusinessError).message; 96 let code = (error as BusinessError).code; 97 console.error(`UpdateCustomDialog args error code is ${code}, message is ${message}`); 98 }) 99``` 100 101## Example 102 103```ts 104// PromptActionClass.ets 105import { BusinessError } from '@kit.BasicServicesKit'; 106import { ComponentContent, promptAction } from '@kit.ArkUI'; 107import { UIContext } from '@ohos.arkui.UIContext'; 108 109export class PromptActionClass { 110 static ctx: UIContext; 111 static contentNode: ComponentContent<Object>; 112 static options: promptAction.BaseDialogOptions; 113 114 static setContext(context: UIContext) { 115 PromptActionClass.ctx = context; 116 } 117 118 static setContentNode(node: ComponentContent<Object>) { 119 PromptActionClass.contentNode = node; 120 } 121 122 static setOptions(options: promptAction.BaseDialogOptions) { 123 PromptActionClass.options = options; 124 } 125 126 static openDialog() { 127 if (PromptActionClass.contentNode !== null) { 128 PromptActionClass.ctx.getPromptAction().openCustomDialog(PromptActionClass.contentNode, PromptActionClass.options) 129 .then(() => { 130 console.info('OpenCustomDialog complete.') 131 }) 132 .catch((error: BusinessError) => { 133 let message = (error as BusinessError).message; 134 let code = (error as BusinessError).code; 135 console.error(`OpenCustomDialog args error code is ${code}, message is ${message}`); 136 }) 137 } 138 } 139 140 static closeDialog() { 141 if (PromptActionClass.contentNode !== null) { 142 PromptActionClass.ctx.getPromptAction().closeCustomDialog(PromptActionClass.contentNode) 143 .then(() => { 144 console.info('CloseCustomDialog complete.') 145 }) 146 .catch((error: BusinessError) => { 147 let message = (error as BusinessError).message; 148 let code = (error as BusinessError).code; 149 console.error(`CloseCustomDialog args error code is ${code}, message is ${message}`); 150 }) 151 } 152 } 153 154 static updateDialog(options: promptAction.BaseDialogOptions) { 155 if (PromptActionClass.contentNode !== null) { 156 PromptActionClass.ctx.getPromptAction().updateCustomDialog(PromptActionClass.contentNode, options) 157 .then(() => { 158 console.info('UpdateCustomDialog complete.') 159 }) 160 .catch((error: BusinessError) => { 161 let message = (error as BusinessError).message; 162 let code = (error as BusinessError).code; 163 console.error(`UpdateCustomDialog args error code is ${code}, message is ${message}`); 164 }) 165 } 166 } 167} 168``` 169 170```ts 171// Index.ets 172import { ComponentContent } from '@kit.ArkUI'; 173import { PromptActionClass } from './PromptActionClass'; 174 175class Params { 176 text: string = "" 177 178 constructor(text: string) { 179 this.text = text; 180 } 181} 182 183@Builder 184function buildText(params: Params) { 185 Column() { 186 Text(params.text) 187 .fontSize(50) 188 .fontWeight(FontWeight.Bold) 189 .margin({ bottom: 36 }) 190 Button('Close') 191 .onClick(() => { 192 PromptActionClass.closeDialog() 193 }) 194 }.backgroundColor('#FFF0F0F0') 195} 196 197@Entry 198@Component 199struct Index { 200 @State message: string = "hello" 201 private ctx: UIContext = this.getUIContext(); 202 private contentNode: ComponentContent<Object> = 203 new ComponentContent(this.ctx, wrapBuilder(buildText), new Params(this.message)); 204 205 aboutToAppear(): void { 206 PromptActionClass.setContext(this.ctx); 207 PromptActionClass.setContentNode(this.contentNode); 208 PromptActionClass.setOptions({ alignment: DialogAlignment.Top, offset: { dx: 0, dy: 50 } }); 209 } 210 211 build() { 212 Row() { 213 Column() { 214 Button("open dialog and update options") 215 .margin({ top: 50 }) 216 .onClick(() => { 217 PromptActionClass.openDialog() 218 219 setTimeout(() => { 220 PromptActionClass.updateDialog({ 221 alignment: DialogAlignment.Bottom, 222 offset: { dx: 0, dy: -50 } 223 }) 224 }, 1500) 225 }) 226 Button("open dialog and update content") 227 .margin({ top: 50 }) 228 .onClick(() => { 229 PromptActionClass.openDialog() 230 231 setTimeout(() => { 232 this.contentNode.update(new Params('update')) 233 }, 1500) 234 }) 235 } 236 .width('100%') 237 .height('100%') 238 } 239 .height('100%') 240 } 241} 242``` 243 244  245