vst-gridform
v6.2.0-beta.1
Published
A biblioteca vst-gridform digamos que é um syntax-sugar, ou mais específico, uma biblioteca que ajuda na implementação de um CRUD usando o devextreme. Esta biblioteca é completamente dependente do devextreme, assim não tendo direitos nenhum. Muito pelo co
Downloads
27
Readme
vst-gridform. O que é?
A biblioteca vst-gridform digamos que é um syntax-sugar, ou mais específico, uma biblioteca que ajuda na implementação de um CRUD usando o devextreme. Esta biblioteca é completamente dependente do devextreme, assim não tendo direitos nenhum. Muito pelo contrário, essa biblioteca tem única intenção de ajudar o programador a desenvolver certos códigos de forma mais rápida e mais amigável, utilizando a checagem estática que o typescript fornece.
Disclaimer
A idéia foi para me ajudar a desenvolver projetos mais elaborados mais rapidamente.
A única licença para essa biblioteca é a do DevExtreme. Para usar o devextreme em projetos privados, por favor, pague a licença necessária (não é barato, mas vale a pena).
ATENÇÃO!! USE POR SUA CONTA E RISCO!!!
Dependencias
- Angular 12 ou 13
- DevExtreme 21
Por que?
Usar o devextreme no angular segue uma linha diferente ao de como o devextreme foi inicialmente proposto, com o uso em paralelo com o jQuery.
Para usar com o angular, apesar de muito bom, foi necessário ligar-se ao HTML, como porta de entrada dos parametros e funções. Funciona muito bem, porém em algumas situações o desenvolvedor perde o monitoramente de erros estáticos que os arquivos em typescript fornecem. Os seguintes componentes datagrid e form oferecem muitas opções de configurações em uma camada mais profunda que a checagem de tipo no HTML consegue monitorar.
Só foi escrito o datagrid e form de maneira schematica, pois são os mais usados com comportamentos padrões, de uma tela pra outra.
O desenvolvedor pode muito bem usar o @ViewChild do angular, e usar o lint do ts. Porém, o segundo motivo é: Funcionalidades adicionais. Existe funcionalidades que é necessário em toda dela de crud (ou comportamento), e não existe implementação no devextreme, por ser algo muito específico com o tipo de desenvolvimento.
E o último motivo, mas o principal é: COMPONENTES CUSTOMIZADOS E FORMULARIO COMPLETO NA DATAGRID.
A datagrid do devextreme abre um formulário muito limitado, e fica a cargo do desenvolvedor criar um formulário mais elaborado e ter que gerenciar tanto o formulário quando a datagrid. O novo modelo, a própria datagrid gerencia o formulário que pode receber N customizações possíveis, que podem ser modulares, estando em múltiplos projetos.
Como funciona
Essa biblioteca segue o padrão composition
(mais conhecida no java). Que diz o seguinte:
The composition is a design technique in which your class can have an instance of another class as a field of your class. - Fonte: Google
A herança de componentes não funciona muito bem no angular, pois não herda a parte visual, somente o código escrito do js.
Então segue a documentação dos dois componentes:
O DxDataGridComponent
equivale a VsGridComponent
, e o seletor dx-data-grid
equivale a vs-grid
. Equivale pois tanto o component quando o seletor do componente datagrid original ainda pode ser usado normalmente, o vs-grid
é só uma camada, ele não reescreve o comportamente original. E o mesmo vale para o form, que tem as equivalências DxFormComponent
para VsFormComponent
, e dx-form
para vs-form
.
DOCS
FORMULÁRIO
O básico, import { VsFormModule } from 'vst-gridform'
.
O component VsForm recebe apenas 6 entradas:
- hasSubmit: boolean
- formOperation: "create" | "read" | "update"
- data: T
- keys: any
- schema: VsFormSchema
- format: 'readonly' | 'edit'
e possui 5 saídas:
- dataChange: EventEmitter
- keysChange: EventEmitter
- onValueChanged: EventEmitter
- formatChange: EventEmitter
- onEvent: EventEmitter
@Input() hasSubmit: boolean; (Default: false)
O hasSubmit
é responsável por colocar as tags form ao redor do vs-form, e internamente todo submit event é encaminhado a uma função que é necessário ser escrito no schema
Exemplo:
<vs-form ... [hasSubmit]="true"></vs-form>
@Input() formOperation: "create" | "read" | "update"; (Default: undefined)
O formOperation
é apenas um valor que a grid passa ao formulário quando está em alguma operação informada. Por exemplo, se o usuário aperta no botão mais na grid, então a grid renderiza o formulário e seta a variável formOperation
do formulário que ela está cuidando como "create"
, assim, para algumas funcionalidades dentro do schema, esse formOperation
é passado, e o desenvolvedor pode ou não deixar alguns campos visíveis.
@Input() data: T; (Default: undefined)
O data
é o armazenamento onde o formulário insere os valores dos editores, e onde os editores fazem a leitura para renderizarem o conteúdo.
Exemplo:
<vs-form ... [data]="myFormData"></vs-form>
@Input() keys: any; (Default: undefined)
O keys
é a chave do data que está sendo renderizado. Usado mais pelo datagrid quando em submit do handler do schema.
@Input() format: CustomTemplateFormat; (Default: 'edit')
O format
informa ao formulário como ele deve ser renderizado, se normal, quando "edit"
, ou se em modo leitura, quando format é igual a "readonly"
.
@Output() dataChange: EventEmitter;
Emite um sinal quando o data
é alterado.
@Output() keysChange: EventEmitter;
Emite um sinal quando o keys
é alterado.
@Output() onValueChanged: EventEmitter;
Emite um sinal quando qualquer editor realiza uma alteração no data
.
@Output() formatChange: EventEmitter;
Emite um sinal quando o format é alterado.
@Output() onEvent: EventEmitter;
Documentação aqui
VsFormSchema
O schema
é a parte mais importante do <vs-form ... [schema]="schema"></vs-form>
, é o responsável por levar as instruções iniciais para o formulário se renderizar, e também regula o comportamento.
Em sua maioria é composta por instruções e parametros definidos no DxForm, logo a maior parte da documentação do vsSchema é proprío da documentação original.
Porém, para as customizações realizadas no VsForm, adiante está maiores detalhes sobre o schema.
id: number | string;
É um identificador de formulário. Não tem utilidades.
handler: VsFormHandler;
Handler é uma interface. Algumas dessas implementações só funcionam se hasSubmit
for igual a true
.
interface VsFormHandler {
onAppearing?: (e: VsOnAppearing) => void;
onAppeared?: (e: VsOnAppeared) => void;
onSubmiting?: (e: VsOnSubmiting) => any;
onSubmited?: (e: VsOnSubmited) => any;
toolbar?: VsFormToolbar;
toolbarTop?: VsFormToolbar;
cloneToolbarOnTop?: boolean;
cancelButton?: VsFormButton;
saveButton?: VsFormButton;
backButton?: VsFormButton;
showSubmitErrorSummary?: boolean;
}
| CAMPO | DESCRIÇÃO |
|---------|-------------|
| onAppearing
| É um evento que é disparado quando o formulário se torna visível, muito usado pelo datagrid, que gerencia o formulário. Ele é chamado depois do onInitialized (método do devextreme). O onAppearing
recebe um objeto com informações do dado, component e instancia do VsFormComponent
. Se quiser alterar, ou editar alguma informação dos dados pode ser aqui, usando o data
, que a alteração é enviado para o formulário |
| onAppeared
| É um evento disparado após o formulário aparecer. Muito parecido com o onAppearing
|
| onSubmiting
| É chamado quando hasSubmit==true
. Recebe um objeto do tipo VsOnSubmiting
que refere as chaves de alguma atualização no campo keys
. Referencia os dados do formulário. Pode cancelar o envio de dados da datagrid com o cancel
. Ele retorna um objeto dos dados enviados, ou um Promise
do tipo resultado da operação. |
| onSubmited
| É chamado quando hasSubmit==true
. Recebe um objeto do tipo VsOnSubmited
que refere keys e data parecido com o onSubmiting
. Refere ao campo response
que é o resultado do retorno do onSubmited
. E refere ao campo goToGrid
que bloqueia o retorno para a datagrid, se o formulário for gerenciado pela datagrid |
| toolbar
| É usado quando hasSubmit==true
. É o toolbar que será incluido os botões configurados em backButton
, cancelButton
, saveButton
|
| toolbarTop
| Não funciona. É usado quando hasSubmit==true
. Ainda tem que terminar a implementaçao. Mas seria um toolbar no topo do formulário também, igual como no bottom. |
| cloneToolbarOnTop
| Não funciona. É usado quando hasSubmit==true
. Seria pra copiar o toolbar no bottom no topo do formulário. Ainda é necessário implementação. |
| cancelButton
| É usado quando hasSubmit==true
. É aplicado quando o format
do formulário for igual a "edit"
, e também tiver enabled.|
| saveButton
| É usado quando hasSubmit==true
. É aplicado quando o format
do formulário for igual a "edit"
, e também tiver enabled.|
| backButton
| É usado quando hasSubmit==true
. É aplicado quando o format
do formulário for igual a "readonly"
, e também tiver enabled. |
| showSubmitErrorSummary
| É usado quando hasSubmit==true
. Mostra o erro de submir no summario do devextreme. Mais fácil do que fazer widget de erro de submit para formulário. |
Obs.: Os Botões tem:
- confirmClick: boolean;
- confirmMsg: string;
São responsáveis de confirmar ao usuário se ele tem certeza da operação. (Botões cancelButton, saveButton e cancelButton no Handler)
items: VsFormItems;
Novamente, é igual ao devextreme, só tem algumas adições para facilitar o desenvolvimento interno de algumas funcionalidades. Segue as customizações:
Todos os tipos de items tem o atributo name
e dynamicOptions
que logo será abordado.
Para o itemType
igual a simple
, o editorType
tem uma nova opção, que é "vsCustomComponent"
, com isso o VsFormComponent
liga os eventos e valores do dataField com o valor implementado no template. Leia mais em Componentes Customizados.
transform: VsTransform;
Ele aplica uma transformação no campo, e aplica css no html. // TODO: melhorar documentação
formClass: string;
Bota css na tag html.
savePartial
O savePartial
é interessante. Ele salva no browser a atividade de preenchimento do formulário do usuário, se a internet cair, ou der erro, em vez do usuário perder o preenchimento que ele fez, a proxima vez que o formulário for aberto uma mensagem de recuperação de formulário entra como popup, se ele quiser todos os dados que o usuário pensou que perderia volta e o formulário é automaticamente preenchido.
O problema que para formulários grandes pode dar uma travada ou outra, mas nada fora do comum.
| CAMPO | DESCRIÇÃO |
|-------|-----------|
| active: boolean
| Ativa ou desativa a funcionalidade. Default: false
|
| saveas: string
| Obrigatório. Nome para salvar o formulário no cache |
| loadMode?: VsPartialLoadMode
| Tipo de leitura, pode ser ask
ou always
. Caso seja o primeiro, é aberto um popup para perguntar ao usuário se ele quer recuperar os dados. O segundo ele sempre vai recuperar, e preencher automaticamente. Default: "ask"
|
| onOperation?: "insert"
| Tipo de operação do formulário para que essa funcionarlidade funcione. Default: "insert"
|
| askMessage?: string
| Mensagem para perguntar se gostaria de recuperar os dados. Default: "Observamos que a última inclusão não foi salva. Deseja recuperar os dados?"
|
| delay?: number
| Tempo de delay para salvar os dados. Default: 400
|
COMPONENTES CUSTOMIZADOS
Chamamos de Componente Customizado o componente que pode entrar em um editorType: "vsCustomComponent"
de um formulário. O componente tem que extender a classe abstrata e genérica VsCustomTemplateComponent<T>
, sendo T
o tipo do valor que seu componente assume, podendo ser um void, string, array, como até um objeto com formulário próprio.
Para instanciar um componente customizado no devextreme é necessário chamar o serviço de "ligação de nós". O VsTieCustomComponents
é um serviço fornecido em root pelo vst-template. Nele existe dois métodos que devem ser usados nos atributos template dos items do devextreme.
Segue exemplo:
Implementando a classe customizada:
// FILE: endereco.component.ts
// Digamos que a classe seguinte é um componente customizado
@Component({
...
})
export class EnderecoComponent extends VsCustomComponent<Endereco> {
////////
/// ...
/// LOGICA
/// ...
///////
alterarEndereco(address) {
// para alterar o valor e informar a árvore do devextreme. Basta fazer o seguinte:
this.value = address;
}
// Esse método é usado para converter o valor iniciado pelo tiecomponentservice
setValue(v: any) {
if (typeof v !== "object") v = new Endereco(); // Inicializa endereço se por acaso não existe
super.setValue(v); // Volta a inicializar normalmente o pai
}
}
Usando a classe customizada:
// FILE: usuario.component.ts
// A CLASSE SEGUINTE EH UM CADASTRO DE USUARIO
@Component({
...
})
export class PerfilUsuarioComponent {
// Segue com a definição de schema
schema: VsFormSchema = {
items: [
{ dataField: "name", label: {text: "Nome"}, ...},
{ dataField: "email", label: {text: "Email"}, ...},
{ dataField: "password", label: {text: "Senha"}, ...},
// Agora queremos pedir o endereço do usuário
{ dataField: "address", label: {text: "Endereço"}, editorType: "vsCustomComponent", template: this.tie.onForm(EnderecoComponent) },
// Pronto, o formulário desenvolvido dentro do componente endereço agora obedece ao formulário Perfil de Usuário
]
}
// Eh necessário pedir o servico de amarração
constructor(private tie: VsTieCustomComponents) {}
}
Mais opções podem ser usada quando for usar this.tie.onForm
, pois o método onForm recebe 3 entradas, primeiro a classe do componente, depois os inputs caso seja necessário usar o editorOptions
, e também um callback que é chamado quando a classe está instanciada.
Exemplo2:
Usando a classe customizada:
// FILE: usuario.component.ts
// A CLASSE SEGUINTE EH UM CADASTRO DE USUARIO
@Component({
...
})
export class PerfilUsuarioComponent {
// Segue com a definição de schema
schema: VsFormSchema = {
items: [
...
// Agora queremos pedir o endereço do usuário.
// Porem, quero inserir uma imagem no componente do endereço.
// E o endereço pode ficar desabilitado enquanto o usuário ainda não digitou nem email e senha.
// O endereço tem um evento que ativa quando o usuário clica
{ dataField: "address", label: {text: "Endereço"},
editorType: "vsCustomComponent",
template: this.tie.onForm(EnderecoComponent, ["disabled", "imageSrc"], (instance) => {
instance.someEvent.subscribe((e: any) => {
// DO SOMETHING
});
}),
editorOptions: {
imageSrc: "/assets/nome-da-imagem.jpg",
},
dynamicOptions: [{
toSet: "editorOptions.disabled",
value: (e) => (e.data.email && e.data.password)
}]
},
// Pronto, o formulário desenvolvido dentro do componente endereço agora obedece ao formulário Perfil de Usuário
]
}
// Eh necessário pedir o servico de amarração
constructor(private tie: VsTieCustomComponents) {}
}
Existe também o método onTemplate
, que insere um componente em qualquer área que tem o atributo template
do devextreme.
// todo: doc do onTemplate
GRADE
O básico, import { VsGridModule } from 'vst-gridform'
.
O component VsFormComponent recebe apenas 4 components:
- format: CustomTemplateFormat
- templates: Array
- useCssHiden: boolean = false
- schema: VsGridSchema
e possui 3 saídas:
- onEvent: EventEmitter
- onFormEvent: EventEmitter
- formatChange: EventEmitter
@Input() useCssHiden: boolean; (Default: false)
Se true
insere o formulário no DOM, e gerencia usando CSS para esconder e aparecer. Caso contrário, o funcionamento padrão, trabalha com o formulário na memória.
Usando useCssHiden pode demorar mais pra abrir a grid pela primeira vez, porém o formulário fica mais rápido.
@Input() format: CustomTemplateFormat; (Default: 'edit')
Como o datagrid deve ser renderizado.
@Input() templates: Array;
Templates customizados. É complicado dessa maneita. Recomendo usar o Customtemplate.
@Input('schema') schema: VsGridSchema;
Logo abaixo terá a definição do schema.
@Output() onEvent: EventEmitter;
Documentação aqui
@Output() onFormEvent: EventEmitter;
Entrega eventos que acontecem no formulário interno. Mesma definição do onEvent dentro do formulário acima.
@Output() formatChange: EventEmitter;
Emite um sinal quando o format é alterado.
VsGridSchema
O schema
é a parte mais importante do <vs-grid ... [schema]="schema"></vs-grid>
, é o responsável por levar as instruções iniciais para a datagrid se renderizar, e também regula o comportamento. Em sua maioria é composta por instruções e parametros definidos no DxDataGrid, logo a maior parte da documentação do VsGridSchema é proprío da documentação original.
O VsGrid tem muito menos customização que o VsForm. São apenas 3 customizações:
allowRefresh?: boolean;
Insere um botão na toolbar do datagrid. E esse botão permite ao usuário fazer refresh dos dados da tabela.
transform?: VsTransform;
Mesmo que o transform do formulário. Só que usa a transformação antes de enviar os dados para o datasurce.
gridClass?: string;
Uma classe CSS para a grade.
auxiliarDetail?: Array;
Lista de detalhes auxiliares. Para usar mais de um master details.
// toto: doc
auxiliarDetailStyle?: "tabs" | "rows" | "columns"; (Default: "rows")
Tipo de estilo em que os detalhes serão renderizados
columns[n].mask
Adição de máscara para o campo ficar visualmente melhor na datagrid.
DOC onEvent
@Output() onEvent: EventEmitter;
Emite sinais nas seguintes fases:
| ENUM | DESCRIÇÃO |
|------|-----------|
| VsWidgetEvent.beforeInit
| Dispara junto ao ngOnInit
do Angular e antes do onInitialized
do Devextreme. Porém esse Evento dispara antes das inicializações e configurações internas do VsWidget |
| VsWidgetEvent.onInit
| Dispara junto ao ngOnInit
do Angular e antes do onInitialized
do Devextreme. Porém esse Evento dispara depois das inicializações e configurações internas do VsWidget |
| VsWidgetEvent.afterInit
| Dispara junto ao ngAfterViewInit
do Angular |
| VsWidgetEvent.onDestroy
| Dispara quando o componente entra em no processo de destruição pelo Angular |
| VsWidgetEvent.hide
| Quando o componente está se escondendo na tela. |
| VsWidgetEvent.show
| Quando o componente está aparecendo na tela. |