[comment]: # aside:2

[comment]: # ({49595c0a-680e771f})
# Apresentação

Esta página descreve os componentes que podem ser usados para criar uma visualização de apresentação do widget.
A visualização de apresentação do widget é a parte do widget que recebe os dados de acordo com sua [configuração](/configuration) e os exibe no dashboard em um contêiner.

A visualização de apresentação consiste em três partes:

-   [Ação do widget](#widget-action)
-   [Visualização do widget](#widget-view)
-   [JavaScript](#javascript)

[comment]: # ({/49595c0a-680e771f})

[comment]: # ({12d91455-59d8ff17})
### Ação do widget

A classe de ação do widget (*WidgetView*) contém métodos para operações com widgets no modo de visualização de apresentação.
A maioria das ações de widget usa e/ou estende a classe de controlador padrão *CControllerDashboardWidgetView*.

A classe de ação do widget deve estar localizada no diretório *actions* e especificada no parâmetro [*actions*](/devel/modules/file_structure/manifest#actions) (*actions/widget.{id}.view/class*) no arquivo *manifest.json*.

**Exemplo de actions/WidgetView.php (implementado no widget nativo do Zabbix [*Informações do sistema*](/manual/web_interface/frontend_sections/dashboards/widgets/system))**

```php
class WidgetView extends CControllerDashboardWidgetView {

    protected function doAction(): void {
        $this->setResponse(new CControllerResponseData([
            'name' => $this->getInput('name', $this->widget->getDefaultName()),
            'system_info' => CSystemInfoHelper::getData(),
            'info_type' => $this->fields_values['info_type'],
            'user_type' => CWebUser::getType(),
            'user' => [
                'debug_mode' => $this->getDebugMode()
            ]
        ]));
    }
}
```

[comment]: # ({/12d91455-59d8ff17})

[comment]: # ({c06252a9-962bf489})
### Visualização do widget

A classe de visualização do widget (*CWidgetView*) é responsável por construir a visualização de apresentação do widget.

A classe de visualização do widget deve estar localizada no diretório *views*.
Se o arquivo que contém a classe de visualização do widget tiver um nome diferente do padrão (*widget.view.php*), ele deverá ser especificado no parâmetro [*actions*](/devel/modules/file_structure/manifest#actions) do arquivo *manifest.json* (*actions/widget.{id}.view/view*).

**Exemplo de views/widget.view.php**

```php
<?php

/**
 * Minha visualização de widget personalizada.
 *
 * @var CView $this
 * @var array $data
 */

(new CWidgetView($data))
    ->addItem(
        new CTag('h1', true, $data['name'])
    )
    ->show();
```

[comment]: # ({/c06252a9-962bf489})

[comment]: # ({f4f943a3-9c902f1e})
### JavaScript

A classe JavaScript é responsável por determinar o comportamento do widget, como atualização dos dados do widget, redimensionamento do widget, exibição de elementos do widget, etc.

Todas as operações JavaScript utilizam e/ou estendem a classe base JavaScript de todos os widgets do dashboard - *CWidget*.
A classe *CWidget* contém um conjunto de métodos com a implementação padrão para o comportamento do widget.
Dependendo da complexidade do widget, esses métodos podem ser utilizados como estão ou estendidos.

A classe *CWidget* contém os seguintes métodos:

-   Métodos que definem o ciclo de vida do widget: *onInitialize()*, *onStart()*, *onActivate()*, *onDeactivate()*, *onDestroy()*, *onEdit()*.
-   Métodos que lidam com a atualização e exibição dos dados do widget: *promiseUpdate()*, *getUpdateRequestData()*, *processUpdateResponse(response)*, *processUpdateErrorResponse(error)*, *setContents(response)*.
-   Métodos que modificam a aparência do widget: *onResize()*, *hasPadding()*.

A classe JavaScript deve estar localizada no diretório *assets/js* e especificada no parâmetro [*assets*](/devel/modules/file_structure/manifest#assets) (*assets/js*) no arquivo *manifest.json*.

[comment]: # ({/f4f943a3-9c902f1e})

[comment]: # ({83b2097c-be08c6bd})
##### Métodos do ciclo de vida

Os métodos do ciclo de vida do widget são invocados pelo dashboard, e em diferentes estágios do ciclo de vida do widget durante sua existência dentro do dashboard.

[comment]: # ({/83b2097c-be08c6bd})

[comment]: # ({af2ec67e-bbc2c368})
O método ***onInitialize()*** define o estado inicial e/ou valores do widget, sem realizar qualquer manipulação de HTML ou dados.
Este método é invocado quando um widget é criado (um objeto widget é instanciado), normalmente ao adicionar o widget a uma página de dashboard ou ao carregar a página do dashboard.

Exemplo:

```js
onInitialize() {
    this._time_offset = 0;
    this._interval_id = null;
    this._clock_type = CWidgetClock.TYPE_ANALOG;
    this._time_zone = null;
    this._show_seconds = true;
    this._time_format = 0;
    this._tzone_format = 0;
    this._show = [];
    this._has_contents = false;
    this._is_enabled = true;
}
```

[comment]: # ({/af2ec67e-bbc2c368})

[comment]: # ({d89d02f3-9d16c8d2})
O método ***onStart()*** define a estrutura HTML do widget, sem realizar qualquer manipulação de dados.
Este método é invocado antes da primeira ativação da página do dashboard, ou seja, antes que o dashboard e seus widgets sejam totalmente exibidos ao usuário.

Exemplo:

```js
onStart() {
    this._events.resize = () => {
        const padding = 25;
        const header_height = this._view_mode === ZBX_WIDGET_VIEW_MODE_HIDDEN_HEADER
            ? 0
            : this._header.offsetHeight;

        this._target.style.setProperty(
            '--content-height',
            `${this._cell_height * this._pos.height - padding * 2 - header_height}px`
        );
    }
}
```

[comment]: # ({/d89d02f3-9d16c8d2})

[comment]: # ({02fa6174-eb9b91db})
O método ***onActivate()*** torna o widget ativo e interativo, habilitando ouvintes de eventos personalizados (para responder às ações do usuário) e iniciando o ciclo de atualização do widget (para manter seu conteúdo atualizado).
Este método é invocado quando a página do dashboard é ativada, ou seja, quando ela é totalmente exibida na interface do usuário.

Observe que antes do método *onActivate()* ser invocado, o widget está no estado inativo (`WIDGET_STATE_INACTIVE`).
Após a invocação bem-sucedida, o widget transita para o estado ativo (`WIDGET_STATE_ACTIVE`).
No estado ativo, o widget é responsivo, escuta eventos, atualiza seu conteúdo periodicamente e pode interagir com outros widgets.

Exemplo:

```js
onActivate() {
    this._startClock();

    this._resize_observer = new ResizeObserver(this._events.resize);
    this._resize_observer.observe(this._target);
}
```

[comment]: # ({/02fa6174-eb9b91db})

[comment]: # ({4464acae-1b9abef7})
O método ***onDeactivate()*** interrompe qualquer atividade e interatividade do widget, desativando ouvintes de eventos personalizados e interrompendo o ciclo de atualização do widget.
Este método é invocado quando a página do dashboard é desativada, ou seja, alternada ou excluída, ou quando o widget é excluído da página do dashboard.

Observe que antes do método *onDeactivate()* ser invocado, o widget está no estado ativo (`WIDGET_STATE_ACTIVE`).
Após a invocação bem-sucedida, o widget transita para o estado inativo (`WIDGET_STATE_INACTIVE`).

Exemplo:

```js
onDeactivate() {
    this._stopClock();
    this._resize_observer.disconnect();
}
```

[comment]: # ({/4464acae-1b9abef7})

[comment]: # ({a26add25-06e3db00})
O método ***onDestroy()*** executa tarefas de limpeza antes que o widget seja excluído do dashboard,
o que pode incluir fechar uma conexão de banco de dados que foi estabelecida durante a inicialização do widget,
limpar dados temporários para liberar a memória do sistema e evitar vazamentos de recursos,
cancelar o registro de listeners de eventos relacionados a eventos de redimensionamento ou cliques de botões para evitar o tratamento desnecessário de eventos e vazamentos de memória, etc.
Este método é invocado quando o widget ou a página do dashboard que o contém é excluído.

Observe que antes que o método *onDestroy()* seja invocado, um widget em estado ativo (`WIDGET_STATE_ACTIVE`) é sempre desativado com a invocação do método *onDeactivate()*.

Exemplo:

```js
onDestroy() {
    if (this._filter_widget) {
        this._filter_widget.off(CWidgetMap.WIDGET_NAVTREE_EVENT_MARK, this._events.mark);
        this._filter_widget.off(CWidgetMap.WIDGET_NAVTREE_EVENT_SELECT, this._events.select);
    }
}
```

[comment]: # ({/a26add25-06e3db00})

[comment]: # ({2a2b0a8f-5e5aaf59})
O método ***onEdit()*** define a aparência e o comportamento do widget quando o dashboard entra no modo de edição.
Este método é invocado quando o dashboard entra no modo de edição, normalmente quando um usuário interage com o botão *Editar* do widget ou com o botão *Editar dashboard* do dashboard.

Exemplo:

```js
onEdit() {
    this._deactivateGraph();
}
```

[comment]: # ({/2a2b0a8f-5e5aaf59})

[comment]: # ({1e54f2e8-87f28aae})
##### Métodos do processo de atualização

Os métodos do processo de atualização do widget são responsáveis por recuperar dados atualizados do Zabbix server ou de qualquer outra fonte de dados e exibi-los no widget.

[comment]: # ({/1e54f2e8-87f28aae})

[comment]: # ({fa94eb63-c743ab46})
O método ***promiseUpdate()*** inicia o processo de atualização de dados recuperando dados, normalmente usando requisições web ou chamadas de API.
Este método é invocado quando uma página de dashboard é exibida e periodicamente depois disso, até que a página do dashboard seja trocada para outra página de dashboard.

A seguir está um exemplo da implementação padrão do método *promiseUpdate()* usado pela maioria dos widgets nativos do Zabbix.
Na implementação padrão, o método *promiseUpdate()* segue um padrão geral para recuperar dados do server.
Ele cria um novo objeto `Curl` com a URL apropriada e parâmetros de requisição,
envia uma requisição `POST` usando o método *fetch()* com o objeto de dados construído pelo método *getUpdateRequestData()*,
e processa a resposta (ou uma resposta de erro) com *processUpdateResponse(response)* ou *processUpdateErrorResponse(error)*, respectivamente.
Esta implementação é adequada para a maioria dos widgets, pois normalmente recuperam dados em formato JSON e os tratam de maneira consistente.

```js
promiseUpdate() {
    const curl = new Curl('zabbix.php');

    curl.setArgument('action', `widget.${this._type}.view`);

    return fetch(curl.getUrl(), {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify(this.getUpdateRequestData()),
        signal: this._update_abort_controller.signal
    })
        .then((response) => response.json())
        .then((response) => {
            if ('error' in response) {
                this.processUpdateErrorResponse(response.error);

                return;
            }

            this.processUpdateResponse(response);
        });
    }
```

[comment]: # ({/fa94eb63-c743ab46})

[comment]: # ({5d0423d9-5b7f40bf})
O método ***getUpdateRequestData()*** prepara os dados da solicitação ao server para atualizar o widget, reunindo várias propriedades e seus respectivos valores (identificadores do widget, configurações de filtro, intervalos de tempo, etc.) do estado e da configuração do widget,
e construindo um objeto de dados que representa as informações necessárias a serem enviadas ao server na solicitação de atualização.
Este método é invocado apenas como parte do método padrão *promiseUpdate()*, ou seja, durante o processo de atualização do widget.

Implementação padrão:

```js
getUpdateRequestData() {
    return {
        templateid: this._dashboard.templateid ?? undefined,
        dashboardid: this._dashboard.dashboardid ?? undefined,
        widgetid: this._widgetid ?? undefined,
        name: this._name !== '' ? this._name : undefined,
        fields: Object.keys(this._fields).length > 0 ? this._fields : undefined,
        view_mode: this._view_mode,
        edit_mode: this._is_edit_mode ? 1 : 0,
        dynamic_hostid: this._dashboard.templateid !== null || this.supportsDynamicHosts()
            ? (this._dynamic_hostid ?? undefined)
            : undefined,
        ...this._contents_size
    };
}
```

[comment]: # ({/5d0423d9-5b7f40bf})

[comment]: # ({980ceee3-dd2550e1})
O método ***processUpdateResponse(response)*** lida com a resposta recebida do server após a solicitação de atualização e, se o processo de atualização foi bem-sucedido e sem erros, limpa os dados do widget e exibe novos conteúdos com o método *setContents()*. Este método é invocado apenas como parte do método padrão *promiseUpdate()*, ou seja, durante o processo de atualização do widget.

Implementação padrão:

```js
processUpdateResponse(response) {
    this._setHeaderName(response.name);

    this._updateMessages(response.messages);
    this._updateInfo(response.info);
    this._updateDebug(response.debug);

    this.setContents(response);
}
```

[comment]: # ({/980ceee3-dd2550e1})

[comment]: # ({d3ce9166-2abd3964})
O método ***processUpdateErrorResponse(error)*** trata a resposta recebida do server após a solicitação de atualização se a resposta for um erro, e exibe a(s) mensagem(ns) de erro.
Este método é invocado apenas como parte do método padrão *promiseUpdate()*, ou seja, durante o processo de atualização do widget.

Implementação padrão:

```js
processUpdateErrorResponse(error) {
    this._updateMessages(error.messages, error.title);
}
```

[comment]: # ({/d3ce9166-2abd3964})

[comment]: # ({31ffc8a7-8ea0452d})
O método ***setContents(response)*** exibe o conteúdo do widget se o processo de atualização do widget foi bem-sucedido e sem erros,
o que pode incluir manipulação de elementos DOM, atualização de componentes da interface do usuário, aplicação de estilos ou formatação, etc.
Este método é invocado apenas como parte do método padrão *processUpdateResponse(response)*, ou seja, durante o processo de tratamento da resposta recebida do server após a solicitação de atualização.

Implementação padrão:

```js
setContents(response) {
    this._body.innerHTML = response.body ?? '';
}
```

[comment]: # ({/31ffc8a7-8ea0452d})

[comment]: # ({7b8ba0e6-95f750ef})
##### Métodos de modificação de apresentação

Os métodos de modificação de apresentação do widget são responsáveis por modificar a aparência do widget.

[comment]: # ({/7b8ba0e6-95f750ef})

[comment]: # ({5e245dd6-b5613994})
O método ***onResize()*** é responsável por ajustar os elementos visuais do widget para acomodar o novo tamanho do widget,
o que pode incluir o rearranjo de elementos, ajuste das dimensões dos elementos, truncamento de texto, implementação de carregamento preguiçoso para melhorar a responsividade durante o redimensionamento, etc.
Este método é invocado quando o widget é redimensionado, por exemplo, quando o usuário redimensiona manualmente o widget ou quando a janela do navegador é redimensionada.

Exemplo:

```js
onResize() {
    if (this.getState() === WIDGET_STATE_ACTIVE) {
        this._startUpdating();
    }
}
```

[comment]: # ({/5e245dd6-b5613994})

[comment]: # ({d22bedba-88b32413})
O método ***hasPadding()*** é responsável por aplicar um padding vertical de 8px na parte inferior do widget quando ele está configurado para [exibir seu cabeçalho](/manual/web_interface/frontend_sections/dashboards/widgets#common-parameters).
Este método é invocado quando a página do dashboard é ativada, ou seja, quando ela se torna a página exibida na interface do usuário.

Implementação padrão:

```js
hasPadding() {
    return this.getViewMode() !== ZBX_WIDGET_VIEW_MODE_HIDDEN_HEADER;
}
```

Para alguns widgets, é necessário usar todo o espaço disponível do widget para configurar, por exemplo, uma cor de fundo personalizada.
A seguir, um exemplo da implementação do método *hasPadding()* utilizado no widget nativo do Zabbix [*Valor do item*](/manual/web_interface/frontend_sections/dashboards/widgets/item_value).

```js
hasPadding() {
    return false;
}
```

[comment]: # ({/d22bedba-88b32413})
