E na classe dos algoritmos mais estranhos, e que faz com que os programadores pensem duas vezes, encontram-se os recursivos. Ou seja, aqueles que por alguma razão precisam chamar a si próprios.
Acontece que uma das aplicações mais interessantes desses algoritmos, se encontram exatamente os menus de opções, e planejar um bom menu para o usuário é uma das tarefas importantes do desenvolvimento, para dar acessibilidade, organização e clareza nas operações do sistema.
A boa notícia é que Genexus é 10! e alguns programadores muito bem intencionados nos deram todos os recursos para programar um menu recursivo, sem muito esforço, portanto, cabe aqui apenas o direcionamento para os recursos corretos.
Entao, maos na massa e um pouco de paciencia para entender os elementos do menu.
1. JSCookMenu:
Esse é um controle muito pratico, que possibilita que se construam menus na interface web de forma muito interessante com controle sobre as classes CSS, ou seja, estilos, imagens, ...
Para carregar o JSCookMenu é necessário utilizar uma SDT, que já é recursiva por natureza, pois os Itens (Item) são na verdade ramos da própria SDT, como pode ser visto abaixo (veja o Type).
O menu possui uma variável do tipo coleção do SDT JsCookMenuItem que ao ser carregado apresenta as opções no controle, se olhar nas Variables verá que foi incluida uma variavel chamada &MenuDataCollection para esta finalidade. Portanto, para se carregar um item no menu teriamos que programar algo como:
&JSCookMenuItem = new()
&JSCookMenuItem.Title = 'item'
&JSCookMenuItem.UTL = 'http://www.gotoitem.com/itemfolder/item'
&MenuDataCollection.Add(&JSCookMenuItem)
Desta forma para cada item a ser incluido no menu teriamos que gerar um conjunto igual a este de codigo.Se não entendeu este código melhor voce estudar um pouquinho a respeito de Structured Data Type e também Collections.
2. Data Provider:
Para programarmos o menu recursivo usando a programação apresentada anteriormente seria bastante complexo, com for each, procedure recursiva, enfim, vamos aproveitar o exemplo para falar de mais um recurso interessante que temos a nosso favor.
Para ser mais claro, o DP abaixo dá conta do recado e substitui a programação da procedure mais complexa, apenas usando o recurso de declarar o conteudo que queremos.
Os elementos incluidos nesta programação são atributos que estão em uma tabela Menu, e prontos para irem para nosso controle na interface (MenuTitulo, MenuTarget, FatherMenuId, ...)
Um detalhe que nao explicamos da primeira vez aqui foi a regra PARM necessária para este Data Provider funcionar, que deve ser:
Parm(&FatherMenuId, &FatherMenuItemId);
Falando em recursividade, se observar bem verá que existe um elemento na estrutura (childs) que chama o próprio Data Provider (JsCookMenuProvider1), ou seja, o SDT foi criado para funcionar de forma recursiva.
Quando este artigo foi escrito pela primeira vez, a idéia era uma tabela mais complexa, agora analisando com calma, a tabela Menu poderia ter sido criada mais simples apenas com os atributos:
- MenuId
- MenuTitulo
- MenuUrl
- MenuPaiId (subtipo apontando para MenuId)
3. Web Panel:
Aqui a coisa é simples, somente inclua um user control JSCookMenu na interface, e em seguida carregue a variável &MenuDataCollection com o nosso DP recursivo. Passe o parâmetro 1,1 na ‘primeira chamada’, e no evento Start do Webpanel chame o MenuSample.
4. O Resultado:
O resultado alcançado com esse Data Provider é bem legal, com as opções principais, sub menus e por ai vai, nao existe limite para organizar os niveis no Menu, pois, lembre que é recursivo.
Temos ai um recurso de árvore!! Fala sério, ficou legal, hein!!
5. A Árvore:
Observe que a parte programável acabou! E não gastamos muito para chegar aqui (Uma transação Menu, Um DataProvider carregando uma coleção do tipo SDT JSCookMenuItem), e você deve estar se perguntando cadê a procedure, onde esta o codigo fonte necessário para se carregar a coisa?. A resposta é que o Data Provider faz tudo, é uma 'procedure declarativa', e pode funcionar ainda como caracteristica recursiva.
Se não temos muito o que fazer com o programa então vamos explicar à parte mais difícil que consiste em alimentar o monstro, ou seja, como armazenar e carregar informação recursiva que alimente o DP e o JSCookMenu.
Para isso vou recorrer a um desenho de árvore mesmo, que talvez simplifique um pouco a visão para você. Veja que pendurado no nó 2 temos os itens (5, 6 e 7), e no nó 6 os itens (8 e 9). Outro exemplo, pendurado no nó 1, temos os nós (2, 3 e 4), e assim por diante. Entenda que o Menu pode ser organizado desta forma, bastando voce escolher onde vai pendurar as coisas.
Para os ‘puristas’ e mais exigentes, pode-se dizer que esta árvore não é binária, portanto, para cada nó, temos vários que podem estar conectados.
Em termos de dados podemos dizer que precisamos apenas de um numero para definir o nó e outro para indicar a qual nó este pertence. Ou seja, nó=7, pertence ao nó=2. E por ai vai.
]
Portanto, simplificando a coisa, precisaremos de uma tabela com os seguintes dados, para produzir o exemplo anterior:
E o que a tabela tem de especial? Apenas um campo recursivo chamado FatherMenuId e FatherMenuItemId que aponta para MenuId e MenuItemId, respectivamente. Observe que utilizei dois números para indicar um nó. Entenda o primeiro como grupo e o segundo como item do grupo, tipo uma idéia para organizar menus por grupos de usuários.
Aqui também faltou na explicação que para apontar FatherMenuId e FatherMenuItemId para MenuId e MenuItemId é necessário um objeto chamado Subtipo no Genexus.
6. Transação:
Claro que estamos no Genexus, e para que tudo se complete é necessária uma transação que grave os dados. Para isso temos uma estrutura simples:
Sendo que FatherMenuId e FatherMenuItemId são subtipos que apontam para MenuId e MenuItemId.
Agradecimentos e Conclusão
Portanto, para se criar um menu siga os passos:
- Crie uma transação Menu
- Crie um WebPanel e inclua nele o controle JSCookMenu
- Crie um DataProvider para carregar o SDT JsCookMenuItem
- Chame o DataProvider no WebPanel
A conclusão aqui é simples, Genexus proporciona uma programação em árvore, complexa, com poucas linhas de código no Data Provider, então, reclamar do que? Genexus é 10!
Já o agradecimento é complexo, porque tantas pessoas participaram da criação do JSCookMenu, do Genexus, Transação, Subtipo, Data Provider, treinamento da Artech, ... que fica impossível identificar todos, e para não deixar ninguém de fora desta, então vamos apenas dizer:
OBRIGADAO!!!
Se quiser saber um pouco mais sobre recursividade em Data Provider, pode dar uma olhada no link: http://wiki.gxtechnical.com/commwiki/servlet/hwiki?Recursive+Data+Providers,