Pragiva — Tecnologia na prática

Validar e bloquear campo no MVC sem mexer no dicionário

Validar e bloquear campo no MVC com SetProperty, que reescreve em tempo de execução o que o dicionário diz. Travar no modelo não é travar na view.

Protheus Referência técnica 5 min de leitura

Assista o vídeo

Resposta rápida

O que muda
SetProperty reescreve, em tempo de execução, uma propriedade que a estrutura leu do dicionário — sem tocar no SX3.
Onde aplicar
na estrutura de MODELO (MODEL_FIELD_*) ou na de VIEW (MVC_VIEW_*) — nunca a mesma constante serve para os dois lados.
A armadilha central
bloquear no modelo com MODEL_FIELD_WHEN faz o SetValue do seu próprio código falhar em silêncio; bloquear na view com MVC_VIEW_CANCHANGE trava só quem digita.
Erro de digitação clássico
MVC_VIEW_ORDER não existe — a constante é MVC_VIEW_ORDEM, em português.
Onde a regra não alcança
o que está escrito no ModelDef de um MVC não vale para a rotina tradicional da mesma tabela, e o inverso também não.
Consulta rápida7 seções

FWFormStruct monta a estrutura de campos lendo o SX3 — é assim que o ModelDef sabe o tipo, o tamanho e a obrigatoriedade de cada campo sem uma linha escrita à mão. O problema aparece quando a rotina precisa de uma regra diferente daquela que está no dicionário: um campo opcional no cadastro padrão que precisa ser obrigatório nesta tela, uma validação que só faz sentido para este fluxo, um campo que só pode ser preenchido pelo código e nunca pelo usuário. Mexer no SX3 resolveria, mas vale para o sistema inteiro — e é exatamente o que não se quer. SetProperty resolve o problema certo: reescreve a propriedade só para a estrutura que esta rotina montou, na memória, sem gravar nada no dicionário. A mesma tabela pode ter regras diferentes em telas diferentes porque cada ModelDef chama FWFormStruct de novo e recebe um objeto próprio para mexer.

A forma real, observada no uso

Na prática, a chamada aparece assim — não há uma assinatura publicada, só o padrão que se repete em centenas de lugares:

ADVPL / TLPP
oStruct:SetProperty(cIdCampo, nPropriedade, xValor)

cIdCampo é o nome do campo ("A1_COD") ou o curinga "*", que aplica a propriedade a todos os campos da estrutura de uma vez. nPropriedade é uma das constantes de FWMVCDef.ch — de uma família se oStruct veio de FWFormStruct(1,...), de outra se veio de FWFormStruct(2,...). xValor é o novo valor: um lógico, um code-block, o que a propriedade esperar.

As constantes do lado do MODELO

São 14, de MODEL_FIELD_TITULO (1) a MODEL_FIELD_VIRTUAL (14). As cinco que aparecem no dia a dia de quem escreve regra fora do dicionário:

ConstanteValor
MODEL_FIELD_VALID7
MODEL_FIELD_WHEN8
MODEL_FIELD_OBRIGAT10
MODEL_FIELD_INIT11
MODEL_FIELD_NOUPD13

VALID e WHEN são as mais chamadas das cinco — validação e trava de digitação são a regra mais comum de se personalizar fora do dicionário. VALID troca o bloco de validação do campo. WHEN decide se o campo aceita digitação. OBRIGAT liga ou desliga a obrigatoriedade sem encostar no SX3. INIT troca o valor inicial. NOUPD bloqueia edição depois de gravado — diferente de WHEN, que bloqueia sempre.

As constantes do lado da VIEW

A família MVC_VIEW_* tem 17 posições, e estas são as que mais aparecem depois das estruturais:

ConstanteValor
MVC_VIEW_ORDEM2
MVC_VIEW_LOOKUP9
MVC_VIEW_CANCHANGE10

CANCHANGE é, de longe, a mais chamada das três — travar a edição pela view, sem mexer no modelo, decidindo se o campo aparece editável ou só para leitura na tela, é o caso mais comum desta seção inteira. LOOKUP liga ou desliga a lupa de consulta daquele campo específico.

O curinga que aplica a todos os campos

Quando a regra vale para a estrutura inteira, o primeiro argumento vira "*". Duas formas reais:

ADVPL / TLPP
oStruct:SetProperty("*", MODEL_FIELD_VALID, {|| lVldModel })
oStruct:SetProperty("*", MVC_VIEW_CANCHANGE, .F.)

A primeira troca a validação de todo campo da estrutura de modelo pelo mesmo bloco. A segunda bloqueia a edição da tela inteira de uma vez — útil na entidade que a rotina só exibe, como um SA1MASTER de cabeçalho.

A armadilha: bloquear no modelo não é o mesmo que bloquear na view

A distinção é esta: o modelo é o dado, e uma trava nele vale para qualquer caminho que passe por ali — tela, ExecAuto, evento. A view é a apresentação; uma trava nela impede o clique do usuário e não afeta o que o código faz no modelo por baixo. Antes de escrever SetValue contra um campo que talvez esteja bloqueado, há a saída defensiva: CanSetValue(cIdForm, cIdField) devolve se aquela gravação é permitida, e testar antes evita descobrir a trava pelo sintoma. Quando a gravação precisa acontecer de qualquer jeito, o modelo tem ForceValue. SetValue respeita a trava; ForceValue, não.

A mensagem de erro sai por SetErrorMessage, nunca por MsgAlert

Quando uma validação de campo falha dentro do modelo, quem avisa o usuário é sempre SetErrorMessage — nunca MsgAlert nem FWAlertError, porque o MVC só trata a mensagem que passa por esse método. As nove posições dele, a armadilha das duas vírgulas iniciais e o exemplo completo de uma pós-validação estão em Os eventos de um modelo MVC.

Onde a regra não alcança

Uma propriedade reescrita com SetProperty dentro de um ModelDef vale só para aquele modelo. A rotina tradicional que atualiza a mesma tabela por fora — um batch com RecLock direto, uma tela nunca convertida — não enxerga nada disso: os dois fontes não compartilham estrutura em tempo de execução. O inverso também vale: trava escrita num ponto de entrada tradicional não é lida pelo MVC. Quem precisa da mesma regra valendo nos dois mundos escreve a regra dentro do próprio dicionário, quando ela é sempre válida, ou numa função comum chamada pelos dois lados, quando depende do fluxo.

Esta é a última peça da série sobre MVC no Protheus: depois do esqueleto de três funções, do modelo e da view, e do cadastro pai-filho com grid, fica esta ferramenta fina — mudar uma regra sem tocar em nada que o resto do sistema também usa.


Se um campo seu não aceita o valor que o código manda gravar, fale com a gente.

Referências

  1. TDNtdn.totvs.com

    TDN — FWFormModelStruct
  2. TDNtdn.totvs.com

    TDN — FWFormModel

Continue por aqui