Árvore de páginas

Versões comparadas

Chave

  • Esta linha foi adicionada.
  • Esta linha foi removida.
  • A formatação mudou.

...

Bloco de código
titleAPI REST - idiomas.p
linenumberstrue
collapsetrue
{utp/ut-api.i}

{utp/ut-api-action.i pFindById GET /byid/~* }
{utp/ut-api-action.i pFindAll GET /~* }

{utp/ut-api-action.i pUpdateById PUT /~* }

{utp/ut-api-action.i pGetMetadata POST /metadata/~* }
{utp/ut-api-action.i pValidateForm POST /validateForm/~* }
{utp/ut-api-action.i pCreate POST /~* }

{utp/ut-api-action.i pDeleteById DELETE /~* }

{utp/ut-api-notfound.i}

DEFINE TEMP-TABLE ttIdiomas NO-UNDO
    FIELD cod_idioma      LIKE idioma.cod_idioma      SERIALIZE-NAME "codIdioma"
    FIELD des_idioma      LIKE idioma.des_idioma      SERIALIZE-NAME "desIdioma"
    FIELD cod_idiom_padr  LIKE idioma.cod_idiom_padr  SERIALIZE-NAME "codIdiomPadr"
    FIELD dat_ult_atualiz LIKE idioma.dat_ult_atualiz SERIALIZE-NAME "datUltAtualiz"
    FIELD hra_ult_atualiz LIKE idioma.hra_ult_atualiz SERIALIZE-NAME "hraUltAtualiz"
    FIELD id              AS RECID.

