Grid

Guia de utilização do componente Grid do Web Framework.

A principal ferramenta de apresentação de dados do Web Framework é a grade. A seguir será explicado o básico sobre o desenvolvimento da grade. Para uma visão mais aprofundada, a documentação da API deve ser consultada.

Declaração da grade

Uma grade é construída no contexto de um processo. Assim, a forma mais comum de declarar uma grade é por meio do método grid da classe Process. Em arquivos .ip ou .il (processos e relatórios respectivamente), o objeto do processo corrente pode ser acessado por this. Dessa forma, a declaração de uma grade poderia ser:

const grid = this.grid('nome da grade');

ou

this.ds = classes.getCachedDataSet(-2090000000);
const grid = this.grid('exemplo', this.ds);

Este método de Process pode ser usado para criar uma grade ou acessar pelo nome a instância já criada de uma grade.

O terceiro e o quarto parâmetros são opcionais, sendo respectivamente a chave da classe que terá definição de campos da grade e o objeto da grade mestre (fazendo uma relação masterDetail). Para mais detalhes de como declarar uma grade no processo, ver a documentação de Process.grid .

Objetos da classe Grid também possuem uma série de propriedades que podem ser editadas para modificar o comportamento da grade, como por exemplo, definir se ela pode editar, inserir, apagar, exportar ou duplicar registros. Para mais detalhes dessas propriedades, ver a documentação de Grid .

Registro de eventos

Após declarar a grade, normalmente são registrados os eventos, caso necessário. Eventos geralmente são disparados durante a construção da grade, como na definição de campos, por exemplo, e também antes e depois de ações na grade, como remoção, inclusão, confirmação de edição etc.

No exemplo a seguir, um evento pré-remoção é registrado:

grid.on('beforeDelete', function (evt) {
  if (evt.grid.ds.num('iNumber') < 10) {
    throw new Error('Registros com valores abaixo de 10 não podem ser removidos.');
  }
});

Para mais detalhes sobre cada evento, ver a documentação de eventos da grade .

Definição dos campos

Para acessar ou definir o campo de uma grade, utiliza-se o método field da classe Grid. Com o objeto field, é possível ler e editar o dado do campo do registro corrente, ou modificar suas propriedades.

Exemplo:

const fld = grid.field('non_negative');
const value = fld.getValue();
if (value < 0) {
  fld.setValue(0);
}

Por vezes, a grade declarada precisa ter seus campos definidos ou modificados no momento de sua construção, seja por não possuírem uma definição de classe de onde pegar a definição dos campos, seja por precisarem ter uma customização específica para o processo.

Para isso, usa-se o evento defineFields.

grid.on('defineFields', function (evt) {
  let fld = evt.grid.field('field_1');
  fld.label = 'Field 1';
  fld.help = 'Ajuda do campo 1';
  fld.on('lookupDisplay', function (evt) {
    evt.displayValue = DBKey.from(evt.key).str('iName');
  });

  fld = evt.grid.field('field_2');
  fld.label = 'Field 2';
  fld.readonly = true;

  fld = evt.grid.field('field_3');
  fld.visible = false;
});

Como é possível notar pelo exemplo acima, os campos podem ter propriedades modificadas e eventos registrados. Para mais detalhes, ver a documentação de Field .

Registros

Algumas propriedades da grade que permitem lidar com os registros:

  • maxRecordCount: define o número máximo de registros a serem exibidos por página no modo tabela.
  • maxSelectedRecords: define o número máximo de registros que podem ser selecionados.
  • selectedRecords: guarda a lista de bookmarks dos registros selecionados em um array.
  • unselectableRecords: define por meio de um array de bookmarks quais os registros não podem ser selecionados.

Também é possível percorrer todos os registros e acessar os valores de seus campos por meio do dataset da grade, acessível pela propriedade ds. Em alguns casos, é recomendado que um clone desse dataset seja feito, para evitar modificar apresentação dos dados para o usuário. Por exemplo, quando for necessário percorrer os registros desse dataset, filtrá-lo ou modificar seus índices.

Para criar o clone do dataset, faça:

const clone = grid.ds.newSharedDataSet();

O método newSharedDataSet também admite um parâmetro com opções, como por exemplo ds.newSharedDataSet({ sharedDelta: true }) para que o dataset tenha o delta compartilhado. Para mais informações, acesse a documentação da API .

Largura da grade

Por padrão, a grade se ajusta à largura do seu conteúdo. A propriedade width permite informar uma largura para a grade, em pixels quando a unidade não for informada.

grid.width = 800;

O valor informado não é definitivo e funciona como uma largura mínima. A grade será mais larga que ele sempre que os seus campos ou a sua barra de título precisarem de mais espaço. A barra de botões não aumenta a largura da grade.

Botões

Uma grade pode conter botões que desempenham ações a serem definidas pelo desenvolvedor. Para declarar um botão, basta utilizar o método button da classe Grid. Esse método cria um botão ou acessa pelo nome a instância de um botão já criado.

Exemplo:

grid.button('Tornar maiúsculas', function (bt) {
  var grid = bt.parent;
  var ds = grid.ds;
  var selectedRecords = grid.selectedRecords;
  for (var i = 0; i < selectedRecords.length; ++i) {
    ds.bookmark = selectedRecords[i];
    ds.setField('NOME', ds.str('NOME').toUpperCase());
  }
});

