Como percorrer um array dentro de outro em MVC | Ti Responde 0091

No vídeo de hoje, vamos demonstrar em como percorrer uma grid dentro de outra em MVC através de For … Next via AdvPL.

A dúvida de hoje, nos perguntaram, se seria possível percorrer um array de Filhos e dentro dele percorrer um array de Netos em uma tela Modelo X em MVC.

 

Pensando nisso, montamos esse exemplo, onde demonstramos em como pegar os modelos das grids, e percorrer elas usando o laço de repetição For … Next com o método GoLine.

 

Segue abaixo o vídeo exemplificando:

 

E abaixo o código fonte desenvolvido:

//Bibliotecas
#Include "Totvs.ch"
#Include "FWMVCDef.ch"

//Variveis Estaticas
Static cTitulo := "Artistas x CDs x Músicas"
Static cTabPai := "ZD1"
Static cTabFilho := "ZD2"
Static cTabNeto := "ZD3"

/*/{Protheus.doc} User Function zVid0091
Exemplo de Modelo X
@author Daniel Atilio
@since 04/02/2022
@version 1.0
@type function
/*/

User Function zVid0091()
	Local aArea   := GetArea()
	Local oBrowse
	Private aRotina := {}

	//Definicao do menu
	aRotina := MenuDef()

	//Instanciando o browse
	oBrowse := FWMBrowse():New()
	oBrowse:SetAlias(cTabPai)
	oBrowse:SetDescription(cTitulo)
	oBrowse:DisableDetails()

	//Ativa a Browse
	oBrowse:Activate()

	RestArea(aArea)
Return Nil

/*/{Protheus.doc} MenuDef
Menu de opcoes na funcao zVid0091
@author Daniel Atilio
@since 04/02/2022
@version 1.0
@type function
/*/

Static Function MenuDef()
	Local aRotina := {}

	//Adicionando opcoes do menu
	ADD OPTION aRotina TITLE "Visualizar" ACTION "VIEWDEF.zVid0091" OPERATION 1 ACCESS 0
	ADD OPTION aRotina TITLE "Incluir" ACTION "VIEWDEF.zVid0091" OPERATION 3 ACCESS 0
	ADD OPTION aRotina TITLE "Alterar" ACTION "VIEWDEF.zVid0091" OPERATION 4 ACCESS 0
	ADD OPTION aRotina TITLE "Excluir" ACTION "VIEWDEF.zVid0091" OPERATION 5 ACCESS 0

Return aRotina

/*/{Protheus.doc} ModelDef
Modelo de dados na funcao zVid0091
@author Daniel Atilio
@since 04/02/2022
@version 1.0
@type function
/*/

Static Function ModelDef()
	Local oStruPai := FWFormStruct(1, cTabPai)
	Local oStruFilho := FWFormStruct(1, cTabFilho, { |x| ! Alltrim(x) $ 'ZD2_NOME' })
    Local oStruNeto := FWFormStruct(1, cTabNeto)
	Local aRelFilho := {}
    Local aRelNeto := {}
	Local oModel
	Local bPre := Nil
	Local bPos := Nil
	Local bCommit := Nil
	Local bCancel := Nil


	//Cria o modelo de dados para cadastro
	oModel := MPFormModel():New("zVid91M", bPre, bPos, bCommit, bCancel)
	oModel:AddFields("ZD1MASTER", /*cOwner*/, oStruPai)
	oModel:AddGrid("ZD2DETAIL","ZD1MASTER",oStruFilho,/*bLinePre*/, /*bLinePost*/,/*bPre - Grid Inteiro*/,/*bPos - Grid Inteiro*/,/*bLoad - Carga do modelo manualmente*/)
    oModel:AddGrid("ZD3DETAIL","ZD2DETAIL",oStruNeto,/*bLinePre*/, /*bLinePost*/,/*bPre - Grid Inteiro*/,/*bPos - Grid Inteiro*/,/*bLoad - Carga do modelo manualmente*/)
	oModel:SetPrimaryKey({})

    //Fazendo o relacionamento (pai e filho)
    oStruFilho:SetProperty("ZD2_ARTIST", MODEL_FIELD_OBRIGAT, .F.)
	aAdd(aRelFilho, {"ZD2_FILIAL", "FWxFilial('ZD2')"} )
	aAdd(aRelFilho, {"ZD2_ARTIST", "ZD1_CODIGO"})
	oModel:SetRelation("ZD2DETAIL", aRelFilho, ZD2->(IndexKey(1)))

	//Fazendo o relacionamento (filho e neto)
	aAdd(aRelNeto, {"ZD3_FILIAL", "FWxFilial('ZD3')"} )
	aAdd(aRelNeto, {"ZD3_CD", "ZD2_CD"})
	oModel:SetRelation("ZD3DETAIL", aRelNeto, ZD3->(IndexKey(1)))

	//Definindo campos unicos da linha
    oModel:GetModel("ZD2DETAIL"):SetUniqueLine({'ZD2_CD'})
	oModel:GetModel("ZD3DETAIL"):SetUniqueLine({'ZD3_MUSICA'})