/** Procedure que retorna a metadata **/
PROCEDURE pGetMetadata:
    DEFINE INPUT  PARAMETER oJsonInput  AS JsonObject NO-UNDO.
    DEFINE OUTPUT PARAMETER oJsonOutput AS JsonObject NO-UNDO.

    DEFINE VARIABLE oResponse AS JsonAPIResponse NO-UNDO.
    DEFINE VARIABLE oIdiomas  AS JsonArray       NO-UNDO.
    DEFINE VARIABLE oObj      AS JsonObject      NO-UNDO.

    ASSIGN oIdiomas = NEW JsonArray().
    
    /* Define a lista de campos a serem apresentados no HTML */
    ASSIGN oObj = NEW JsonObject().
    oObj:add('property', 'codIdioma').
    oObj:add('label', 'Idioma').
    oObj:add('visible', TRUE).
    oObj:add('disable', TRUE).
    oObj:add('type', JsonAPIUtils:convertAblTypeToHtmlType('character')).
    oObj:add('gridColumns', 6).
    oIdiomas:add(oObj).
    
    ASSIGN oObj = NEW JsonObject().
    oObj:add('property', 'desIdioma').
    oObj:add('label', 'Descrição').
    oObj:add('visible', TRUE).
    oObj:add('required', TRUE).
    oObj:add('type', JsonAPIUtils:convertAblTypeToHtmlType('character')).
    oObj:add('gridColumns', 6).
    oIdiomas:add(oObj).

    ASSIGN oObj = NEW JsonObject().
    oObj:add('property', 'codIdiomPadr').
    oObj:add('label', 'Idioma Padrão').
    oObj:add('visible', TRUE).
    oObj:add('type', JsonAPIUtils:convertAblTypeToHtmlType('character')).
    oObj:add('gridColumns', 6).
    oIdiomas:add(oObj).

    ASSIGN oObj = NEW JsonObject().
    oObj:add('property', 'datUltAtualiz').
    oObj:add('label', 'Última Atualização').
    oObj:add('visible', TRUE).
    oObj:add('format', 'dd/MM/yyyy').
    oObj:add('disable', TRUE).
    oObj:add('type', JsonAPIUtils:convertAblTypeToHtmlType('date')).
    oObj:add('gridColumns', 6).
    oIdiomas:add(oObj).

    ASSIGN oObj = NEW JsonObject().
    oObj:add('property', 'hraUltAtualiz').
    oObj:add('label', 'Hora Última Atualização').
    oObj:add('visible', TRUE).
    oObj:add('disable', TRUE).
    oObj:add('type', JsonAPIUtils:convertAblTypeToHtmlType('character')).
    oObj:add('gridColumns', 6).
    oIdiomas:add(oObj).
    
    // os Adicionacampos oabaixo campoforam IDadicionados napara listatestes de camposvalidacao para a interface HTMLdo formulario
    //ASSIGN IssooOpts facilitara= o gerenciamento do registro na interface HTML
    oIdiomas:add(JsonAPIUtils:getIdField()).

    // Adiciona o JsonArray em um JsonObject para enviar para a UPCNEW JsonArray().
    ASSIGN oOpt = NEW JsonObject().
    oOpt:add('label', 'Foco CodIdiomaPadrao').
    oOpt:add('value', 'focoCodIdiomPadr').
    oOpts:add(oOpt).
    oObjASSIGN oOpt       = NEW JsonObject().
    oObjoOpt:add('rootlabel', oIdiomas'Foco DesIdioma').
    
    // Realiza a chamada da UPC Progress
    {include/i-epcrest.i &endpoint=getMetaData &event=getMetaData &jsonVar=oObj}    

    // Recupera o JsonArray de dentro do JsonObject retornado pela UPC
    oIdiomas = oObj:getJsonArray('root').    
    
    // Retorna a colecao de campos customizados ou nao para a interface HTML
    oResponse   = NEW JsonAPIResponse(oIdiomasoOpt:add('value', 'FocoDesIdioma').
    oOpts:add(oOpt).
    ASSIGN oOpt = NEW JsonObject().
    oOpt:add('label', 'Desabilita CodIdiomaPadrao').
    oOpt:add('value', 'DesabilitaCodIdiomaPadrao').
    oOpts:add(oOpt).
    ASSIGN oOpt = NEW JsonObject().
    oOpt:add('label', 'Habilita CodIdiomaPadrao').
    oOpt:add('value', 'HabilitaCodIdiomaPadrao').
    oOpts:add(oOpt).
    ASSIGN oOpt = NEW JsonObject().
    oOpt:add('label', 'Mascara CPF').
    oOpt:add('value', 'MascaraCPF').
    oOpts:add(oOpt).
    oJsonOutputASSIGN oOpt = oResponse:createJsonResponseNEW JsonObject().
END PROCEDURE.

/** Procedure que retorna os valores **/
PROCEDURE pFindAll:
    DEFINE INPUT  PARAMETER oJsonInput  AS JsonObject NO-UNDO oOpt:add('label', 'Mascara CNPJ').
    oOpt:add('value', 'MascaraCNPJ').
    oOpts:add(oOpt).
    DEFINEASSIGN OUTPUToOpt PARAMETER= oJsonOutput ASNEW JsonObject NO-UNDO().

    DEFINE VARIABLE oResponse AS JsonAPIResponse NO-UNDOoOpt:add('label', 'TrocaValor DesIdioma').
    DEFINE VARIABLE oIdiomas  AS JsonArray       NO-UNDOoOpt:add('value', 'TrocaValorDesIdioma').
    oOpts:add(oOpt).
    DEFINEASSIGN VARIABLEoOpt oObj= NEW JsonObject().
    AS JsonObject oOpt:add('label', 'Esconder DesIdioma').
     NO-UNDOoOpt:add('value', 'EsconderDesIdioma').
    DEFINE VARIABLE oIdoOpts:add(oOpt).
    ASSIGN oOpt =  ASNEW JsonObject().
    oOpt:add('label',  NO-UNDO'Aparecer DesIdioma').
 
    EMPTY TEMP-TABLE ttIdiomas.
oOpt:add('value', 'AparecerDesIdioma').
    // Monta a lista de valores dos camposoOpts:add(oOpt).
    ASSIGN oOpt = NEW JsonObject().
    FOR EACH idioma NO-LOCK BY idioma.cod_idioma:oOpt:add('label', 'Mostra Mensagem de Erro').
    oOpt:add('value', 'showErrorMessage').
   CREATE ttIdiomas oOpts:add(oOpt).
    ASSIGN oOpt =  BUFFER-COPY idioma TO ttIdiomasNEW JsonObject().
    oOpt:add('label', 'Muda Label DesIdioma').
 // Alimenta o campo ID utilizado pela interface HTML como chave primaria oOpt:add('value', 'mudaLabelDesIdioma').
    oOpts:add(oOpt).

        ASSIGN ttIdiomas.idoObj = RECIDNEW JsonObject(idioma).
    ENDoObj:add('property', 'codAcoes').
    
    // Obtem um jsonArray com base no conteudo da temp-tableoObj:add('label', 'Acoes de Tela').
    oObj:add('visible', TRUE).
    oObj:add('type', JsonAPIUtils:convertAblTypeToHtmlType('character')).
    oIdiomas oObj:add('options', oOpts).
   = JsonAPIUtilsoObj:convertTempTableToJsonArray(TEMP-TABLE ttIdiomas:HANDLEadd('gridColumns', 12).
    oIdiomas:add(oObj).

    // AdicionaInformacoes ode JsonArrayTipo emde umPessoa
 JsonObject para enviar paraASSIGN aoOpts UPC
= NEW JsonArray().
  oObj  ASSIGN   oOpt   = NEW JsonObject().
    oObjoOpt:add('rootlabel', oIdiomas'Pessoa Fisica').
    
    // Realiza a chamada da UPC ProgressoOpt:add('value', 'f').
    {include/i-epcrest.i &endpoint=findAll &event=findAll &jsonVar=oObj}

oOpts:add(oOpt).
    //ASSIGN RecuperaoOpt o= JsonArray de dentro do JsonObject retornado pela UPCNEW JsonObject().
    oOpt:add('label', 'Pessoa Juridica').
    oIdiomas = oObj:getJsonArray('rootoOpt:add('value', 'j').
    oOpts:add(oOpt).

    // Retorna a colecao de dados customizados ou nao para a interface HTML
    oResponseASSIGN oObj  = NEW JsonAPIResponseJsonObject(oIdiomas).
    oJsonOutput = oResponse:createJsonResponse(oObj:add('property', 'tipUsuario').
END PROCEDURE.

/** Procedure que retorna 1 registro pelo ID **/ 
PROCEDURE pFindById: oObj:add('label', 'Tipo do usuario').
    oObj:add('visible', TRUE).
    DEFINE INPUT  PARAMETER oJsonInput  AS JsonObject NO-UNDOoObj:add('type', JsonAPIUtils:convertAblTypeToHtmlType('character')).
    oObj:add('options', oOpts).
    DEFINE OUTPUT PARAMETER oJsonOutput AS JsonObject NO-UNDOoObj:add('gridColumns', 6).
    oIdiomas:add(oObj).

    ASSIGN oObj DEFINE= VARIABLE oRequestNEW JsonObject().
   AS JsonAPIRequestParser NO-UNDO oObj:add('property', 'codCpfCnpj').
    DEFINE VARIABLE oResponse  AS JsonAPIResponse oObj:add('label', 'CPF/CNPJ').
    oObj:add('visible', TRUE).
     NO-UNDOoObj:add('mask', '999.999.999-99').
    DEFINE VARIABLE oIdioma    AS JsonObject   oObj:add('type', JsonAPIUtils:convertAblTypeToHtmlType('character')).
    oObj:add('gridColumns', 6).
    oIdiomas:add(oObj).

    // Adiciona o campo NO-UNDO.
ID na lista de DEFINEcampos VARIABLEpara oIda interface HTML
    // Isso ASfacilitara JsonObjecto gerenciamento do registro na interface HTML
     NO-UNDOoIdiomas:add(JsonAPIUtils:getIdField()).

    
// Adiciona o JsonArray DEFINEem VARIABLEum cIdJsonObject para enviar para a UPC
   AS CHARACTERoObj        =    NO-UNDONEW JsonObject().
    DEFINE VARIABLE iIdoObj:add('root', oIdiomas).
    
    // ASRealiza INTEGERa chamada da UPC Progress
    {include/i-epcrest.i &endpoint=getMetaData &event=getMetaData &jsonVar=oObj}    NO-UNDO.

    EMPTY TEMP-TABLE ttIdiomas.

    // Le os parametros enviados pela interface HTML// Recupera o JsonArray de dentro do JsonObject retornado pela UPC
    oRequestoIdiomas = NEW JsonAPIRequestParser(oJsonInput).oObj:getJsonArray('root').    
    
    // ObtemRetorna oa ID
colecao de campos customizados cIdou = oRequest:getPathParams():getCharacter(2).
    nao para a interface HTML
    //oResponse Localiza o registro na tabela IDIOMA pelo ID (recid)
    FIND FIRST idioma = NEW JsonAPIResponse(oIdiomas).
    oJsonOutput = oResponse:createJsonResponse().
END PROCEDURE.

/** Procedure que retorna os valores **/
PROCEDURE pFindAll:
    DEFINE INPUT  PARAMETER oJsonInput WHERE RECID(idioma) = INT(cId)AS JsonObject NO-UNDO.
    DEFINE OUTPUT PARAMETER  NO-LOCKoJsonOutput AS JsonObject NO-ERRORUNDO.

    DEFINE IFVARIABLE AVAILABLEoResponse idiomaAS THEN DO:
    JsonAPIResponse NO-UNDO.
    DEFINE VARIABLE oIdiomas  AS JsonArray    BUFFER-COPY idioma TO ttIdiomasNO-UNDO.
    DEFINE VARIABLE oObj  ASSIGN ttIdiomas.id = RECID(idioma).
 AS JsonObject  END.
    NO-UNDO.
    //DEFINE ObtemVARIABLE umoId jsonArray com base no conteudo da temp-table
  AS JsonObject  oIdioma     = JsonAPIUtils:convertTempTableFirstItemToJsonObject(NO-UNDO.
 
    EMPTY TEMP-TABLE ttIdiomas:HANDLE).

    // RealizaMonta a chamadalista de davalores UPCdos Progresscampos
    FOR EACH idioma {include/i-epcrest.i &endpoint=findById &event=findById &jsonVar=oIdioma}    
   
NO-LOCK BY idioma.cod_idioma:
        CREATE ttIdiomas.
        BUFFER-COPY idioma TO ttIdiomas.
        // RetornaAlimenta o registrocampo customizadoID ou nao para autilizado pela interface HTML
 como chave primaria
 oResponse   = NEW JsonAPIResponse(oIdioma).
  ASSIGN  oJsonOutputttIdiomas.id = oResponse:createJsonResponseRECID(idioma).
    END PROCEDURE.

/** Procedure que cria um
 novo registro na tabela **/
PROCEDURE pCreate:
    DEFINE INPUT  PARAMETER oJsonInput  AS JsonObject NO-UNDO.// Obtem um jsonArray com base no conteudo da temp-table
    DEFINEoIdiomas OUTPUT PARAMETER oJsonOutput AS JsonObject NO-UNDO. = JsonAPIUtils:convertTempTableToJsonArray(TEMP-TABLE ttIdiomas:HANDLE).

    DEFINE// VARIABLEAdiciona oBodyo JsonArray em um JsonObject para enviar para a UPC
 AS JsonObject  oObj         NO-UNDO. 
    DEFINE VARIABLE oRequest = NEW JsonObject().
    oObj:add('root', oIdiomas).
    
    // Realiza ASa JsonAPIRequestParser NO-UNDO.
    DEFINE VARIABLE oResponse      AS JsonAPIResponse      NO-UNDO.
    
    DEFINE VARIABLE cCodIdioma     AS CHARACTER            NO-UNDO.
    DEFINE VARIABLE cDesIdioma     AS CHARACTER           chamada da UPC Progress
    {include/i-epcrest.i &endpoint=findAll &event=findAll &jsonVar=oObj}

    // Recupera o JsonArray de dentro do JsonObject retornado pela UPC
    oIdiomas = oObj:getJsonArray('root').    

    // Retorna a colecao de dados customizados ou nao para a interface HTML
    oResponse   = NEW JsonAPIResponse(oIdiomas).
    oJsonOutput = oResponse:createJsonResponse().
END PROCEDURE.

/** Procedure que retorna 1 registro pelo ID **/ 
PROCEDURE pFindById:
    DEFINE INPUT  PARAMETER oJsonInput  AS JsonObject NO-UNDO.
    DEFINE VARIABLEOUTPUT cCodIdiomPadrPARAMETER oJsonOutput AS CHARACTER JsonObject NO-UNDO.

    DEFINE VARIABLE oRequest   AS JsonAPIRequestParser NO-UNDO.
    DEFINE VARIABLE rIdiomaoResponse  AS JsonAPIResponse      NO-UNDO.
   AS RECIDDEFINE VARIABLE oIdioma    AS JsonObject           NO-UNDO.
    DEFINE VARIABLE lCreatedoId        AS LOGICALJsonObject              NO-UNDO INITIAL FALSE.
 
   
 // Le os parametrosDEFINE eVARIABLE oscId dados enviados pela interface HTML
   AS oRequestCHARACTER = NEW JsonAPIRequestParser(oJsonInput).
    oBody    = oRequest:getPayload() NO-UNDO.
    
DEFINE VARIABLE iId  // Obtem os demais dados
  AS INTEGER cCodIdioma    = oBody:getCharacter("codIdioma") NO-ERROR.
    cDesIdioma    = oBody:getCharacter("desIdioma") NO-ERRORUNDO.

    cCodIdiomPadrEMPTY = oBody:getCharacter("codIdiomPadr") NO-ERRORTEMP-TABLE ttIdiomas.

    // Le Criaos oparametros registroenviados napela tabelainterface IDIOMAHTML
    DOoRequest = NEW TRANSACTIONJsonAPIRequestParser(oJsonInput).
    
    ON// ERRORObtem UNDO,o LEAVE:ID
    cId = oRequest:getPathParams():getCharacter(2).
  FIND FIRST idioma
    // Localiza o registro na tabela IDIOMA pelo ID (recid)
   WHERE idioma.cod_idioma = cCodIdioma
      FIND FIRST idioma 
        WHERE RECID(idioma) = INT(cId)
        NO-LOCK NO-ERROR.
        IF  NOT AVAILABLE idioma THEN DO:
        BUFFER-COPY idioma TO  CREATE idiomattIdiomas.
        ASSIGN ttIdiomas.id =  ASSIGN RECID(idioma).cod_idioma
    END.
   = cCodIdioma
    // Obtem um jsonArray com base no conteudo da temp-table
      idioma.des_idiomaoIdioma      = cDesIdioma= JsonAPIUtils:convertTempTableFirstItemToJsonObject(TEMP-TABLE ttIdiomas:HANDLE).

    // Realiza a chamada da UPC Progress
    {include/i-epcrest.i &endpoint=findById &event=findById &jsonVar=oIdioma}  idioma.cod_idiom_padr  = cCodIdiomPadr
   
    // Retorna o registro customizado ou nao para a interface HTML
  idioma.dat_ult_atualiz = TODAY
oResponse   = NEW JsonAPIResponse(oIdioma).
    oJsonOutput = oResponse:createJsonResponse().
END PROCEDURE.

/** Procedure que cria um novo registro  idioma.hra_ult_atualiz = STRING(TIME,"HH:MM:SS")na tabela **/
PROCEDURE pCreate:
    DEFINE INPUT  PARAMETER oJsonInput  AS JsonObject NO-UNDO.
    DEFINE OUTPUT PARAMETER rIdiomaoJsonOutput AS JsonObject NO-UNDO. 

    DEFINE VARIABLE oBody      = RECID(idioma)
   AS JsonObject           NO-UNDO. 
   lCreated DEFINE VARIABLE oRequest       AS JsonAPIRequestParser NO-UNDO.
   = TRUE.
DEFINE VARIABLE oResponse      
AS JsonAPIResponse      NO-UNDO.
    
 // Realiza a chamadaDEFINE daVARIABLE UPCcCodIdioma   Progress para aAS criacaoCHARACTER do 
          NO-UNDO.
  // registro customizado.DEFINE NaoVARIABLE utilizaremoscDesIdioma o retorno da UPC
 AS CHARACTER          // neste caso. 
NO-UNDO.
    DEFINE VARIABLE cCodIdiomPadr  AS CHARACTER            {include/i-epcrest.i &endpoint=create &event=afterCreate &jsonVar=oBody}NO-UNDO.
    DEFINE VARIABLE rIdioma    
    AS RECID   
            RELEASE idioma.
NO-UNDO.
    DEFINE VARIABLE lCreated       AS LOGICAL          END.
    ENDNO-UNDO INITIAL FALSE.
 
    // RetornaLe oos IDparametros e os sedados foienviados criadopela cominterface sucessoHTML
    oBodyoRequest = NEW JsonObjectJsonAPIRequestParser(oJsonInput).
    oBody:add('id', rIdioma    = oRequest:getPayload().
    oBody:add('created', (IF lCreated THEN 'OK' ELSE 'NOK')).   


    // Obtem os demais dados
    //cCodIdioma Retorna o oBody montado para a interface HTML
    oResponse= oBody:getCharacter("codIdioma") NO-ERROR.
    cDesIdioma    = NEW JsonAPIResponse(oBody)oBody:getCharacter("desIdioma") NO-ERROR.
    oJsonOutputcCodIdiomPadr = oResponseoBody:createJsonResponsegetCharacter("codIdiomPadr").
END PROCEDURE NO-ERROR.

/**   Procedure que// atualizaCria o conteudoregistro dona registrotabela peloIDIOMA
 ID **/ 
PROCEDURE pUpdateById:
DO  TRANSACTION
  DEFINE INPUT  PARAMETER oJsonInput  ASON JsonObjectERROR NO-UNDO.UNDO, LEAVE:
    DEFINE OUTPUT PARAMETER oJsonOutput ASFIND JsonObject NO-UNDO.
FIRST idioma
    DEFINE VARIABLE oBody      WHERE idioma.cod_idioma = cCodIdioma
 AS JsonObject          NO-LOCK NO-UNDOERROR. 
    DEFINE VARIABLE oRequest   IF  NOT AVAILABLE ASidioma JsonAPIRequestParser NO-UNDO.THEN DO:
    DEFINE VARIABLE oResponse      ASCREATE JsonAPIResponseidioma.
      NO-UNDO.
    DEFINE VARIABLE oIdiomaASSIGN idioma.cod_idioma      = AScCodIdioma
  JsonObject           NO-UNDO.
    DEFINE VARIABLE oIdidioma.des_idioma      = cDesIdioma
     AS JsonObject           NO-UNDO.
  idioma.cod_idiom_padr  DEFINE= VARIABLEcCodIdiomPadr
 cId            AS CHARACTER     idioma.dat_ult_atualiz = TODAY
     NO-UNDO.
    
    DEFINE VARIABLE cCodIdioma     AS CHARACTERidioma.hra_ult_atualiz = STRING(TIME,"HH:MM:SS")
            NO-UNDO.
    DEFINE VARIABLE cDesIdioma rIdioma    AS CHARACTER            NO-UNDO.= RECID(idioma)
    DEFINE  VARIABLE cCodIdiomPadr  AS CHARACTER         lCreated   NO-UNDO.
    DEFINE VARIABLE datUltAtualiz  AS DATE   = TRUE.
        
     NO-UNDO.
    DEFINE VARIABLE hraUltAtualiz // ASRealiza a CHARACTERchamada da UPC Progress para a criacao do 
    NO-UNDO.
    DEFINE VARIABLE lUpdated  // registro customizado. Nao utilizaremos ASo LOGICALretorno da UPC
            NO-UNDO INITIAL FALSE.

// neste caso. 
    // Le os parametros e os dados enviados pela interface HTML
  {include/i-epcrest.i &endpoint=create &event=afterCreate &jsonVar=oBody}   oRequest =
 NEW JsonAPIRequestParser(oJsonInput).
    oBody  
  = oRequest:getPayload().
   
    // Obtem oRELEASE IDidioma.
    cId    END.
  = oRequest:getPathParams():getCharacter(1)  END.

    // Retorna o ObtemID ose demaisse dados
foi criado com sucesso
 cCodIdioma   oBody = oBody:getCharacter("codIdioma") NO-ERRORNEW JsonObject().
    cDesIdioma oBody:add('id', rIdioma).
   = oBody:getCharacter("desIdioma") NO-ERROR.
    cCodIdiomPadr = oBody:getCharacter("codIdiomPadr") NO-ERROR.
    add('created', (IF lCreated THEN 'OK' ELSE 'NOK')).   

    // AtualizaRetorna o registrooBody namontado tabelapara IDIOMAa pelo ID (recid)interface HTML
    DOoResponse  TRANSACTION
 = NEW JsonAPIResponse(oBody).
    oJsonOutput ON ERROR UNDO, LEAVE:
        FIND FIRST idioma 
 = oResponse:createJsonResponse().
END PROCEDURE.

/** Procedure que atualiza o conteudo do registro pelo ID **/ 
PROCEDURE pUpdateById:
    DEFINE INPUT  PARAMETER oJsonInput  AS WHERE RECID(idioma) = INT(cId)JsonObject NO-UNDO.
    DEFINE OUTPUT PARAMETER oJsonOutput AS JsonObject   EXCLUSIVE-LOCK NO-ERRORUNDO.

    DEFINE VARIABLE oBody  IF  AVAILABLE idioma THEN DO:
   AS JsonObject        ASSIGN idioma.des_idioma      = cDesIdiomaNO-UNDO. 
    DEFINE VARIABLE oRequest       AS      idioma.cod_idiom_padr  = cCodIdiomPadrJsonAPIRequestParser NO-UNDO.
    DEFINE VARIABLE oResponse      AS JsonAPIResponse      idioma.dat_ult_atualiz = TODAYNO-UNDO.
    DEFINE VARIABLE oIdioma        AS JsonObject    idioma.hra_ult_atualiz = STRING(TIME,"HH:MM:SS")
     NO-UNDO.
    DEFINE VARIABLE oId        lUpdated    AS JsonObject          = TRUENO-UNDO.
    DEFINE VARIABLE cId       
     AS CHARACTER      // Realiza a chamada da UPC ProgressNO-UNDO.
 para atualizar o registro
    DEFINE VARIABLE cCodIdioma     AS CHARACTER // na tabela cutomizada ou nao. Nao utilizaremos o retorno da UPCNO-UNDO.
    DEFINE VARIABLE cDesIdioma     AS //CHARACTER neste caso. 
         NO-UNDO.
   {include/i-epcrest.i &endpoint=update &event=afterUpdate &jsonVar=oBody}    
 DEFINE VARIABLE cCodIdiomPadr  AS CHARACTER         END.
    ENDNO-UNDO.
   
 DEFINE VARIABLE datUltAtualiz // RetornaAS oDATE ID e se foi atualizado com sucesso
    oBody = NEW JsonObject().
    oBody:add('id', cId)NO-UNDO.
    oBody:add('updated', (IF lUpdated THEN 'OK' ELSE 'NOK')).   

DEFINE VARIABLE hraUltAtualiz  AS CHARACTER        // Retorna o oBody montadoNO-UNDO.
 para a interface HTML
DEFINE VARIABLE lUpdated  oResponse   = NEW JsonAPIResponse(oBody).
  AS LOGICAL   oJsonOutput = oResponse:createJsonResponse().
END PROCEDURE.

/** Procedure que atualiza o conteudo do registro peloNO-UNDO ID **/ 
PROCEDURE pDeleteById:INITIAL FALSE.

    DEFINE// INPUTLe os PARAMETERparametros oJsonInpute os ASdados JsonObject NO-UNDO.
    DEFINE OUTPUT PARAMETER oJsonOutput AS JsonObject NO-UNDO.
enviados pela interface HTML
    oRequest = NEW JsonAPIRequestParser(oJsonInput).
    DEFINEoBody VARIABLE oObj  = oRequest:getPayload().
   
    // ASObtem JsonObjecto ID
    cId      NO-UNDO.
    DEFINE VARIABLE oRequest       AS JsonAPIRequestParser NO-UNDO.
= oRequest:getPathParams():getCharacter(1).

    // Obtem os demais dados
    cCodIdioma    DEFINE VARIABLE oResponse= oBody:getCharacter("codIdioma") NO-ERROR.
    cDesIdioma  AS JsonAPIResponse =     oBody:getCharacter("desIdioma") NO-UNDOERROR.
    DEFINEcCodIdiomPadr VARIABLE oArray = oBody:getCharacter("codIdiomPadr") NO-ERROR.
    
    AS// JsonArrayAtualiza o registro na tabela IDIOMA pelo ID (recid)
    NO-UNDO.
DO  TRANSACTION
  DEFINE VARIABLE oIdioma    ON ERROR UNDO, LEAVE:
 AS JsonObject      FIND FIRST idioma   NO-UNDO.
    DEFINE VARIABLE oId      WHERE RECID(idioma) = INT(cId)
   AS JsonObject        EXCLUSIVE-LOCK   NO-UNDOERROR.
    DEFINE VARIABLE cId  IF  AVAILABLE idioma THEN  DO:
    AS  CHARACTER      ASSIGN idioma.des_idioma     NO-UNDO.
 = cDesIdioma
  DEFINE VARIABLE lDeleted       AS LOGICAL       idioma.cod_idiom_padr  = cCodIdiomPadr
    NO-UNDO INITIAL FALSE.
    DEFINE VARIABLE ix       idioma.dat_ult_atualiz = TODAY
    AS INTEGER              NO-UNDO.

    // Le os parametros enviados pela interface HTML
idioma.hra_ult_atualiz = STRING(TIME,"HH:MM:SS")
             oRequest = NEW JsonAPIRequestParser(oJsonInput).
   lUpdated 
    // Eliminacao de registro individual
    IF  oRequest:getPathParams():length > 0 THEN DO:
= TRUE.
         // Obtem o ID
        cId = oRequest:getPathParams():getCharacter(1).
  // Realiza a chamada da UPC 
Progress para atualizar o registro
    RUN piDeleteRecord (cId).
      // na ASSIGNtabela lDeletedcutomizada = (RETURN-VALUE = "OK").
    END.ou nao. Nao utilizaremos o retorno da UPC
    ELSE DO:
        // Eliminacao de registros em loteneste caso. 
        // Obtem a lista de IDs diretamente do oJsonInput onde vem um JsonArray {include/i-epcrest.i &endpoint=update &event=afterUpdate &jsonVar=oBody}    
        END.
 // oArray = oJsonInput:getJsonArray('payload') END.
   
    // oArrayRetorna = oRequest:getPayloadArray().
        DO  ix = 1 TO oArray:length:o ID e se foi atualizado com sucesso
    oBody = NEW JsonObject().
    oBody:add('id', cId).
    oBody:add('updated', (IF lUpdated THEN oObj'OK' = oArray:getJsonObject(ix).
ELSE 'NOK')).   

    // Retorna o oBody montado para a  cIdinterface HTML
    oResponse   = STRING(oObj:getInteger('id'))NEW JsonAPIResponse(oBody).
    oJsonOutput = oResponse:createJsonResponse().
END PROCEDURE.

/** Procedure 
que atualiza o conteudo do registro pelo ID **/ 
PROCEDURE pDeleteById:
  RUN piDeleteRecord (cId).
DEFINE INPUT  PARAMETER oJsonInput  AS JsonObject NO-UNDO.
    IFDEFINE OUTPUT lDeletedPARAMETER =oJsonOutput FALSEAS THENJsonObject NO-UNDO.

    DEFINE VARIABLE oObj          ASSIGN lDeletedAS =JsonObject (RETURN-VALUE = "OK").
        ENDNO-UNDO.
    END.
DEFINE VARIABLE oRequest  
    // RetornaAS o ID e se foi criado com sucesso
JsonAPIRequestParser NO-UNDO.
    DEFINE VARIABLE oResponse    oObj = NEW JsonObject().
AS JsonAPIResponse    IF  oRequest:getPathParams():length > 0 THEN DO:
  NO-UNDO.
    DEFINE VARIABLE oArray      oObj:add('id', cId).
    END.
   AS JsonArray      oObj:add('deleted', (IF lDeleted THEN 'OK' ELSE 'NOK')) NO-UNDO.
    DEFINE 
VARIABLE oIdioma   // Retorna o oBody montado paraAS aJsonObject interface HTML
    oResponse   = NEW JsonAPIResponse(oObj) NO-UNDO.
    DEFINE VARIABLE oJsonOutputoId = oResponse:createJsonResponse().
END PROCEDURE.

PROCEDURE piDeleteRecord:
    DEFINE INPUT PARAMETER cId AS CHARACTERJsonObject           NO-UNDO.

    DEFINE VARIABLE oObjcId            AS CHARACTER JsonObject           NO-UNDO.
    DEFINE VARIABLE lDeleted       AS LOGICAL NO-UNDO INITIAL FALSE.

    LOG-MANAGER:WRITE-MESSAGE("Eliminando registro -> " + cId, ">>>>>").

    // Elimina o registro na tabela IDIOMA pelo ID (recid)
 NO-UNDO INITIAL FALSE.
    DEFINE VARIABLE ix        DO  TRANSACTION
   AS INTEGER    ON ERROR UNDO, LEAVE:
       NO-UNDO.

 FIND FIRST idioma 
// Le os parametros enviados pela interface HTML
    oRequest WHERE RECID(idioma) = INT(cId)= NEW JsonAPIRequestParser(oJsonInput).
    
    // Eliminacao de  EXCLUSIVE-LOCK NO-ERROR.registro individual
    IF  oRequest:getPathParams():length > IF0 AVAILABLE idioma THEN DO:
        // Obtem o ID
 //  Monta a chave estrangeira para enviarcId para UPC= oRequest:getPathParams():getCharacter(1).
        
    // poder elominar o registroRUN da tabela customizadapiDeleteRecord (cId).
        ASSIGN lDeleted = (RETURN-VALUE oObj = NEW JsonObject("OK").
    END.
    ELSE    oObj:add('codIdioma', idioma.cod_idioma).
DO:
        // Eliminacao de registros em lote
            // RealizaObtem a chamadalista dade UPC Progress para a eliminacao IDs diretamente do 
oJsonInput onde vem um JsonArray
        // oArray registro customizado. Nao utilizaremos o retorno da UPC= oJsonInput:getJsonArray('payload').
        oArray    // neste caso. = oRequest:getPayloadArray().
        DO  ix  {include/i-epcrest.i &endpoint=delete &event=beforeDelete &jsonVar=oObj}= 1 TO oArray:length:
            oObj = oArray:getJsonObject(ix).
            cId = STRING(oObj:getInteger('id')).
        

            RUN DELETEpiDeleteRecord idioma(cId).
            IF  lDeleted = FALSE THEN 
                ASSIGN lDeleted = (RETURN-VALUE = TRUE"OK").
        END.
    END.
    
    RETURN (IF lDeleted THEN "OK" ELSE "NOK").
END PROCEDURE.

/* fim */

Programa UPC:

Abaixo temos um exemplo de uma UPC criada para a API REST:

Bloco de código
titleExemplo de UPC da API REST - idiomas_upc.p
linenumberstrue
collapsetrue
/**************************************************************************
** idiomas_upc.p - Exemplo de epc para Endpoints REST 
***************************************************************************/

USING PROGRESS.json.*.
USING PROGRESS.json.ObjectModel.*.
USING com.totvs.framework.api.*.

DEFINE INPUT        PARAMETER pEndPoint AS CHARACTER  NO-UNDO.
DEFINE INPUT        PARAMETER pEvent    AS CHARACTER  NO-UNDO.
DEFINE INPUT        PARAMETER pAPI      AS CHARACTER  NO-UNDO.
DEFINE INPUT-OUTPUT PARAMETER jsonIO    AS JSONObject NO-UNDO.

DEFINE VARIABLE jAList  AS JsonArray  NO-UNDO.
DEFINE VARIABLE jObj    AS JsonObject NO-UNDO.

DEFINE VARIABLE ix      AS INTEGER// Retorna o ID e se foi criado com sucesso
    oObj = NEW JsonObject().
    IF  oRequest:getPathParams():length > 0 THEN DO:
        oObj:add('id', cId).
    END.
    oObj:add('deleted', (IF lDeleted THEN 'OK' ELSE 'NOK')).
    
    // Retorna o oBody montado para a interface HTML
    oResponse   = NEW JsonAPIResponse(oObj).
    oJsonOutput = oResponse:createJsonResponse().
END PROCEDURE.

PROCEDURE piDeleteRecord:
    DEFINE INPUT PARAMETER cId AS CHARACTER NO-UNDO.

    DEFINE VARIABLE oObj           AS JsonObject           NO-UNDO.
    DEFINE VARIABLE iTotlDeleted    AS INTEGER  AS LOGICAL NO-UNDO INITIAL FALSE.

DEFINE VARIABLE cCodIdioma  AS CHARACTER  NO-UNDO.
DEFINE VARIABLE cCodUsuario AS CHARACTER  NO-UNDO.
DEFINE VARIABLE cNomUsuario AS CHARACTER  NO-UNDO.
DEFINE VARIABLE cCodDialet  AS CHARACTER  NO-UNDO.

/* ***************************  Main Block  *************************** */

// Carrega as definicoes dos campos customizados da tabela
IF  pEndPoint = "getMetaData"
AND pEvent    = "getMetaData" THEN DO ON STOP UNDO, LEAVE:

    // Obtem a lista de campos e valores    
    ASSIGN jAList = jsonIO:getJsonArray('root').

    // Cria os novos campos na lista
    ASSIGN jObj = NEW JsonObject().
    jObj:add('property', 'codUsuario').
    jObj:add('label', 'Usuário').
    jObj:add('visible', TRUE).
    jObj:add('required', TRUE).
    jObj:add('type', JsonAPIUtils:convertAblTypeToHtmlType('character')).
    jObj:add('gridColumns', 6).
    jAList:add(jObj).
    
    ASSIGN jObjLOG-MANAGER:WRITE-MESSAGE("Eliminando registro -> " + cId, ">>>>>").

    // Elimina o registro na tabela IDIOMA pelo ID (recid)
    DO  TRANSACTION
        ON ERROR UNDO, LEAVE:
        FIND FIRST idioma 
            WHERE RECID(idioma) = INT(cId)
            EXCLUSIVE-LOCK NO-ERROR.
        IF AVAILABLE idioma THEN DO:
            // Monta a chave estrangeira para enviar para UPC
            // poder elominar o registro da tabela customizada
            oObj = NEW JsonObject().
    jObj:add('property', 'nomUsuario').
        jObjoObj:add('labelcodIdioma', 'Nome'idioma.cod_idioma).
      jObj:add('visible', TRUE).
    jObj:add('required', TRUE).
    jObj:add('type', JsonAPIUtils:convertAblTypeToHtmlType('character')).
      jObj:add('gridColumns', 6).
 // Realiza  jAList:add(jObj).

    ASSIGN jObj = NEW JsonObject().a chamada da UPC Progress para a eliminacao do 
    jObj:add('property', 'codDialet').
    jObj:add('label', 'Dialeto').
  //  jObj:add('visible', TRUE).
    jObj:add('required', TRUE).registro customizado. Nao utilizaremos o retorno da UPC
    jObj:add('type', JsonAPIUtils:convertAblTypeToHtmlType('character')).
    jObj:add('gridColumns', 6).
  //  jAList:add(jObj).neste caso. 
    
    // Retorna a nova lista com os campos customizados
    jsonIO:Set("root", jAList).
END.

// Carrega os valores dos campos customizados das tabelas
IF  pEndPoint = "findAll"
AND pEvent    = "findAll" THEN DO ON STOP UNDO, LEAVE: {include/i-epcrest.i &endpoint=delete &event=beforeDelete &jsonVar=oObj}    

            DELETE idioma.
           
    // Obtem a lista de campos e valores ASSIGN lDeleted = TRUE.
        ASSIGNEND.
  jAList = jsonIO:getJsonArray('root') END.
    
    RETURN LOG-MANAGER:WRITE-MESSAGE("UPC FINDALL", ">>>>").
(IF lDeleted THEN "OK" ELSE "NOK").
END PROCEDURE.

PROCEDURE pValidateForm:
    FIND FIRST usuar_mestre NO-LOCK NO-ERRORDEFINE INPUT  PARAMETER oJsonInput  AS JsonObject NO-UNDO.
    DEFINE OUTPUT PARAMETER oJsonOutput AS JsonObject NO-UNDO.

    //DEFINE ArmazenaVARIABLE ooRequest tamanho da listaAS em variavel para evitar LOOP devido a adicionar novos itens na lista
JsonAPIRequestParser NO-UNDO.
    DEFINE VARIABLE oResponse  AS JsonAPIResponse     ASSIGN iTot = jAList:length NO-UNDO.

    DODEFINE VARIABLE ixoBody = 1 TO iTot:
  AS JsonObject     ASSIGN jObj = jAList:GetJsonObject(ix)    NO-UNDO.
    DEFINE VARIABLE cProp   
   AS CHARACTER    // Alimenta os novos dados
    NO-UNDO.
    IFDEFINE VARIABLE AVAILABLEoValue usuar_mestre THEN DO:
  AS JsonObject         jObj:add('codUsuario', usuar_mestre.cod_usuario) NO-ERRORUNDO.
    DEFINE VARIABLE cValue      jObj:add('nomUsuario', usuar_mestre.nom_usuario) NO-ERROR.
  AS CHARACTER          jObj:add('codDialet', usuar_mestre.cod_dialet) NO-ERRORUNDO.
    DEFINE VARIABLE cId  END.
      AS CHARACTER 
        // Atualiza o objetoNO-UNDO.
 na lista
  DEFINE VARIABLE oNewValue  AS  jAList:set(ix, jObj).
JsonObject           NO-UNDO.
    DEFINE VARIABLE oNewFields  FIND NEXT usuar_mestre NO-LOCKAS JsonArray            NO-ERRORUNDO.
    END.

DEFINE VARIABLE cFocus  // Retorna o jsonAS ROOTCHARACTER a lista nova com novos dados customizados 
    jsonIO:Set("root", jAList).
END.

IF  pEndPoint = "findById"
AND pEvent    = "findById" THEN DO ON STOP UNDO, LEAVE:
    // Obtem as informacoes necessarias da API para retornar dados    
    cCodIdioma  = jsonIO:getCharacter("codIdioma"). // chave estrangeira

    LOG-MANAGER:WRITE-MESSAGE("UPC FINDBYID cod_idioma= " + cCodIdioma, ">>>>").

    // Adiciona os valores da tabela customizada no retorno
    FIND FIRST usuar_mestre NO-LOCK NO-ERROR.
    IF  AVAILABLE usuar_mestre THEN DO:
        jsonIO:add('codUsuario', usuar_mestre.cod_usuario) NO-ERROR.
        jsonIO:add('nomUsuario', usuar_mestre.nom_usuario) NO-ERROR.
        jsonIO:add('codDialet', usuar_mestre.cod_dialet) NO-ERROR.
    END.
END.

IF  pEndPoint = "create"
AND pEvent    = "afterCreate" THEN DO ON STOP UNDO, LEAVE:
    // Obtem as informacoes necessarias da API para criacao do registro    
    cCodIdioma  = jsonIO:getCharacter("codIdioma") NO-ERROR. // chave estrangeira
    cCodUsuario = jsonIO:getCharacter("codUsuario") NO-ERROR.
    cNomUsuario = jsonIO:getCharacter("nomUsuario") NO-ERROR.
    cCodDialet  = jsonIO:getCharacter("codDialet") NO-ERROR.

    LOG-MANAGER:WRITE-MESSAGE("UPC CREATE cod_idioma= " + cCodIdioma, ">>>>").
    LOG-MANAGER:WRITE-MESSAGE("UPC CREATE cod_usuario= " + cCodUsuario, ">>>>").
    
    // logica de CREATE
    /* Em comentario a logica para nao criar registros desnecessariamente
    FIND FIRST usuar_mestre
        WHERE usuar_mestre.cod_usuario = cCodUsuario
        EXCLUSIVE-LOCK NO-ERROR.
    IF  NOT AVAILABLE usuar_mestre THEN DO:
NO-UNDO.
    DEFINE VARIABLE oRet       AS JsonObject           NO-UNDO.
    DEFINE VARIABLE oObj       AS JsonObject           NO-UNDO.
    DEFINE VARIABLE oMessages  AS JsonArray            NO-UNDO.

    oRequest = NEW JsonAPIRequestParser(oJsonInput).
    oBody    = oRequest:getPayload().
   
    // obtem o nome da propriedade que ocorreu o LEAVE para validacao
    cProp      = oBody:getCharacter("property")     NO-ERROR.
    oValue     = oBody:getJsonObject("value")       NO-ERROR.
    cValue     = STRING(oValue:GetCharacter(cProp)) NO-ERROR.
    cId        = oValue:getCharacter("id")          NO-ERROR.
    
    /* Recebemos do HTML o JSON abaixo
    {
        "property": "codAcoes",
        "value": {
            "codIdiomPadr": "01 Português",
            "codIdioma": "12345678",
            "desIdioma": "12345678901234567890",
            "hraUltAtualiz": "",
            "datUltAtualiz": null,
          ASSIGN usuar_mestre.nom_usuario = cNomUsuario "id": 6,
            "codAcoes": "FocoDesIdioma"
   usuar_mestre.cod_dialet   = cCodDialet. }
    END.}
    */
END.

IF  pEndPoint = "update"
AND pEvent    = "afterUpdate" THEN DO ON STOP UNDO, LEAVE: // Novas Acoes sobre os campos da tela
    
    // ObtemoNewValue guarda asos informacoesvalores necessariasa daserem APIespecificados para atualizacaoos    campos
    cCodIdiomaASSIGN oNewValue = NEW jsonIO:getCharacter("codIdioma") NO-ERROR. // chave estrangeiraJsonObject().
    
    cCodUsuario// = jsonIO:getCharacter("codUsuario") NO-ERROR.
    cNomUsuario = jsonIO:getCharacter("nomUsuario") NO-ERROR.oNewFields guarda a lista de campos que serao alterados/modificados
    cCodDialetASSIGN oNewFields = jsonIO:getCharacter("codDialet") NO-ERRORNEW JsonArray().
    
    LOG-MANAGER:WRITE-MESSAGE("UPC UPDATE cod_idioma= " + cCodIdioma, ">>>>").
    LOG-MANAGER:WRITE-MESSAGE("UPC UPDATE cod_usuario= " + cCodUsuario, ">>>>")// cFocus especifica em qual campo sera feito o focus
    ASSIGN cFocus = cProp.

    // logicaoMessages deguarda UPDATE
as mensagens de retorno /*formato Em
 comentario a logica para// nao{ alterar tabelas desnecessariamente
    FIND FIRST usuar_mestrecode: '00', message: 'texto', detailedMessage: 'detalhes da mensagem' }
    ASSIGN oMessages = NEW WHERE usuar_mestre.cod_usuario = cCodUsuarioJsonArray().
   
    CASE cProp:
   EXCLUSIVE-LOCK NO-ERROR.
    IF  AVAILABLE usuar_mestreWHEN "codAcoes" THEN DO:
        ASSIGN usuar_mestre.nom_usuario = cNomUsuario
 CASE cValue:
             usuar_mestre.cod_dialet  = cCodDialet. 
WHEN 'focoCodIdiomPadr' THEN DO:
       END.
    */
END.

IF  pEndPoint = "delete"
AND pEvent    = "beforeDelete" THEN DO ON STOP UNDO, LEAVE:// setamos o focus para o campo desejado
    // obtem as informacoes necessarias da API para eliminacao    
    cCodIdiomaASSIGN cFocus = jsonIO:getCharacter("codIdioma"). // chave estrangeira
'codIdiomPadr'.
      
    LOG-MANAGER:WRITE-MESSAGE("UPC DELETE cod_idioma= " + cCodIdioma, ">>>>").
 END.
    // logica de DELETE
    /* Em comentario a logica paraWHEN nao'FocoDesIdioma' eliminar o registro desnecessariamenteTHEN DO:
    FIND FIRST usuar_mestre
        WHERE usuar_mestre.cod_usuario = cCodUsuario
   // setamos o focus  EXCLUSIVE-LOCK NO-ERROR.para o campo desejado
    IF   AVAILABLE usuar_mestre THEN DO:
        delete usuar_mestre.
 ASSIGN cFocus = END'desIdioma'.
     */
END.

RETURN "OK".

/* fim */

Resultado ao chamar ao API tendo uma UPC cadastrada:

Ao fazer as requisições, virão os seguintes resultados na UPC.

Bloco de código
titleResultado de leituras no backend Progress
linenumberstrue
collapsetrue
Busca do METADADOS onde foram adicionados os novos camposEND.
 codUsuario, nomUsuario e codDialet:

POST - http://localhost:8180/dts/datasul-rest/resources/prg/trn/v1/idiomas/metadata

{
    "total": 9,
    "hasNext": false, WHEN 'DesabilitaCodIdiomaPadrao' THEN DO:
    "items": [
        {
       // criamos um novo field "visible": true,para desabilitar
            "gridColumns": 6,
        ASSIGN oObj = NEW JsonObject().
  "disable": true,
            "property": "codIdioma",
    oObj:add('property', 'codIdiomPadr').
       "label": "Idioma",
            "type": "string"oObj:add('disabled', TRUE).
        },
        {
    oNewFields:add(oObj).
        "visible": true,
        END.
      "gridColumns": 6,
         WHEN 'HabilitaCodIdiomaPadrao' THEN "property": "desIdioma",DO:
            "label": "Descrição",
       // criamos um novo field "type": "string",para habilitar
            "required": true
        ASSIGN oObj =  },NEW JsonObject().
        {
            "visible": true,oObj:add('property', 'codIdiomPadr').
            "gridColumns": 6,
        oObj:add('disabled', FALSE).
       "property": "codIdiomPadr",
            "label": "Idioma Padrão",
oNewFields:add(oObj).
               "type": "string" END.
        },
        {
WHEN 'MascaraCPF' THEN DO:
         "visible": true,
            "gridColumns": 6,// IMPORTANTE:
            "disable": true,
       // Quando alteramos o  "property": "datUltAtualiz"valor do radio-set tipUsuario por aqui,
            "format": "dd/MM/yyyy",
       // O value-changed dele  "label": "Última Atualização",
que especifica qual a mascara
              "type": "date"
     // será utilizada },
NAO sera disparado, pois ele é dinamico e {
            "visible": true,
       // estamos validando o  "gridColumns": 6,
   campo codAcoes, sendo necessario 
         "disable": true,
          // fazermos "property": "hraUltAtualiz",
     a formatacao da mascara aqui tambem. 
       "label": "Hora Última Atualização",
          // A "type": "string"
        },mesma regra é valida para o CNPJ
        {
            "visible": false,
            "property": "id",
       // mudamos os valores dos "type": "number",campos desejados
            "key": true
        },oNewValue:add('tipUsuario', 'f').
        {
            "visible": true,oNewValue:add('codCpfCnpj', FILL('0',11)).

            "gridColumns": 6,
       // criamos um novo field "property": "codUsuario",
  para mudar a mascara
          "label": "Usuário",
         ASSIGN oObj = "type": "string",NEW JsonObject().
            "required": true
        },oObj:add('property', 'codCpfCnpj').
        {
            "visible": true,
oObj:add('mask', '999.999.999-99').
                  "gridColumns": 6,
  oNewFields:add(oObj).
               "property": "nomUsuario", END.
            "label": "Nome",
        WHEN 'MascaraCNPJ' THEN DO:
        "type": "string",
           // "required"IMPORTANTE: true
        },
        {
    // Quando alteramos o valor do radio-set tipUsuario "visible": truepor aqui,
            "gridColumns": 6,
       // O value-changed dele que "property": "codDialet",
  especifica qual a mascara
          "label": "Dialeto",
         // será  "type": "string",
      utilizada NAO sera disparado, pois ele é dinamico e 
      "required": true
        }
    ]
}

Busca dos dados onde foram adicionados novos valores:

GET - http://localhost:8180/dts/datasul-rest/resources/prg/trn/v1/idiomas

{ // estamos validando o campo codAcoes, sendo necessario 
    "total": 3,
    "hasNext": false,
    "items": [
     // fazermos a {
formatacao da mascara aqui tambem. 
       "codIdiomPadr": "99 Outros",
            "codDialet": "Pt",
      // A mesma regra é valida para o CPF

      "codIdioma": "ale",
            "codUsuario": "super",
      // alteramos os valores dos campos desejados
       "desIdioma": "Alemão",
            "hraUltAtualiz": "",oNewValue:add('tipUsuario', 'j').
            "datUltAtualiz": null,
            "nomUsuario": "Super",
 oNewValue:add('codCpfCnpj', FILL('0',15)).

           "id": 4580144
        },
// criamos um novo field para mudar a {mascara
            "codIdiomPadr": "99 Outros",
      ASSIGN oObj = NEW JsonObject().
  "codDialet": "PT",
            "codIdioma": "EN",
    oObj:add('property', 'codCpfCnpj').
       "codUsuario": "joao",
            "desIdioma": "Ingles",
    oObj:add('mask', '99.999.999/9999-99').
        "hraUltAtualiz": "",
            "datUltAtualiz": null,
oNewFields:add(oObj).
             "nomUsuario": "Joao da Silva",END.
            "id": 194736
   WHEN 'TrocaValorDesIdioma'    },THEN DO:
        {
            "codIdiomPadr": "03 Espanhol",
     // alteramos o conteudo de um campo qualquer
       "codDialet": "PT",
            "codIdioma": "ES",
     oNewValue:add('desIdioma', "Valor retornado do backend de validacao").
       "codUsuario": "Manoel",
        END.
    "desIdioma": "Espanhol",
            "hraUltAtualiz": "",
WHEN 'EsconderDesIdioma' THEN DO:
                    // criamos um novo field para tornar invisivel o campo
              "datUltAtualiz": null,
      ASSIGN oObj = NEW JsonObject().
                 "nomUsuario": "Manoel da Silva",
 oObj:add('property', 'desIdioma').
                    "id": 2968898
oObj:add('visible', FALSE).
               }
     ]
}

Front-End PO-UI

Introdução:

Para este exemplo vamos criar um CRUD com template dinâmico, onde serão mostrados os dados de acordo com o que o back-end retornar.

O desenvolvimento do frontend utilizando este campo componente se divide basicamente em três partes:

  • Routes:
    • Na definição da rota é onde vamos definir todos os caminhos dos componentes;
  • HTML
    • No HTML basta colocarmos os componentes, pois o metadados irá retornar o que precisamos para renderizar o componente;
  • TypeScript
    • No Typescript do componente vamos realizar uma pequena lógica para o tratamento dos dados de acordo com metadado;

Abaixo vamos mostrar como ficaram a parte de Listagem, Edição e Detalhe do nosso CRUD dinâmico.

Routes:

Abaixo segue exemplo de como ficará o arquivo de rotas de nossa aplicação CRUD.

Bloco de código
languagejs
titleapp-routing.module.ts
linenumberstrue
collapsetrue
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { IdiomaDetailComponent } from './idioma/detail/idioma-detail.component';
import { IdiomaEditComponent } from './idioma/edit/idioma-edit.component';
import { IdiomaListComponent } from './idioma/list/idioma-list.component';

const routes: Routes = [
  { path: 'idiomas/create', component: IdiomaEditComponent },
  { path: 'idiomas/edit/:id', component: IdiomaEditComponent },
  { path: 'idiomas/detail/:id', component: IdiomaDetailComponent },
  { path: 'idiomas', component: IdiomaListComponent },
  { path: '', redirectTo: '/idiomas', pathMatch: 'full' },
  { path: '**', component: IdiomaListComponent }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Listagem:

É a tela inicial da nossa aplicação e mostra a lista de dados da tabela Idioma, onde foram adicionados através de customização três campos da tabela usuar_mestre. Esta tela dará acesso às outras funcionalidades como edição e detalhamento.

Bloco de código
languagexml
titleListagem - idioma-list.componente.html
linenumberstrue
collapsetrue
<po-loading-overlay
  [hidden]="!showLoading">
</po-loading-overlay>

<po-page-dynamic-table
  p-auto-router
  [p-title]="cTitle"
  [p-actions]="actions"
  [p-breadcrumb]="breadcrumb"
  [p-fields]="fields"
  [p-service-api]="serviceApi">
</po-page-dynamic-table>
oNewFields:add(oObj).
                END.
                WHEN 'AparecerDesIdioma' THEN DO:
                    // criamos um novo field para tornar visivel o campo
                    ASSIGN oObj = NEW JsonObject().
                    oObj:add('property', 'desIdioma').
                    oObj:add('visible', TRUE).
                    oNewFields:add(oObj).
                END.
                WHEN 'mudaLabelDesIdioma' THEN DO:
                    // criamos um novo field para mudar o label
                    ASSIGN oObj = NEW JsonObject().
                    oObj:add('property', 'desIdioma').
                    oObj:add('label', 'Label alterado da descricao').
                    oNewFields:add(oObj).
                END.
                WHEN 'showErrorMessage' THEN DO:
                    // criamos uma mensagem de erro
                    ASSIGN oObj = NEW JsonObject().
                    oObj:add('code', '33').
                    oObj:add('message', 'A Descricao do idioma nao foi preenchida corretamente'). 
                    oObj:add('detailedMessage', 'Detalhe da mensagem de erro').
                    oMessages:add(oObj).
                END.
            END CASE.
        END.
        WHEN "tipUsuario" THEN DO:
            // setamos o focus para o campo desejado
            ASSIGN cFocus = 'codCpfCnpj'.

            // criamos um field para mudar o informar o campo e a nova mascara
            ASSIGN oObj = NEW JsonObject().
            oObj:add('property', "codCpfCnpj").
            IF  cValue = "j" THEN DO:
                // é definido um novo valor para o CNPJ
                oNewValue:add('codCpfCnpj', FILL('0',15)).
                // é alterado o formato da mascara de edicao
                oObj:add('mask', '99.999.999/9999-99').
            END.
            IF  cValue = "f" THEN DO:
                // é definido um novo valor para o CPF
                oNewValue:add('codCpfCnpj', FILL('0',11)).
                // é alterado o formato da mascara de edicao
                oObj:add('mask', '999.999.999-99').
            END.
            oNewFields:add(oObj).
        END.
    END CASE.
    
    ASSIGN oRet = NEW JsonObject().
    // value -> contem todos os valores dos campos de tela
    oRet:add('value', oNewValue).
    // fields -> contem a lista de campos com suas novas propriedades
    oRet:add('fields', oNewFields).
    // focus -> especifica em qual campo o cursor vai ficar posicionado
    oRet:add('focus', cFocus).
    // _messages -> contem uma lista de mensagens que vao aparecer como notificacoes
    oRet:add('_messages', oMessages).
    
    // encapsulamos o retorno para enviar para a UPC
    oObj = NEW JsonObject().
    oObj:add("property", cProp).
    oObj:add("originalValues", oValue).
    oObj:add("return", oRet).

    // Realiza a chamada da UPC Progress
    {include/i-epcrest.i &endpoint=validateForm &event=validateForm &jsonVar=oObj}    

    // obtem o retorno customizado
    oRet = oObj:getJsonObject("return").

    /* JSON de retorno para o HTML      
    value: {
      desIdioma: 'teste de escrita',
      hraUltAtualiz: '17:18:19'
    },
    fields: [
      {
        property: 'codCpfCnpj', 
        mask: '99.999.999/9999-99' 
      }
    ],
    focus: 'hraUltAtualiz',
    _messages: [ 
        { 
            code: '01', 
            message: 'Mensagem do erro que aconteceu', 
            detailedMessage: 'detalhes do erro acontecido' 
        } 
    ]
    */
    
    // Retorna a colecao de campos customizados ou nao para a interface HTML
    oResponse   = NEW JsonAPIResponse(oRet).
    oJsonOutput = oResponse:createJsonResponse().
END PROCEDURE.

/* fim */


Programa UPC:

Abaixo temos um exemplo de uma UPC criada para a API REST:

Bloco de código
titleExemplo de UPC da API REST - idiomas_upc.p
linenumberstrue
collapsetrue
/**************************************************************************
** idiomas_upc.p - Exemplo de epc para Endpoints REST 
***************************************************************************/

USING PROGRESS.json.*.
USING PROGRESS.json.ObjectModel.*.
USING com.totvs.framework.api.*.

DEFINE INPUT        PARAMETER pEndPoint AS CHARACTER  NO-UNDO.
DEFINE INPUT        PARAMETER pEvent    AS CHARACTER  NO-UNDO.
DEFINE INPUT        PARAMETER pAPI      AS CHARACTER  NO-UNDO.
DEFINE INPUT-OUTPUT PARAMETER jsonIO    AS JSONObject NO-UNDO.

DEFINE VARIABLE jAList  AS JsonArray  NO-UNDO.
DEFINE VARIABLE jObj    AS JsonObject NO-UNDO.

DEFINE VARIABLE ix      AS INTEGER    NO-UNDO.
DEFINE VARIABLE iTot    AS INTEGER    NO-UNDO.

DEFINE VARIABLE cCodIdioma  AS CHARACTER  NO-UNDO.
DEFINE VARIABLE cCodUsuario AS CHARACTER  NO-UNDO.
DEFINE VARIABLE cNomUsuario AS CHARACTER  NO-UNDO.
DEFINE VARIABLE cCodDialet  AS CHARACTER  NO-UNDO.

/* ***************************  Main Block  *************************** */

// Carrega as definicoes dos campos customizados da tabela
IF  pEndPoint = "getMetaData"
AND pEvent    = "getMetaData" THEN DO ON STOP UNDO, LEAVE:

    // Obtem a lista de campos e valores    
    ASSIGN jAList = jsonIO:getJsonArray('root').

    // Cria os novos campos na lista
    ASSIGN jObj = NEW JsonObject().
    jObj:add('property', 'codUsuario').
    jObj:add('label', 'Usuário').
    jObj:add('visible', TRUE).
    jObj:add('required', TRUE).
    jObj:add('type', JsonAPIUtils:convertAblTypeToHtmlType('character')).
    jObj:add('gridColumns', 6).
    jAList:add(jObj).
    
    ASSIGN jObj = NEW JsonObject().
    jObj:add('property', 'nomUsuario').
    jObj:add('label', 'Nome').
    jObj:add('visible', TRUE).
    jObj:add('required', TRUE).
    jObj:add('type', JsonAPIUtils:convertAblTypeToHtmlType('character')).
    jObj:add('gridColumns', 6).
    jAList:add(jObj).

    ASSIGN jObj = NEW JsonObject().
    jObj:add('property', 'codDialet').
    jObj:add('label', 'Dialeto').
    jObj:add('visible', TRUE).
    jObj:add('required', TRUE).
    jObj:add('type', JsonAPIUtils:convertAblTypeToHtmlType('character')).
    jObj:add('gridColumns', 6).
    jAList:add(jObj).
    
    // Retorna a nova lista com os campos customizados
    jsonIO:Set("root", jAList).
END.

// Carrega os valores dos campos customizados das tabelas
IF  pEndPoint = "findAll"
AND pEvent    = "findAll" THEN DO ON STOP UNDO, LEAVE:
    // Obtem a lista de campos e valores    
    ASSIGN jAList = jsonIO:getJsonArray('root').

    LOG-MANAGER:WRITE-MESSAGE("UPC FINDALL", ">>>>").

    FIND FIRST usuar_mestre NO-LOCK NO-ERROR.

    // Armazena o tamanho da lista em variavel para evitar LOOP devido a adicionar novos itens na lista
    ASSIGN iTot = jAList:length.

    DO  ix = 1 TO iTot:
        ASSIGN jObj = jAList:GetJsonObject(ix).
        
        // Alimenta os novos dados
        IF  AVAILABLE usuar_mestre THEN DO:
            jObj:add('codUsuario', usuar_mestre.cod_usuario) NO-ERROR.
            jObj:add('nomUsuario', usuar_mestre.nom_usuario) NO-ERROR.
            jObj:add('codDialet', usuar_mestre.cod_dialet) NO-ERROR.
        END.
        
        // Atualiza o objeto na lista
        jAList:set(ix, jObj).
        
        FIND NEXT usuar_mestre NO-LOCK NO-ERROR.
    END.

    // Retorna o json ROOT a lista nova com novos dados customizados 
    jsonIO:Set("root", jAList).
END.

IF  pEndPoint = "findById"
AND pEvent    = "findById" THEN DO ON STOP UNDO, LEAVE:
    // Obtem as informacoes necessarias da API para retornar dados    
    cCodIdioma  = jsonIO:getCharacter("codIdioma"). // chave estrangeira

    LOG-MANAGER:WRITE-MESSAGE("UPC FINDBYID cod_idioma= " + cCodIdioma, ">>>>").

    // Adiciona os valores da tabela customizada no retorno
    FIND FIRST usuar_mestre NO-LOCK NO-ERROR.
    IF  AVAILABLE usuar_mestre THEN DO:
        jsonIO:add('codUsuario', usuar_mestre.cod_usuario) NO-ERROR.
        jsonIO:add('nomUsuario', usuar_mestre.nom_usuario) NO-ERROR.
        jsonIO:add('codDialet', usuar_mestre.cod_dialet) NO-ERROR.
    END.
END.

IF  pEndPoint = "create"
AND pEvent    = "afterCreate" THEN DO ON STOP UNDO, LEAVE:
    // Obtem as informacoes necessarias da API para criacao do registro    
    cCodIdioma  = jsonIO:getCharacter("codIdioma") NO-ERROR. // chave estrangeira
    cCodUsuario = jsonIO:getCharacter("codUsuario") NO-ERROR.
    cNomUsuario = jsonIO:getCharacter("nomUsuario") NO-ERROR.
    cCodDialet  = jsonIO:getCharacter("codDialet") NO-ERROR.

    LOG-MANAGER:WRITE-MESSAGE("UPC CREATE cod_idioma= " + cCodIdioma, ">>>>").
    LOG-MANAGER:WRITE-MESSAGE("UPC CREATE cod_usuario= " + cCodUsuario, ">>>>").
    
    // logica de CREATE
    /* Em comentario a logica para nao criar registros desnecessariamente
    FIND FIRST usuar_mestre
        WHERE usuar_mestre.cod_usuario = cCodUsuario
        EXCLUSIVE-LOCK NO-ERROR.
    IF  NOT AVAILABLE usuar_mestre THEN DO:
        ASSIGN usuar_mestre.nom_usuario = cNomUsuario
               usuar_mestre.cod_dialet  = cCodDialet. 
    END.
    */
END.

IF  pEndPoint = "update"
AND pEvent    = "afterUpdate" THEN DO ON STOP UNDO, LEAVE:
    // Obtem as informacoes necessarias da API para atualizacao    
    cCodIdioma  = jsonIO:getCharacter("codIdioma") NO-ERROR. // chave estrangeira
    cCodUsuario = jsonIO:getCharacter("codUsuario") NO-ERROR.
    cNomUsuario = jsonIO:getCharacter("nomUsuario") NO-ERROR.
    cCodDialet  = jsonIO:getCharacter("codDialet") NO-ERROR.
    
    LOG-MANAGER:WRITE-MESSAGE("UPC UPDATE cod_idioma= " + cCodIdioma, ">>>>").
    LOG-MANAGER:WRITE-MESSAGE("UPC UPDATE cod_usuario= " + cCodUsuario, ">>>>").

    // logica de UPDATE
    /* Em comentario a logica para nao alterar tabelas desnecessariamente
    FIND FIRST usuar_mestre
        WHERE usuar_mestre.cod_usuario = cCodUsuario
        EXCLUSIVE-LOCK NO-ERROR.
    IF  AVAILABLE usuar_mestre THEN DO:
        ASSIGN usuar_mestre.nom_usuario = cNomUsuario
               usuar_mestre.cod_dialet  = cCodDialet. 
    END.
    */
END.

IF  pEndPoint = "delete"
AND pEvent    = "beforeDelete" THEN DO ON STOP UNDO, LEAVE:
    // obtem as informacoes necessarias da API para eliminacao    
    cCodIdioma  = jsonIO:getCharacter("codIdioma"). // chave estrangeira
    
    LOG-MANAGER:WRITE-MESSAGE("UPC DELETE cod_idioma= " + cCodIdioma, ">>>>").

    // logica de DELETE
    /* Em comentario a logica para nao eliminar o registro desnecessariamente
    FIND FIRST usuar_mestre
        WHERE usuar_mestre.cod_usuario = cCodUsuario
        EXCLUSIVE-LOCK NO-ERROR.
    IF  AVAILABLE usuar_mestre THEN DO:
        delete usuar_mestre.
    END.
    */
END.

RETURN "OK".

/* fim */

Resultado ao chamar ao API tendo uma UPC cadastrada:

Ao fazer as requisições, virão os seguintes resultados na UPC.

Bloco de código
titleResultado de leituras no backend Progress
linenumberstrue
collapsetrue
Busca do METADADOS onde foram adicionados os novos campos codUsuario, nomUsuario e codDialet:

POST - http://localhost:8180/dts/datasul-rest/resources/prg/trn/v1/idiomas/metadata

{
    "total": 9,
    "hasNext": false,
    "items": [
        {
            "visible": true,
            "gridColumns": 6,
            "disable": true,
            "property": "codIdioma",
            "label": "Idioma",
            "type": "string"
        },
        {
            "visible": true,
            "gridColumns": 6,
            "property": "desIdioma",
            "label": "Descrição",
            "type": "string",
            "required": true
        },
        {
            "visible": true,
            "gridColumns": 6,
            "property": "codIdiomPadr",
            "label": "Idioma Padrão",
            "type": "string"
        },
        {
            "visible": true,
            "gridColumns": 6,
            "disable": true,
            "property": "datUltAtualiz",
            "format": "dd/MM/yyyy",
            "label": "Última Atualização",
            "type": "date"
        },
        {
            "visible": true,
            "gridColumns": 6,
            "disable": true,
            "property": "hraUltAtualiz",
            "label": "Hora Última Atualização",
            "type": "string"
        },
        {
            "visible": false,
            "property": "id",
            "type": "number",
            "key": true
        },
        {
            "visible": true,
            "gridColumns": 6,
            "property": "codUsuario",
            "label": "Usuário",
            "type": "string",
            "required": true
        },
        {
            "visible": true,
            "gridColumns": 6,
            "property": "nomUsuario",
            "label": "Nome",
            "type": "string",
            "required": true
        },
        {
            "visible": true,
            "gridColumns": 6,
            "property": "codDialet",
            "label": "Dialeto",
            "type": "string",
            "required": true
        }
    ]
}

Busca dos dados onde foram adicionados novos valores:

GET - http://localhost:8180/dts/datasul-rest/resources/prg/trn/v1/idiomas

{
    "total": 3,
    "hasNext": false,
    "items": [
        {
            "codIdiomPadr": "99 Outros",
            "codDialet": "Pt",
            "codIdioma": "ale",
            "codUsuario": "super",
            "desIdioma": "Alemão",
            "hraUltAtualiz": "",
            "datUltAtualiz": null,
            "nomUsuario": "Super",
            "id": 4580144
        },
        {
            "codIdiomPadr": "99 Outros",
            "codDialet": "PT",
            "codIdioma": "EN",
            "codUsuario": "joao",
            "desIdioma": "Ingles",
            "hraUltAtualiz": "",
            "datUltAtualiz": null,
            "nomUsuario": "Joao da Silva",
            "id": 194736
        },
        {
            "codIdiomPadr": "03 Espanhol",
            "codDialet": "PT",
            "codIdioma": "ES",
            "codUsuario": "Manoel",
            "desIdioma": "Espanhol",
            "hraUltAtualiz": "",
            "datUltAtualiz": null,
            "nomUsuario": "Manoel da Silva",
            "id": 2968898
        }
    ]
}

Front-End PO-UI

Introdução:

Para este exemplo vamos criar um CRUD com template dinâmico, onde serão mostrados os dados de acordo com o que o back-end retornar.

O desenvolvimento do frontend utilizando este campo componente se divide basicamente em três partes:

  • Routes:
    • Na definição da rota é onde vamos definir todos os caminhos dos componentes;
  • HTML
    • No HTML basta colocarmos os componentes, pois o metadados irá retornar o que precisamos para renderizar o componente;
  • TypeScript
    • No Typescript do componente vamos realizar uma pequena lógica para o tratamento dos dados de acordo com metadado;


Abaixo vamos mostrar como ficaram a parte de Listagem, Edição e Detalhe do nosso CRUD dinâmico.

Routes:

Abaixo segue exemplo de como ficará o arquivo de rotas de nossa aplicação CRUD.

Bloco de código
languagejs
titleapp-routing.module.ts
linenumberstrue
collapsetrue
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { IdiomaDetailComponent } from './idioma/detail/idioma-detail.component';
import { IdiomaEditComponent } from './idioma/edit/idioma-edit.component';
import { IdiomaListComponent } from './idioma/list/idioma-list.component';

const routes: Routes = [
  { path: 'idiomas/create', component: IdiomaEditComponent },
  { path: 'idiomas/edit/:id', component: IdiomaEditComponent },
  { path: 'idiomas/detail/:id', component: IdiomaDetailComponent },
  { path: 'idiomas', component: IdiomaListComponent },
  { path: '', redirectTo: '/idiomas', pathMatch: 'full' },
  { path: '**', component: IdiomaListComponent }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Listagem:

É a tela inicial da nossa aplicação e mostra a lista de dados da tabela Idioma, onde foram adicionados através de customização três campos da tabela usuar_mestre. Esta tela dará acesso às outras funcionalidades como edição e detalhamento.

Bloco de código
languagexml
titleListagem - idioma-list.componente.html
linenumberstrue
collapsetrue
<po-loading-overlay
  [hidden]="!showLoading">
</po-loading-overlay>

<po-page-dynamic-table
  p-auto-router
  [p-title]="cTitle"
  [p-actions]="actions"
  [p-breadcrumb]="breadcrumb"
  [p-fields]="fields"
  [p-service-api]="serviceApi">
</po-page-dynamic-table>
Bloco de código
languagejs
titleListagem - idioma-lista.component.ts
linenumberstrue
collapsetrue
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { PoBreadcrumb } from '@po-ui/ng-components';
import { PoPageDynamicTableActions } from '@po-ui/ng-templates';

import { IdiomaService } from './../resources/idioma.service';

@Component({
  selector: 'app-idioma-list',
  templateUrl: './idioma-list.component.html',
  styleUrls: ['./idioma-list.component.css']
})

export class IdiomaListComponent implements OnInit {
  // Definicao das variaveis utilizadas
  public cTitle = 'Manutenção de Idiomas';
  public serviceApi: string;
  public fields: Array<any> = [];
  public showLoading = false;

  public readonly actions: PoPageDynamicTableActions = {
    new: '/idiomas/create',
    detail: '/idiomas/detail/:id',
    edit: '/idiomas/edit/:id',
    remove: true,
    removeAll: true
  };

  public readonly breadcrumb: PoBreadcrumb = {
    items: [
      { label: 'Home', link: '/' },
      { label: 'Idiomas'}
    ]
  };

  // Construtor da classe
  constructor(
    private service: IdiomaService,
    private route: Router
  ) { }

  // Load do componente
  public ngOnInit(): void {
    this.fields = [];
    this.serviceApi = this.service.getUrl();
    this.showLoading = true;
    this.service.getMetadata().subscribe(resp => {
      this.fields = resp['items'];
      this.service.setFieldList(this.fields);
      this.showLoading = false;
    });
  }
}

Edição: 

Esta tela permite a inclusão de um novo registro na tabela Idioma e também a alteração de registros já existentes.

Bloco de código
languagexml
titleEdição: idioma-edit.component.html
linenumberstrue
collapsetrue
<po-loading-overlay
  [hidden]="!showLoading">
</po-loading-overlay>

<po-page-edit
  [p-title]="cTitle"
  [p-breadcrumb]="breadcrumb"
  [p-disable-submit]="formEdit.form.invalid"
  (p-cancel)="cancelClick()"
  (p-save)="saveClick()">
  <po-dynamic-form
    #formEdit
    p-auto-focus="string"
    [p-fields]="fields"
    p-validate="/api/trn/v1/idiomas/validateForm"
    [p-value]="record">
  </po-dynamic-form>
</po-page-edit>
Bloco de código
languagejs
titleEdição - idioma-edit.component.ts
linenumberstrue
collapsetrue
import { Component, OnInit, ViewChild } from '@angular/core';
import { NgForm } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { PoBreadcrumb, PoDialogService, PoNotificationService } from '@po-ui/ng-components';

import { IdiomaService } from './../resources/idioma.service';

@Component({
  selector: 'app-idioma-edit',
  templateUrl: './idioma-edit.component.html',
  styleUrls: ['./idioma-edit.component.css']
})

export class IdiomaEditComponent implements OnInit {
  // Define as variaveis a serem utilizadas
  public cTitle: string;
  public currentId: string;
  public record = {};
  public fields: Array<any> = [];
  public isUpdate = false;
  public showLoading = false;

  public breadcrumb: PoBreadcrumb;

  // Obtem a referencia do componente HTML
  @ViewChild('formEdit', { static: true })
  formEdit: NgForm;

  // Construtor da classe com os servicos necessarios
  constructor(
    private service: IdiomaService,
    private activatedRoute: ActivatedRoute,
    private route: Router,
    private poDialog: PoDialogService,
    private poNotification: PoNotificationService
  ) { }

  // Load do componente
  public ngOnInit(): void {
    this.isUpdate = false;
    this.showLoading = true;

    // Carrega o registro pelo ID
    this.activatedRoute.params.subscribe(pars => {
      this.currentId = pars['id'];

      // Se nao tiver o ID definido sera um CREATE
      if (this.currentId === undefined) {
        this.isUpdate = false;
        this.cTitle = 'Inclusão de Idioma';
      } else {
        this.isUpdate = true;
        this.cTitle = 'Alteração de Idioma';
      }

      // Atualiza o breadcrumb de acordo com o tipo de edicao
      this.breadcrumb = {
        items: [
          { label: 'Home', action: this.beforeRedirect.bind(this) },
          { label: 'Idiomas', action: this.beforeRedirect.bind(this) },
          { label: this.cTitle }
        ]
      };

      // Se for uma alteracao, busca o registro a ser alterado
      if (this.isUpdate) {
        this.service.getById(this.currentId).subscribe(resp => {
          Object.keys(resp).forEach((key) => this.record[key] = resp[key]);

          // Em alteracao temos que receber o registro para depois buscar a lista de campos
          this.getMetadata();
        });
      } else {
        // Se for create, pega a lista de campos
        this.getMetadata();
      }
    });
  }

  // Retorna a lista de campos
  private getMetadata() {
    let fieldList: Array<any> = [];

    // Carrega a lista de campos, trabalhando com um cache da lista de campos
    fieldList = this.service.getFieldList(this.isUpdate);
    if (fieldList === null || fieldList.length === 0) {
      
Bloco de código
languagejs
titleListagem - idioma-lista.component.ts
linenumberstrue
collapsetrue
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { PoBreadcrumb } from '@po-ui/ng-components';
import { PoPageDynamicTableActions } from '@po-ui/ng-templates';

import { IdiomaService } from './../resources/idioma.service';

@Component({
  selector: 'app-idioma-list',
  templateUrl: './idioma-list.component.html',
  styleUrls: ['./idioma-list.component.css']
})

export class IdiomaListComponent implements OnInit {
  // Definicao das variaveis utilizadas
  public cTitle = 'Manutenção de Idiomas';
  public serviceApi: string;
  public fields: Array<any> = [];
  public showLoading = false;

  public readonly actions: PoPageDynamicTableActions = {
    new: '/idiomas/create',
    detail: '/idiomas/detail/:id',
    edit: '/idiomas/edit/:id',
    remove: true,
    removeAll: true
  };

  public readonly breadcrumb: PoBreadcrumb = {
    items: [
      { label: 'Home', link: '/' },
      { label: 'Idiomas'}
    ]
  };

  // Construtor da classe
  constructor(
    private service: IdiomaService,
    private route: Router
  ) { }

  // Load do componente
  public ngOnInit(): void {
    this.fields = [];
    this.serviceApi = this.service.getUrl();
    this.showLoading = true;
    this.service.getMetadata().subscribe(resp => {
      this.fields = resp['items'];
{
        this.service.setFieldList(this.fieldsresp['items']);
        this.showLoadingfields = falsethis.service.getFieldList(this.isUpdate);
    });
  }
}

Edição: 

Esta tela permite a inclusão de um novo registro na tabela Idioma e também a alteração de registros já existentes.

Bloco de código
languagexml
titleEdição: idioma-edit.component.html
linenumberstrue
collapsetrue
<po-loading-overlay
  [hidden]="!showLoading">
</po-loading-overlay>

<po-page-edit
  [p-title]="cTitle"
  [p-breadcrumb]="breadcrumb"
  [p-disable-submit]="formEdit.form.invalid"
  (p-cancel)="cancelClick()"
  (p-save)="saveClick()">
  <po-dynamic-form
    #formEdit
    p-auto-focus="string"
    [p-fields]="fields"
    [p-value]="record">
  </po-dynamic-form>
</po-page-edit>
  this.showLoading = false;
      });
    } else {
      this.fields = fieldList;
      this.showLoading = false;
    }
  }

  // Redireciona via breadcrumb
  private beforeRedirect(itemBreadcrumbLabel) {
    if (this.formEdit.valid) {
      this.route.navigate(['/']);
    } else {
      this.poDialog.confirm({
        title: `Confirma o redirecionamento para ${itemBreadcrumbLabel}`,
        message: `Existem dados que não foram salvos ainda. Você tem certeza que quer sair ?`,
        confirm: () => this.route.navigate(['/'])
      });
    }
  }

  // Grava o registro quando clicado no botao Salvar
  public saveClick(): void {
    this.showLoading = true;
    if (this.isUpdate) {
      // Altera um registro ja existente
      this.service.update(this.currentId, this.record).subscribe(resp => {
        this.poNotification.success('Idioma alterado com sucesso');
        this.showLoading = false;
        this.route.navigate(['/idiomas']);
      });
    } else {
      // Cria um registro novo
      this.service.create(this.record).subscribe(resp => {
        this.poNotification.success('Idioma criado com sucesso');
        this.showLoading = false;
        this.route.navigate(['/idiomas']);
      });
    }
  }

  // Cancela a edicao e redireciona ao clicar no botao Cancelar
  public cancelClick(): void {
    this.poDialog.confirm({
      title: 'Confirma cancelamento',
      message: 'Existem dados que não foram salvos ainda. Você tem certeza que quer cancelar ?',
      confirm: () => this.route.navigate(['/'])
    });
  }
}

Detalhe:

Esta tela apresenta os detalhes de um registro de Idioma, com suas customizações.

Bloco de código
languagexml
titleDetalhe: idioma-detail.component.html
linenumberstrue
collapsetrue
<po-loading-overlay
  [hidden]="!showLoading">
</po-loading-overlay>

<po-page-detail
  [p-title]="cTitle"
  [p-breadcrumb]="breadcrumb"
  (p-edit)="editClick()"
  (p-back)="goBackClick()">
  <po-dynamic-view 
    [p-fields]="fields"
    [p-value]="record">
  </po-dynamic-view>
</po-page-detail>
Bloco de código
languagejs
titleDetalhe: idioma-detail.component.ts
linenumberstrue
collapsetrue
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { PoBreadcrumb } from '@po-ui/ng-components';

import { IdiomaService } from './../resources/idioma.service';

@Component({
  selector: 'app-idioma-detail',
  templateUrl: './idioma-detail.component.html',
  styleUrls: ['./idioma-detail.component.css']
})

export class IdiomaDetailComponent implements OnInit {
  // definicao das variaveis utilizadas
  public cTitle = 'Detalhe do Idioma';
  public currentId: string;
  public fields: Array<any> = [];
  public record = {};
  public showLoading = false;

  public readonly breadcrumb: PoBreadcrumb = { items: [
      { label: 'Home', link: '/' },
      { label: 'Idiomas', link: '/idiomas' },
      { label: 'Detail' } ]
  };

  // construtor com os servicos necessarios
  constructor(
    private service: IdiomaService,
    private activatedRoute: ActivatedRoute,
    private route: Router
  ) { }

  // load do componente
  public ngOnInit(): void {
    this.activatedRoute.params.subscribe(pars => {
      this.showLoading = true;

      // carrega o registro pelo ID
      this.currentId = pars['id'];
      this.service.getById(this.currentId).subscribe(resp => {
        Object.keys(resp).forEach((key) => this.record[key] = resp[key]);

        // carrega a lista de campos somente apos receber o registro a ser apresentado
        this.fields = this.service.getFieldList(false);
        if (this.fields
Bloco de código
languagejs
titleEdição - idioma-edit.component.ts
linenumberstrue
collapsetrue
import { Component, OnInit, ViewChild } from '@angular/core';
import { NgForm } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { PoBreadcrumb, PoDialogService, PoNotificationService } from '@po-ui/ng-components';

import { IdiomaService } from './../resources/idioma.service';

@Component({
  selector: 'app-idioma-edit',
  templateUrl: './idioma-edit.component.html',
  styleUrls: ['./idioma-edit.component.css']
})

export class IdiomaEditComponent implements OnInit {
  // Define as variaveis a serem utilizadas
  public cTitle: string;
  public currentId: string;
  public record = {};
  public fields: Array<any> = [];
  public isUpdate = false;
  public showLoading = false;

  public breadcrumb: PoBreadcrumb;

  // Obtem a referencia do componente HTML
  @ViewChild('formEdit', { static: true })
  formEdit: NgForm;

  // Construtor da classe com os servicos necessarios
  constructor(
    private service: IdiomaService,
    private activatedRoute: ActivatedRoute,
    private route: Router,
    private poDialog: PoDialogService,
    private poNotification: PoNotificationService
  ) { }

  // Load do componente
  public ngOnInit(): void {
    this.isUpdate = false;
    this.showLoading = true;

    // Carrega o registro pelo ID
    this.activatedRoute.params.subscribe(pars => {
      this.currentId = pars['id'];

      // Se nao tiver o ID definido sera um CREATE
      if (this.currentId === undefined) {
        this.isUpdate = false;
        this.cTitle = 'Inclusão de Idioma';
      } else {
        this.isUpdate = true;
        this.cTitle = 'Alteração de Idioma';
      }

      // Atualiza o breadcrumb de acordo com o tipo de edicao
      this.breadcrumb = {
        items: [
          { label: 'Home', action: this.beforeRedirect.bind(this) },
          { label: 'Idiomas', action: this.beforeRedirect.bind(this) },
          { label: this.cTitle }
        ]
      };

      // Se for uma alteracao, busca o registro a ser alterado
      if (this.isUpdate) {
        this.service.getById(this.currentId).subscribe(resp => {
          Object.keys(resp).forEach((key) => this.record[key] = resp[key]);

          // Em alteracao temos que receber o registro para depois buscar a lista de campos
          this.getMetadata();
        });
      } else {
        // Se for create, pega a lista de campos
        this.getMetadata();
      }
    });
  }

  // Retorna a lista de campos
  private getMetadata() {
    let fieldList: Array<any> = [];

    // Carrega a lista de campos, trabalhando com um cache da lista de campos
    fieldList = this.service.getFieldList(this.isUpdate);
    if (fieldList === null || fieldListthis.fields.length === 0) {
          this.service.getMetadata().subscribe(respdata => {
            this.service.setFieldList(respfields = data['items']);
        this.fields   = this.service.getFieldListsetFieldList(this.isUpdatefields);
            this.showLoading = false;
          });
        }
 else {
      this.fieldsshowLoading = fieldList;
      this.showLoading = false;
    } false;
      });
    });
  }

  // Redireciona quando clicar no botao Edit
  public editClick(): void {
    this.route.navigate(['/idiomas', 'edit', this.currentId]);
  }

  // Redireciona viaquando breadcrumb
clicar no private beforeRedirect(itemBreadcrumbLabel) {botao Voltar
  public  if (this.formEdit.valid) {
  goBackClick(): void {
    this.route.navigate(['/idiomas']);
    } else {
      this.poDialog.confirm({
}

06. VALIDAÇÃO DE COMPONENTES

Para os itens a seguir, são apresentados algumas formas de interação com os componentes presentes na interface, bem como possíveis validações sobre os mesmos. 

Esconder ou visualizar os campos


Como a geração da tela dinâmica é automática, para esconder determinados campos basta setar o atributo visible para FALSE na montagem do JsonObject de retorno do metadados. 

Bloco de código
languagejs
titleEsconder campos na interface
linenumberstrue
collapsetrue
... 
    ASSIGN jObj =  title: `Confirma o redirecionamento para ${itemBreadcrumbLabel}`,NEW JsonObject().
    jObj:add('property', 'codDialet').
    jObj:add('label', 'Dialeto').
    message: `Existem dados que não foram salvos ainda. Você tem certeza que quer sair ?`,
        confirm: () => this.route.navigate(['/'])
      });
    }
  }

  // Grava o registro quando clicado no botao Salvar
  public saveClick(): void {
    this.showLoading = true;
    if (this.isUpdate) {
      // Altera um registro ja existente
      this.service.update(this.currentId, this.record).subscribe(resp => {
        this.poNotification.success('Idioma alterado com sucesso');
        this.showLoading = false;
        this.route.navigate(['/idiomas']);
      });
    } else {
      // Cria um registro novo
      this.service.create(this.record).subscribe(resp => {
        this.poNotification.success('Idioma criado com sucesso');
        this.showLoading = false;
        this.route.navigate(['/idiomas']);
      });
    }
  }

  // Cancela a edicao e redireciona ao clicar no botao Cancelar
  public cancelClick(): void {
    this.poDialog.confirm({
      title: 'Confirma cancelamento',
      message: 'Existem dados que não foram salvos ainda. Você tem certeza que quer cancelar ?',
      confirm: () => this.route.navigate(['/'])
    });
  }
}

Detalhe:

Esta tela apresenta os detalhes de um registro de Idioma, com suas customizações.

Bloco de código
languagexml
titleDetalhe: idioma-detail.component.html
linenumberstrue
collapsetrue
<po-loading-overlay
  [hidden]="!showLoading">
</po-loading-overlay>

<po-page-detail
  [p-title]="cTitle"
  [p-breadcrumb]="breadcrumb"
  (p-edit)="editClick()"
  (p-back)="goBackClick()">
  <po-dynamic-view 
    [p-fields]="fields"
    [p-value]="record">
  </po-dynamic-view>
</po-page-detail>
jObj:add('visible', FALSE). // <- Remove o item da tela de todos seus correspondentes (Form, View, Table)
    jObj:add('required', TRUE).
    jObj:add('type', JsonAPIUtils:convertAblTypeToHtmlType('character')).
    jObj:add('gridColumns', 6).
    jAList:add(jObj).
...


Validação de componentes na interface

Uma boa prática em desenvolvimento de telas é a validação de alguns campos na própria interface, cujo intuito é reduzir requisições desnecessárias ao 'Back-End'. As funcionalidades apresentadas a seguir podem ser utilizadas conjunto com a validação do próprio Form ([p-disable-submit]="formEdit.form.invalid"), no qual pode desabilitar o botão de confirmação enquanto houver campos inválidos.

Utilização do pattern (RegEx)

Para a validação de campos textos, pode ser utilizado o atributo pattern qualquer expressão regular, caso não atenda ao RegEx, uma mensagem de erro definida em errorMessage é apresentada em tela. 

Bloco de código
languagejs
titleUtilização de pattern
linenumberstrue
collapsetrue
... 
    ASSIGN jObj = NEW JsonObject().
    jObj:add('property', 'testeValidacaoRegEx').
    jObj:add('label', 'Teste Validação RegEx').
    jObj:add('gridColumns', 6).
    jObj:add('pattern', "[0-9]~{2~}"). // <- Validacao RegEx
    jObj:add('errorMessage', 'Obrigatório mínimo 2 números consecutivos.').
    jAList:add(jObj).
...

Utilização de limites em numeração

Com a utilização dos atributos minValue e maxValue, é possível efetuar a restrição de períodos da numeração que pode ser utilizado em conjunto com o type para restringir a digitação em somente números. Caso houver números inválidos, a mensagem definida em errorMessage é apresentada na tela.

Bloco de código
languagejs
titleUtilização intervalo de valores
linenumberstrue
collapsetrue
... 
    ASSIGN jObj = NEW JsonObject().
    jObj:add('property', 'numberValidate').
    jObj:add('label', 'Somente números').
    jObj:add('visible', TRUE).
    jObj:add('required', FALSE).
    jObj:add('minValue', 1).
    jObj:add('maxValue', 9).
    jObj:add('errorMessage', 'Somente números de 1 a 9'). // <- Mensagem de erro 1-9
    jObj:add('type', JsonAPIUtils:convertAblTypeToHtmlType('integer')). // <- Restringe a digitacao somente numeros
    jObj:add('gridColumns', 6).
    jAList:add(jObj).
...

Utilização de máscaras para os campos

Quando é definida uma máscara mask, ocorre a restrição de digitação no próprio campo. Para o exemplo abaixo, é permitido digitar somente números e ao efetuar a digitação, a máscara será aplicada automaticamente.

Bloco de código
languagejs
titleUtilização de máscaras
linenumberstrue
collapsetrue
...   
    ASSIGN jObj = NEW JsonObject().
    jObj:add('property', 'numberRangeValidate').
    jObj:add('label', 'Aplicação de máscara CPF').
    jObj:add('mask', '999.999.999-99').  // <-- Mascara CPF
    jObj:add('visible', TRUE).
    jObj:add('required', FALSE).
    jObj:add('type', JsonAPIUtils:convertAblTypeToHtmlType('character')).
    jObj:add('gridColumns', 6).
    jAList:add(jObj).
...


07. VALIDAÇÃO DE FORMULÁRIOS

O quê deve ser alterado no componente PO-DYNAMIC-FORM

Para validarmos um formulário, temos que configurar primeiro o nosso componente po-dynamic-form para ficar apto a enviar as ocorrências de validações. Para isso temos que especificar no componente po-dynamic-form a tag p-validate, onde informamos a URL que fará a validação do form, neste exemplo será "/api/trn/v1/idiomas/validateForm".

Bloco de código
languagejs
titleTag p-validate no po-dynamic-form
Bloco de código
languagejs
titleDetalhe: idioma-detail.component.ts
linenumberstrue
collapsetrue
import  <po-dynamic-form
    #formEdit
    p-auto-focus="string"
    [p-fields]="fields"
    p-validate="/api/trn/v1/idiomas/validateForm"
    [p-value]="record">
  </po-dynamic-form>


JSon que recebemos da tela HTML

O componente PO-DYNAMIC-FORM, quando ocorre alguma alteração em seus campos, no LEAVE do campo, ele enviará um JSon com o seguinte formato para o back-end:

TagTipoDescrição
propertyCharacterContêm o nome do campo que houve a alteração para ser validado.
valueJSonObjectContêm uma tag para cada campo da tela contendo os valores atuais dos campos.


A cada campo que for alterado e ocorrer um LEAVE, será enviado pelo PO-UI um Json que contém o campo que teve o seu valor alterado junto com todos os valores dos demais campos da tela HTML, conforme o exemplo abaixo:

Bloco de código
languagejs
titleJSon enviado pelo HTML para validação dos campos
linenumberstrue
collapsetrue
{
    "property": "codAcoes",
    "value": {
        "codIdiomPadr": "01 Português",{ Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { PoBreadcrumb } from '@po-ui/ng-components';

import { IdiomaService } from './../resources/idioma.service';

@Component({
  selector: 'app-idioma-detail',
  templateUrl: './idioma-detail.component.html',
  styleUrls: ['./idioma-detail.component.css']
})

export class IdiomaDetailComponent implements OnInit {
  // definicao das variaveis utilizadas
  public cTitle = 'Detalhe do Idioma';
  public currentId: string;
  public fields: Array<any> = [];
  public record = {};
  public showLoading = false;

  public readonly breadcrumb: PoBreadcrumb = { items: [
      { label: 'Home', link: '/' } "codIdioma": "12345678",
      { label: 'Idiomas', link: '/idiomas' },
 "desIdioma": "12345678901234567890",
       { label"hraUltAtualiz": 'Detail' } ]"",
  };

  // construtor com os servicos necessarios"datUltAtualiz": null,
  constructor(
    private service: IdiomaService,
    private activatedRoute: ActivatedRoute,
 "id": 6,
     private route   "codAcoes": Router"FocoDesIdioma"
  ) { }
}


JSon que teremos que retornar para o PO-DYNAMIC-FORM

As validações do formulário, aguardam o seguinte formato de JSon:

TagTipoDescrição
valueJSonObjectContêm uma tag que representa o nome do campo em tela e o seu novo valor. Se não for especificado um novo valor, não é necessario adicionar a tag referente ao campo
fieldsJSonArrayContêm uma lista de campos com as suas propriedades que serão alteradas. Se não for alterada nenhuma propriedade de nenhum campo, não é necessário informar essa tag.
focusCharacterContêm o campo que receberá o foco ao voltar para a tela HTML.
_messagesJSonArrayContêm uma lista de mensagens "de erro" que deverão ser apresentadas ao voltar para o HTML.


Para retornar as informações para o PO-UI, temos que devolver o seguinte JSon:

Bloco de código
languagejs
titleJSon de retorno do backend para o HTML
linenumberstrue
collapsetrue
{    
    value: {
      desIdioma: 'teste de escrita',
      hraUltAtualiz: '17:18:19'
    },
    fields: [
      {
  // load do componente
  public ngOnInit(): void {
    this.activatedRoute.params.subscribe(pars => {
      this.showLoading = true;

      // carrega o registro pelo ID
      this.currentId = pars['id'];
      this.service.getById(this.currentId).subscribe(resp => {
        Object.keys(resp).forEach((key) => this.record[key] = resp[key]);

        // carrega a lista de campos somente apos receber o registro a ser apresentado
        this.fields = this.service.getFieldList(false);property: 'codCpfCnpj', 
        if (this.fields === null || this.fields.length === 0) {mask: '99.999.999/9999-99' 
      }
    ],
      this.service.getMetadata().subscribe(data => {
  focus: 'hraUltAtualiz',
    _messages: [ 
    this.fields = data['items'];
  { 
         this.service.setFieldList(this.fields);
   code: '01', 
       this.showLoading = false;
   message: 'Mensagem do erro que aconteceu', 
 });
        }
   detailedMessage: 'detalhes do erro acontecido' this.showLoading
 = false;
      }); 
    });]
  }

  // Redireciona quando clicar no botao Edit
  public editClick(): void {
    this.route.navigate(['/idiomas', 'edit', this.currentId]);
  }

  // Redireciona quando clicar no botao Voltar
  public goBackClick(): void {
    this.route.navigate(['/idiomas']);
  }
}

06. VALIDAÇÃO DE COMPONENTES

Para os itens a seguir, são apresentados algumas formas de interação com os componentes presentes na interface, bem como possíveis validações sobre os mesmos. 

Esconder ou visualizar os campos

Como a geração da tela dinâmica é automática, para esconder determinados campos basta setar o atributo visible para FALSE na montagem do JsonObject de retorno do metadados. 

Bloco de código
languagejs
titleEsconder campos na interface
linenumberstrue
collapsetrue
... 
    ASSIGN jObj = NEW JsonObject().
    jObj:add('property', 'codDialet').
    jObj:add('label', 'Dialeto').
    jObj:add('visible', FALSE). // <- Remove o item da tela de todos seus correspondentes (Form, View, Table)
    jObj:add('required', TRUE).
    jObj:add('type', JsonAPIUtils:convertAblTypeToHtmlType('character')).
    jObj:add('gridColumns', 6).
    jAList:add(jObj).
...

Validação de componentes na interface

Uma boa prática em desenvolvimento de telas é a validação de alguns campos na própria interface, cujo intuito é reduzir requisições desnecessárias ao 'Back-End'. As funcionalidades apresentadas a seguir podem ser utilizadas conjunto com a validação do próprio Form ([p-disable-submit]="formEdit.form.invalid"), no qual pode desabilitar o botão de confirmação enquanto houver campos inválidos.

Utilização do pattern (RegEx)

Para a validação de campos textos, pode ser utilizado o atributo pattern qualquer expressão regular, caso não atenda ao RegEx, uma mensagem de erro definida em errorMessage é apresentada em tela. 

Bloco de código
languagejs
titleUtilização de pattern
linenumberstrue
collapsetrue
... 
    ASSIGN jObj = NEW JsonObject().
    jObj:add('property', 'testeValidacaoRegEx').
    jObj:add('label', 'Teste Validação RegEx').
    jObj:add('gridColumns', 6).
    jObj:add('pattern', "[0-9]~{2~}"). // <- Validacao RegEx
    jObj:add('errorMessage', 'Obrigatório mínimo 2 números consecutivos.').
    jAList:add(jObj).
...

Utilização de limites em numeração

Com a utilização dos atributos minValue e maxValue, é possível efetuar a restrição de períodos da numeração que pode ser utilizado em conjunto com o type para restringir a digitação em somente números. Caso houver números inválidos, a mensagem definida em errorMessage é apresentada na tela.

Bloco de código
languagejs
titleUtilização intervalo de valores
linenumberstrue
collapsetrue
... 
    ASSIGN jObj = NEW JsonObject().
    jObj:add('property', 'numberValidate').
    jObj:add('label', 'Somente números').
    jObj:add('visible', TRUE).
    jObj:add('required', FALSE).
    jObj:add('minValue', 1).
    jObj:add('maxValue', 9).
    jObj:add('errorMessage', 'Somente números de 1 a 9'). // <- Mensagem de erro 1-9
    jObj:add('type', JsonAPIUtils:convertAblTypeToHtmlType('integer')). // <- Restringe a digitacao somente numeros
    jObj:add('gridColumns', 6).
    jAList:add(jObj).
...

Utilização de máscaras para os campos

Quando é definida uma máscara mask, ocorre a restrição de digitação no próprio campo. Para o exemplo abaixo, é permitido digitar somente números e ao efetuar a digitação, a máscara será aplicada automaticamente.

}


Para utilizarmos a UPC de customização, tivemos que encapsular o JSon recebido no back-end, dentro da procedure pValidateForm, e tambem o JSon a ser enviado para a tela HTML, conforme o exemplo abaixo:

Bloco de código
languagejs
titleJSon empacsulado para UPC de Validação de Formulários
linenumberstrue
collapsetrue
// encapsulamos o retorno para enviar para a UPC
oObj = NEW JsonObject().
oObj:add("property", cProp).
oObj:add("originalValues", oValue).
oObj:add("return", oRet).

// Realiza a chamada da UPC Progress
{include/i-epcrest.i &endpoint=validateForm &event=validateForm &jsonVar=oObj}    

// obtem o retorno customizado
oRet = oObj:getJsonObject("return").


Neste nosso exemplo, nós dividimos o JSon a ser enviado para UPC em três partes, que são:

TagTipoDescrição
propertyCharacterComtêm o nome do campo que esta sendo validado.
originalValuesJSonObjectContêm as tags com os nomes dos campos da tela HTML e os seus respectivos valores atuais.
returnJSonObjectContêm um JSonObject com que será retornado para o HTML e que poderá ser customizado na UPC. Tudo que for customizado deverá estar dentro desta tag.


Exemplo de JSon recebido pela UPC:

Bloco de código
titleJSon recebido na UPC para Validação do Formulário
linenumberstrue
collapsetrue
{ 
    property: 'codAcao',
    originalValues: {
        "codIdiomPadr": "01 Português",
        "codIdioma": "12345678",
        "desIdioma": "12345678901234567890",
        "hraUltAtualiz": "",
        "datUltAtualiz": null,
        "id": 6,
        "codAcoes": "FocoDesIdioma"
    },
    return: {
        value: {
            desIdioma: 'teste de escrita',
            hraUltAtualiz: '17:18:19'
        },
        fields: [
            {
                property: 'codCpfCnpj', 
                mask: '99.999.999/9999-99' 
            }
        ],
        focus: 'hraUltAtualiz',
        _messages: [ 
            { 
                code: '01', 
                message: 'Mensagem do erro que aconteceu', 
                detailedMessage: 'detalhes do erro acontecido' 
            } 
        ]
    }
}
Bloco de código
languagejs
titleUtilização de máscaras
linenumberstrue
collapsetrue
...   
    ASSIGN jObj = NEW JsonObject().
    jObj:add('property', 'numberRangeValidate').
    jObj:add('label', 'Aplicação de máscara CPF').
    jObj:add('mask', '999.999.999-99').  // <-- Mascara CPF
    jObj:add('visible', TRUE).
    jObj:add('required', FALSE).
    jObj:add('type', JsonAPIUtils:convertAblTypeToHtmlType('character')).
    jObj:add('gridColumns', 6).
    jAList:add(jObj).
...











07. FACILITADORES PROGRESS

...