O segundo parâmetro não precisa ser necessariamente uma função. Pode também ser o nome de uma atividade ou interação. Existem mais três parâmetros que definem, respectivamente, a ordem do botão, a chave do processo (para os casos em que o botão abre uma interação ou atividade em um processo diferente do atual) e se a interação ou atividade deverá ser aberta em nova aba.

Os botões visíveis da grade podem ser controlados pela propriedade visibleButtons, que é um array de objetos da classe Button ou de strings com os nomes dos botões.

Quando não for possível exibir todos os botões da grade, o sistema moverá automaticamente os botões que não puderam ser exibidos para um menu acessível a partir do botão “Mais”, criado dinamicamente pelo sistema. Por esse motivo, é recomendado que os botões sejam informados na ordem de prioridade.

Grupos de botões

Botões relacionados podem ser reunidos em um grupo, exibido na barra como um botão que abre um menu com os botões do grupo. O método buttonGroup cria o grupo a partir de botões já criados, ou retorna o grupo existente com o nome informado. O mesmo método existe no processo.

grid.button('Emitir NF-e').on('click', emitir);
grid.button('Imprimir DANFE').on('click', imprimir);

const fiscal = grid.buttonGroup('Fiscal', ['Emitir NF-e', 'Imprimir DANFE']);
fiscal.help = 'Operações fiscais do pedido.';

grid.visibleButtons = ['Aprovar', fiscal, 'Exportar'];

Na lista de visibleButtons, o grupo pode ser informado pela instância ou pelo nome.

O clique no grupo apenas abre o menu. Grupos e botões dividem o mesmo espaço de nomes, e visibleButtons, enabledButtons e as permissões também se aplicam aos grupos. Os botões continuam acessíveis por sua tecla de acesso, mesmo que estejam em um grupo.

Para mais informações do botão, acesse Grid.button e Button .

Botão “Duplicar registro” na grade

Devido a necessidade cada vez mais constante de se criar registros com base em outros, foi criado o botão “Duplicar registro” para todas as grades.

O comportamento

Por padrão o botão “Duplicar registro” irá duplicar todos os campos com exceção da grade e dos campo que possuam os nomes IKEY, CHAVE, IVERSION e VERSAO. Os campos de nome ICODE, CODIGO, INAME e TITULO serão duplicados por padrão com a adição do sufixo “+”.

Este comportamento pode ser alterado definindo a propriedade duplicateMode do campo. Esta propriedade pode receber os seguintes valores:

  • DuplicateMode.NONE: o valor do campo não será duplicado.
  • DuplicateMode.COPY: o valor do campo será duplicado integralmente, caso este campo seja uma grade os dados dela serão duplicados seguindo o comportamento padrão do botão.
  • DuplicateMode.COPY_ADDING_SUFFIX: o valor do campo será duplicado com a adição do sufixo “+”.

Alterando o comportamento

Suponhamos que queremos que uma grade detalhe tenha seus dados duplicados para um novo registro e que os items do seu campo “detailField” não recebam sufixo. Podemos fazer como no código abaixo:

Exemplo:

const DuplicateMode = require('@nginstack/web-framework/lib/classdef/DuplicateMode');
const CLASS_KEY = 12345;

const grid = this.grid('masterGrid', classes.getCachedDataSet(CLASS_KEY), CLASS_KEY);
grid.on('defineFields', function (evt) {
  const field = evt.grid.field('detailGrid');
  field.duplicateMode = DuplicateMode.COPY;
  field.grid.on('defineFields', function (evt) {
    evt.grid.field('detailField').duplicateMode = DuplicateMode.COPY;
  });
});

grid.write();

Alterando o comportamento via x-class

É possível informar que uma determinada classe não pode ter seus dados duplicados por padrão ara isso basta adicionar um x-class na classe desejada e definir a propriedade canDuplicate.

Exemplo: this.canDuplicate = false;

Os eventos

Há dois eventos que são executados a cada clique no botão “Duplicar registro” são eles:

  • beforeDuplicate: Executado antes de iniciar o processo de duplicação do registro;
  • afterDuplicate: Executado ao terminar o processo de duplicação do registro;
const DuplicateMode = require('@nginstack/web-framework/lib/classdef/DuplicateMode');
const CLASS_KEY = 12345;

const grid = this.grid('masterGrid', classes.getCachedDataSet(CLASS_KEY), CLASS_KEY);
grid.on('defineFields', function (evt) {
  const field = evt.grid.field('detailGrid');
  field.duplicateMode = DuplicateMode.COPY;
  field.grid.on('defineFields', function (evt) {
    evt.grid.field('detailField').duplicateMode = DuplicateMode.COPY;
  });
});

grid.on('beforeDuplicate', function (evt) {
  evt.grid.process.alert('Duplicando registros');
});

grid.on('afterDuplicate', function (evt) {
  evt.grid.process.alert('Registros duplicados com sucesso');
});
grid.write();

Botão “Mostrar/Ocultar” chaves na grade

Ao clicar no botão “Mostrar/Ocultar chaves” o comportamento visual do campo definido pelo desenvolvedor será sobreposto, permitindo ficar visível mesmo que tenha sido ocultado em um determinado modo de visão da grade.

Caso haja o desejo de não mostrar as chaves de uma determinada grade, foi criada a propriedade Grid. prototype.enableToggleKeyButton, esta permite desabilitar o botão.

Exemplo:

const CLASS_KEY = 12345;

const grid = this.grid('masterGrid', classes.getCachedDataSet(CLASS_KEY), CLASS_KEY);
grid.enableToggleKeyButton = false;
grid.write();