Return oModel

/*/{Protheus.doc} ViewDef
Visualizacao de dados na funcao zVid0091
@author Daniel Atilio
@since 04/02/2022
@version 1.0
@type function
/*/

Static Function ViewDef()
	Local oModel := FWLoadModel("zVid0091")
	Local oStruPai := FWFormStruct(2, cTabPai)
	Local oStruFilho := FWFormStruct(2, cTabFilho, { |x| ! Alltrim(x) $ 'ZD2_NOME' })
    Local oStruNeto := FWFormStruct(2, cTabNeto)
	Local oView

	//Cria a visualizacao do cadastro
	oView := FWFormView():New()
	oView:SetModel(oModel)
	oView:AddField("VIEW_ZD1", oStruPai, "ZD1MASTER")
	oView:AddGrid("VIEW_ZD2",  oStruFilho,  "ZD2DETAIL")
    oView:AddGrid("VIEW_ZD3",  oStruNeto,  "ZD3DETAIL")

	//Partes da tela
	oView:CreateHorizontalBox("CABEC_PAI", 30)
	oView:CreateHorizontalBox("GRID_FILHO", 30)
    oView:CreateHorizontalBox("GRID_NETO", 40)
	oView:SetOwnerView("VIEW_ZD1", "CABEC_PAI")
	oView:SetOwnerView("VIEW_ZD2", "GRID_FILHO")
    oView:SetOwnerView("VIEW_ZD3", "GRID_NETO")

	//Titulos
    oView:EnableTitleView("VIEW_ZD1", "Pai - ZD1 (Artistas)")
	oView:EnableTitleView("VIEW_ZD2", "Filho - ZD2 (CDs)")
	oView:EnableTitleView("VIEW_ZD3", "Neto - ZD3 (Musicas dos CDs)")

	//Removendo campos
    oStruFilho:RemoveField("ZD2_ARTIST")
    oStruFilho:RemoveField("ZD2_NOME")
	oStruNeto:RemoveField("ZD3_CD")

	//Adicionando campo incremental na grid
	oView:AddIncrementField("VIEW_ZD3", "ZD3_ITEM")

    //Adiciona botões no outras ações para demonstrar em como percorrer um array dentro de outro
	oView:addUserButton("* Percorrer Arrays", "MAGIC_BMP", {|| fExemplo()}, , , , .T.)

Return oView

Static Function fExemplo()
    Local aArea       := FWGetArea()
    Local oModel      := FWModelActive()
	Local oModelFilho := oModel:GetModel('ZD2DETAIL')
    Local oModelNeto  := oModel:GetModel('ZD3DETAIL')
    Local nLinhaFilho := 0
    Local nLinhaNeto  := 0
    Local cMensagem   := ""

    //Percorre as informações da grid de filho
    For nLinhaFilho := 1 To oModelFilho:Length()
        //Posiciona na linha atual do filho
        oModelFilho:GoLine(nLinhaFilho)

        //Incrementa a mensagem
        cMensagem += "[" + cValToChar(nLinhaFilho) + "] Filho: " + oModelFilho:GetValue("ZD2_NOMECD") + CRLF
        
        //Percorre os netos
        For nLinhaNeto := 1 To oModelNeto:Length()
            //Posiciona na linha atual do neto
            oModelNeto:GoLine(nLinhaNeto)

            //Incrementa a mensagem
            cMensagem += "[" + cValToChar(nLinhaFilho) + "][" + cValToChar(nLinhaNeto) + "] Neto: " + oModelNeto:GetValue("ZD3_MUSICA") + CRLF
        Next

        //Volta pra linha 1 dos netos
        oModelNeto:GoLine(1)
    Next

    //Se tiver mensagem, exibe
    If ! Empty(cMensagem)
        ShowLog(cMensagem)
    EndIf

    //Volta para a linha 1 dos filhos
    oModelFilho:GoLine(1)

    FWRestArea(aArea)
Return

Bom pessoal, por hoje é só.

 

Abraços e até a próxima.

Dan (Daniel Atilio)
Cristão de ramificação protestante. Especialista em Engenharia de Software pela FIB, graduado em Banco de Dados pela FATEC Bauru e técnico em informática pelo CTI da Unesp. Entusiasta de soluções Open Source e blogueiro nas horas vagas. Autor e mantenedor do portal Terminal de Informação.

Deixe uma resposta

Terminal de Informação