Arquivo central da sequência UPDATE. O DepartamentoProdutoForm que já tinha 3 inner classes (ShowInsert, Insert, Cancelar) ganha mais 2: ShowUpdate (carregar registro e abrir form preenchido) e Update (gravar alterações com transação). O br() também é atualizado pra mostrar o botão Salvar certo em cada modo.
package br.xt.app.departamento.produto;
import br.jasap.core.Effect;
import br.jasap.effect.Response;
import br.jasap.gui.Bar;
import br.jasap.gui.Button;
import br.jasap.gui.JasapPage;
import br.jasap.gui.Table;
import br.jasap.gui.form.Form;
import br.jasap.gui.form.Text;
import br.jasap.gui.form.Textarea;
import br.jasap.util.Js;
import br.jasap.util.filters.TransactionFilter;
import br.xt.acore.view.XtPage;
public class DepartamentoProdutoForm extends DepartamentoProdutoAction {
@Override
public Effect execute() throws Exception {
render();
return new Response();
}
public static class ShowInsert extends DepartamentoProdutoForm {
@Override
public Effect execute() throws Exception {
setInsert(FORM);
getSession().remove(ROOT.concat(DepartamentoProdutoBean.ID_PRODUTO));
render();
return new Response();
}
}
public static class Insert extends DepartamentoProdutoAction {
public Insert() { super.getFilters().add(new TransactionFilter()); }
@Override
public Effect execute() throws Exception {
getFactory().departamento().proModel().insert(proBean());
evalParent(Js.CLOSE_SUB_WINDOWS);
return new Response();
}
}
// ADICIONAR
public static class ShowUpdate extends DepartamentoProdutoForm {
@Override
public Effect execute() throws Exception {
setUpdate(FORM);
proBean().setId_produto(getInput().getInteger(DepartamentoProdutoBean.ID_PRODUTO));
getSession().addInt(ROOT.concat(DepartamentoProdutoBean.ID_PRODUTO), proBean().getId_produto());
getFactory().departamento().proModel().daoSingle(proBean());
render();
return new Response();
}
}
public static class Update extends DepartamentoProdutoAction {
public Update() { super.getFilters().add(new TransactionFilter()); }
@Override
public Effect execute() throws Exception {
proBean().setId_produto(id_produto());
getFactory().departamento().proModel().update(proBean());
evalParent(Js.CLOSE_SUB_WINDOWS);
return new Response();
}
}
// FIM
public static class Cancelar extends DepartamentoProdutoForm {
@Override
public Effect execute() throws Exception {
evalParent(Js.CLOSE_SUB_WINDOWS);
return new Response();
}
}
public void render() throws Exception {
// ... (sem alteração — mesmo código da sequência CREATE)
XtPage page = new XtPage(getManager());
if (isAjaxCall()) {
update(JasapPage.DIV_WINDOW, page.content(window().toHtml()));
eval(Js.CLOSE_SUB_WINDOWS);
} else {
page.getTable().setBorder(4).rowC("100%")
.setContent(page.content(window().toHtml()))
.setStyle(ui().modalBorder());
page.setWinTitle("Produto");
getOutput().write(this, page);
}
}
public Table window() throws Exception {
// ... (sem alteração)
Table w = new Table(getManager()).setSize("100%", "100%");
w.rowC("1%", JasapPage.DIV_TITLE, ui().title("CADASTRO DE PRODUTO"));
w.rowC("1%", null, ui().line());
w.rowC("auto").setId(JasapPage.DIV_MASTER).setContent(form()).table();
w.rowC("1%", null, ui().line());
w.rowC("1%", JasapPage.DIV_BOTTOM, br());
return w;
}
// ADICIONAR
protected Bar br() throws Exception {
Button salvarInsert = ui().button(" Salvar ")
.setCss("btn btn-success btn-lg").setNoSize()
.setOnClick(submit(Insert.class).validate().toHtml())
.setVisible(isInsert(FORM));
Button salvarUpdate = ui().button(" Salvar ")
.setCss("btn btn-success btn-lg").setNoSize()
.setOnClick(submit(Update.class).validate().toHtml())
.setVisible(isUpdate(FORM));
Button cancelar = ui().button(" Cancelar ")
.setCss("btn btn-primary btn-lg").setNoSize()
.setOnClick(link(Cancelar.class).ajax());
Bar bar = ui().bar();
bar.addRight(cancelar);
bar.addRight(" ");
bar.addRight(salvarInsert);
bar.addRight(salvarUpdate);
return bar;
}
// FIM
public String form() throws Exception {
// ... (sem alteração)
Form frm = ui().form();
frm.addHidden(DepartamentoProdutoBean.ID_PRODUTO, proBean().getId_produto());
frm.line().add(nome_produto(), "150");
frm.line().add(vl_produto(), "150");
frm.line().add(qtd_produto(), "150");
frm.line().add(obs_produto(), "150");
return frm.getTable().toHtml();
}
// ... campos nome_produto, vl_produto, qtd_produto, obs_produto (sem alteração)
public static String FORM = ROOT.concat("__FORM");
}
Mudanças nesta sequência: 2 inner classes novas (ShowUpdate, Update) e br() reescrito com 3 botões. Nenhum import novo. Os campos, o render(), o window(), o form() e as inner classes do CREATE permanecem iguais.
ShowUpdate — carregar registro e abrir preenchido
Executada quando o usuário clica numa linha da lista. Faz quatro coisas antes de montar a tela:
setUpdate(FORM);
proBean().setId_produto(getInput().getInteger(DepartamentoProdutoBean.ID_PRODUTO));
getSession().addInt(ROOT.concat(DepartamentoProdutoBean.ID_PRODUTO), proBean().getId_produto());
getFactory().departamento().proModel().daoSingle(proBean());
setUpdate(FORM) — liga a flag "modo edição" na sessão. É essa flag que o isUpdate(FORM) verifica pra decidir quais botões mostrar (Salvar update). Contraparte do setInsert(FORM) do ShowInsert.getInput().getInteger(...) — lê o ID do produto que veio no request (passado pelo setOnclick da lista).getSession().addInt(...) — guarda esse ID na sessão pra uso futuro. Sem isso, o Update não saberia qual registro operar (ele não recebe o ID no request — lê da sessão via id_produto()).daoSingle(proBean()) — carrega todos os dados do registro do banco e preenche o Bean. Quando o render() montar os campos, cada setValue(proBean().getNome_produto()) já terá o valor real.Comparação com ShowInsert: o ShowInsert limpa a sessão (remove) e deixa o Bean vazio. O ShowUpdate grava na sessão (addInt) e preenche o Bean com dados do banco. Resultado: o mesmo form, mas com campos preenchidos em vez de vazios.
Herda de DepartamentoProdutoForm — por isso tem acesso a render(), window(), form(), br(), e todos os campos. Mesma lógica do ShowInsert.
Update — gravar alterações com transação
Executada quando o usuário clica "Salvar" no modo edição. Estrutura idêntica ao Insert, com uma diferença crucial:
proBean().setId_produto(id_produto());
getFactory().departamento().proModel().update(proBean());
evalParent(Js.CLOSE_SUB_WINDOWS);
proBean().setId_produto(id_produto()) — o proBean() vem preenchido com os dados do formulário (via getInstance), MAS o id_produto chega como null pelo hidden field em alguns browsers. Pra garantir, seta explicitamente o ID lido da sessão.
Sem essa linha, o update().execute geraria um UPDATE ... WHERE id_produto = null — que não afetaria nenhuma linha. O registro ficaria inalterado sem nenhum erro visível. É um risco silencioso clássico do framework.
TransactionFilter — mesmo mecanismo do Insert. Envolve o execute() numa transação: sucesso → COMMIT, exception → ROLLBACK.
Herda de DepartamentoProdutoAction (não de Form) — mesmo padrão do Insert. Não precisa de render() nem de campos, só do proBean() e da conexão com o banco.
br() — barra de botões atualizada
O br() original (do CREATE) tinha 2 botões. Agora tem 3:
| Botão | Visível quando | Posição | Ação |
|---|---|---|---|
| Salvar (insert) | isInsert(FORM) | Direita | submit(Insert.class).validate() |
| Salvar (update) | isUpdate(FORM) | Direita | submit(Update.class).validate() |
| Cancelar | Sempre | Direita | link(Cancelar.class) |
No modo inserção, o usuário vê: Cancelar + Salvar (à direita). No modo edição, vê: Cancelar + Salvar (à direita). Visualmente igual — mas por trás, o Salvar aponta pra actions diferentes (Insert vs Update).
Por que dois botões Salvar separados? Porque cada um aponta pra uma action diferente (Insert vs Update). O setVisible garante que só um aparece por vez — nunca os dois ao mesmo tempo.
O ciclo completo de editar um produto envolve 3 requests (3 agentes distintos):
ShowUpdate → seta modo edição, guarda ID na sessão, carrega dados do banco → monta o form preenchido → modal abre com campos já preenchidosUpdate → TransactionFilter abre transação → seta ID da sessão no Bean → model.update(bean) grava → transação fecha → modal fechasetOnCloseURL dispara refresh → lista atualiza com dados novosCada um desses requests é um agente novo, cartão novo, tudo do zero. O encadeamento lógico vive no código (ShowUpdate carrega, Update grava, List atualiza), não na memória de nenhum agente.
O Form agora tem INSERT e UPDATE completos — mas ainda é a versão mínima. Funcionalidades que virão em episódios futuros:
Cada feature ganha seu próprio episódio com foco pedagógico claro. O CRUD completo (READ + DELETE + CREATE + UPDATE) está pronto na versão básica.