# NodeController
The **NodeController** module provides APIs for managing custom nodes, such as creating, showing, and updating custom nodes, and APIs for mounting custom nodes to a [NodeContainer](arkui-ts/ts-basic-components-nodecontainer.md#nodecontainer) component.
> **NOTE**
>
> The initial APIs of this module are supported since API version 11. Newly added APIs will be marked with a superscript to indicate their earliest API version.
>
> **NodeController** is not available in DevEco Studio Previewer.
## Modules to Import
```ts
import { NodeController } from '@kit.ArkUI';
```
## NodeController
Implements a **NodeController** instance to manage the bound [NodeContainer](arkui-ts/ts-basic-components-nodecontainer.md#nodecontainer) component. One **NodeController** instance can be bound to only one [NodeContainer](arkui-ts/ts-basic-components-nodecontainer.md#nodecontainer) component.
**Atomic service API**: This API can be used in atomic services since API version 12.
**System capability**: SystemCapability.ArkUI.ArkUI.Full
### makeNode
abstract makeNode(uiContext : UIContext): FrameNode | null
Called when the [NodeContainer](arkui-ts/ts-basic-components-nodecontainer.md#nodecontainer) component bound to this **NodeController** instance is created. This callback returns a node, which will be mounted to the **NodeContainer**.
This callback can also be invoked through the **rebuild()** method of **NodeController**.
**Atomic service API**: This API can be used in atomic services since API version 12.
**System capability**: SystemCapability.ArkUI.ArkUI.Full
**Parameters**
| Name | Type | Mandatory| Description |
| --------- | ----------------------------------------- | ---- | ------------------------------------------------------------------------------------------------------------- |
| uiContext | [UIContext](./js-apis-arkui-UIContext.md) | Yes | UI context of the bound **NodeContainer** component.|
**Return value**
| Type | Description |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [FrameNode](./js-apis-arkui-frameNode.md#framenode)\| null | **FrameNode** object, which will be mounted to the placeholder node of the **NodeContainer** component. If a **null** object is returned, the child nodes of the corresponding **NodeContainer** component are removed.|
### aboutToAppear
aboutToAppear?(): void
Called after the [NodeContainer](arkui-ts/ts-basic-components-nodecontainer.md#nodecontainer) component bound to this **NodeController** instance is attached and about to appear.
> **NOTE**
>
> For details about the callback timing, see [onAppear](arkui-ts/ts-universal-events-show-hide.md#onappear).
**Atomic service API**: This API can be used in atomic services since API version 12.
**System capability**: SystemCapability.ArkUI.ArkUI.Full
### aboutToDisappear
aboutToDisappear?(): void
Called when the [NodeContainer](arkui-ts/ts-basic-components-nodecontainer.md#nodecontainer) component bound to this **NodeController** instance is detached and about to be hidden.
> **NOTE**
>
> For details about the callback timing, see [onDisAppear](arkui-ts/ts-universal-events-show-hide.md#ondisappear).
**Atomic service API**: This API can be used in atomic services since API version 12.
**System capability**: SystemCapability.ArkUI.ArkUI.Full
### onAttach18+
onAttach?(): void
Called when the [NodeContainer](arkui-ts/ts-basic-components-nodecontainer.md#nodecontainer) component bound to this **NodeController** instance is attached to the main node tree.
> **NOTE**
>
> For details about the callback timing, see [onAttach](arkui-ts/ts-universal-events-show-hide.md#onattach12).
**Atomic service API**: This API can be used in atomic services since API version 18.
**System capability**: SystemCapability.ArkUI.ArkUI.Full
### onDetach18+
onDetach?(): void
Called when the [NodeContainer](arkui-ts/ts-basic-components-nodecontainer.md#nodecontainer) component bound to this **NodeController** instance is detached from the main node tree.
> **NOTE**
>
> For details about the callback timing, see [onDetach](arkui-ts/ts-universal-events-show-hide.md#ondetach12).
**Atomic service API**: This API can be used in atomic services since API version 18.
**System capability**: SystemCapability.ArkUI.ArkUI.Full
### onWillBind18+
onWillBind?(containerId: number): void
Called when this **NodeController** instance is about to be bound to a [NodeContainer](arkui-ts/ts-basic-components-nodecontainer.md#nodecontainer) component.
**Atomic service API**: This API can be used in atomic services since API version 18.
**System capability**: SystemCapability.ArkUI.ArkUI.Full
**Parameters**
| Name | Type | Mandatory| Description |
| ----------- | ------ |----- |---------------------------------------------------------------------------------------------------------------------------------- |
| containerId | number | Yes | ID of the [NodeContainer](arkui-ts/ts-basic-components-nodecontainer.md#nodecontainer) component to which the **NodeController** instance is about to be bound.|
### onWillUnbind18+
onWillUnbind?(containerId: number): void
Called when this **NodeController** instance is about to be unbound from a [NodeContainer](arkui-ts/ts-basic-components-nodecontainer.md#nodecontainer) component.
**Atomic service API**: This API can be used in atomic services since API version 18.
**System capability**: SystemCapability.ArkUI.ArkUI.Full
**Parameters**
| Name | Type | Mandatory| Description |
| ----------- | ------ |----- |---------------------------------------------------------------------------------------------------------------------------------- |
| containerId | number | Yes | ID of the [NodeContainer](arkui-ts/ts-basic-components-nodecontainer.md#nodecontainer) component from which the **NodeController** instance is about to be unbound.|
### onBind18+
onBind?(containerId: number): void
Called after this **NodeController** instance is bound to a [NodeContainer](arkui-ts/ts-basic-components-nodecontainer.md#nodecontainer) component.
**Atomic service API**: This API can be used in atomic services since API version 18.
**System capability**: SystemCapability.ArkUI.ArkUI.Full
**Parameters**
| Name | Type | Mandatory| Description |
| ----------- | ------ |----- |---------------------------------------------------------------------------------------------------------------------------------- |
| containerId | number | Yes | ID of the [NodeContainer](arkui-ts/ts-basic-components-nodecontainer.md#nodecontainer) component to which the **NodeController** instance is bound.|
### onUnbind18+
onUnbind?(containerId: number): void
Called after this **NodeController** instance is unbound from a [NodeContainer](arkui-ts/ts-basic-components-nodecontainer.md#nodecontainer) component.
**Atomic service API**: This API can be used in atomic services since API version 18.
**System capability**: SystemCapability.ArkUI.ArkUI.Full
**Parameters**
| Name | Type | Mandatory| Description |
| ----------- | ------ |----- |---------------------------------------------------------------------------------------------------------------------------------- |
| containerId | number | Yes | ID of the [NodeContainer](arkui-ts/ts-basic-components-nodecontainer.md#nodecontainer) component from which the **NodeController** instance is unbound.|
### aboutToResize
aboutToResize?(size: Size): void
Called when the [NodeContainer](arkui-ts/ts-basic-components-nodecontainer.md#nodecontainer) component bound to this **NodeController** instance is resized.
**Atomic service API**: This API can be used in atomic services since API version 12.
**System capability**: SystemCapability.ArkUI.ArkUI.Full
**Parameters**
| Name| Type | Mandatory| Description |
| ------ | ---------------------------------------- | ---- | ---------------------------------------- |
| size | [Size](./js-apis-arkui-graphics.md#size) | Yes | Width and height of the component, in vp.|
### onTouchEvent
onTouchEvent?(event: TouchEvent): void
Called when the [NodeContainer](arkui-ts/ts-basic-components-nodecontainer.md#nodecontainer) component bound to this **NodeController** instance receives a touch event.
**Atomic service API**: This API can be used in atomic services since API version 12.
**System capability**: SystemCapability.ArkUI.ArkUI.Full
**Parameters**
| Name| Type | Mandatory| Description |
| ------ | ------------------------------------------------------------------------- | ---- | ---------- |
| event | [TouchEvent](arkui-ts/ts-universal-events-touch.md#touchevent) | Yes | Touch event.|
### rebuild
rebuild(): void
Instructs the [NodeContainer](arkui-ts/ts-basic-components-nodecontainer.md#nodecontainer) component bound to this **NodeController** instance to call the [makeNode](#makenode) API again to change child nodes.
**Atomic service API**: This API can be used in atomic services since API version 12.
**System capability**: SystemCapability.ArkUI.ArkUI.Full
> **NOTE**
> Since the **rebuild** API is actively called by the application and is tied to the UI, you need to ensure that the UI context is valid at the time of the call, that is, it must be consistent with the UI context of the bound NodeContainer.
>
> In cases where the UI context is unclear, for example, during event callbacks, you can use the [runScopedTask](./js-apis-arkui-UIContext.md#runscopedtask) method of [UIContext](./js-apis-arkui-UIContext.md) to explicitly define the UI context at the time of the call.
## Example
### Example 1: Implementing Lifecycle Callbacks for Node Layout, Touch, Mounting, and Unmounting Events
This example demonstrates how to manage the lifecycle of a **NodeContainer** component using **aboutToResize**, **onTouchEvent**,
**aboutToAppear**, and **aboutToDisappear**.
It also shows how to mount a BuilderNode using **NodeController**.
```ts
import { NodeController, BuilderNode, Size, FrameNode ,UIContext } from '@kit.ArkUI';
class Params {
text: string = "this is a text"
}
@Builder
function buttonBuilder(params: Params) {
Column() {
Button(params.text)
.fontSize(12)
.borderRadius(8)
.borderWidth(2)
.backgroundColor(Color.Orange)
}
}
class MyNodeController extends NodeController {
private buttonNode: BuilderNode<[Params]> | null = null;
private wrapBuilder: WrappedBuilder<[Params]> = wrapBuilder(buttonBuilder);
makeNode(uiContext: UIContext): FrameNode {
if (this.buttonNode == null) {
this.buttonNode = new BuilderNode(uiContext);
this.buttonNode.build(this.wrapBuilder, { text: "This is a Button" })
}
return this.buttonNode!.getFrameNode()!;
}
aboutToResize(size: Size) {
console.log("aboutToResize width : " + size.width + " height : " + size.height)
}
aboutToAppear() {
console.log("aboutToAppear")
}
aboutToDisappear() {
console.log("aboutToDisappear");
}
onTouchEvent(event:TouchEvent) {
console.log("onTouchEvent");
}
}
@Entry
@Component
struct Index {
private myNodeController: MyNodeController = new MyNodeController();
build() {
Column() {
NodeContainer(this.myNodeController)
}
.padding({ left: 35, right: 35, top: 35 })
.width("100%")
.height("100%")
}
}
```

### Example 2: Implementing Lifecycle Callbacks for Node Binding/Unbinding and Tree Attachment/Detachment
This example demonstrates how to manage the lifecycle of a **NodeContainer** component when it is attached to or detached from the main node tree and
when it is bound or unbound, using **onAttach**, **onDetach**, **onWillBind**, **onWillUnbind**, **onBind**, and **onUnbind**.
```ts
import { NodeController, BuilderNode, Size, FrameNode, UIContext } from '@kit.ArkUI';
class Params {
text: string = "this is a text"
}
@Builder
function buttonBuilder(params: Params) {
Column() {
Button(params.text)
.fontSize(20)
.borderRadius(8)
.borderWidth(2)
.backgroundColor(Color.Grey)
}
}
class MyNodeController extends NodeController {
private buttonNode: BuilderNode<[Params]> | null = null;
private wrapBuilder: WrappedBuilder<[Params]> = wrapBuilder(buttonBuilder);
makeNode(uiContext: UIContext): FrameNode {
if (this.buttonNode == null) {
this.buttonNode = new BuilderNode(uiContext);
this.buttonNode.build(this.wrapBuilder, { text: "This is a Button" })
}
return this.buttonNode!.getFrameNode()!;
}
onAttach(): void {
console.log("myButton on attach");
}
onDetach(): void {
console.log("myButton on detach");
}
onWillBind(containerId: number): void{
console.log("myButton on WillBind" + containerId);
}
onWillUnbind(containerId: number): void{
console.log("myButton on WillUnbind" + containerId);
}
onBind(containerId: number): void {
console.log("myButton on bind: " + containerId);
}
onUnbind(containerId: number): void {
console.log("myButton on unbind: " + containerId);
}
}
@Entry
@Component
struct Index {
@State buttonShow: boolean = true
@State buttonIndex: number = 0
private buttonController: MyNodeController = new MyNodeController();
private buttonNull: null = null;
private buttonControllerArray: Array < MyNodeController | null > = [this.buttonController,this.buttonNull]
build() {
Column() {
Row(){
Button("Bind/Unbind")
.onClick(() => {
this.buttonIndex++;
}).margin(5)
Button("onAttach/onDetach")
.onClick(() => {
this.buttonShow = !this.buttonShow
}).margin(5)
}
if(this.buttonShow){
NodeContainer(this.buttonControllerArray[this.buttonIndex % this.buttonControllerArray.length])
}
}
.padding({ left: 35, right: 35})
.width("100%")
.height("100%")
}
}
```
