domingo, 4 de dezembro de 2016

Validação de campo em formulário

Em formulários para sinalizar para o usuário que o campo é inválido e o porque normalmente coloco uma borda vermelha no input e / ou um x vermelho ao lado, com tooltip com o motivo nos dois.

Um exemplo:

<div ng-class="{'has-error' : (formCrud.$submitted && formCrud.email.$error.required) || formCrud.email.$error.email}">
    <label>E-mail</label>
    <input type="email" id="email" name="email" class="campo-maior text-lowercase" ng-model="paciente.email" required
           uib-tooltip="{{(formCrud.$submitted && formCrud.email.$error.required ? MENSAGEM.OBRIGATORIO : MENSAGEM.FORMATO_INCORRETO)}}" 
           tooltip-enable="(formCrud.$submitted && formCrud.email.$error.required) || formCrud.email.$error.email" />
    <span ng-show="(formCrud.$submitted && formCrud.email.$error.required) || formCrud.email.$error.email
          class="glyphicon glyphicon-remove text-danger" 
          uib-tooltip="{{(formCrud.$submitted && formCrud.email.$error.required ? MENSAGEM.OBRIGATORIO : MENSAGEM.FORMATO_INCORRETO)}}"></span>
    <span ng-show="!formCrud.email.$error.required && !formCrud.email.$error.email" class="glyphicon glyphicon-ok text-success"></span>
</div>


Mas a repetição em destaque me incomodava (code smells), se precisar alterar a condição teria alguns pontos a fazer.
Pensava em criar uma diretiva e criar watchers quando necessário e variáveis para controle, mas não me parecia ainda opção adequada por ainda achar burocrática.

Então percebi que podia criar variáveis no html.

<div ng-class="{'has-error' : emailInvalid}">
    <label>E-mail</label>
    <input type="email" id="email" name="email" class="campo-maior text-lowercase" ng-model="paciente.email" required
           uib-tooltip="{{mensagemEmail}}" tooltip-enable="emailInvalid" />
    <span ng-show="emailInvalid = (formCrud.$submitted && formCrud.email.$error.required) || formCrud.email.$error.email
          class="glyphicon glyphicon-remove text-danger" 
          uib-tooltip="{{mensagemEmail = (formCrud.$submitted && formCrud.email.$error.required ? MENSAGEM.OBRIGATORIO : MENSAGEM.FORMATO_INCORRETO)}}"></span>
    <span ng-show="!formCrud.email.$error.required && !formCrud.email.$error.email" class="glyphicon glyphicon-ok text-success"></span>
</div>


quinta-feira, 10 de novembro de 2016

IE: SCRIPT7002: XMLHttpRequest: Erro de Rede 0x2f76, Não foi possível concluir a operação. Erro: 00002f76

Numa aplicação usando AngularJS me deparei com um erro muito estranho no Internet Explorer o  SCRIPT7002: XMLHttpRequest: Erro de Rede 0x2f76, Não foi possível concluir a operação. Erro: 00002f76, nos demais navegadores funcionava ok.

Analisando verifiquei que só acontecia quando retornar o HTTP Status Code 302 - Found, troquei para para 200 - OK e funcionou corretamente.

Coisas do IE.




IE: SCRIPT7002: XMLHttpRequest: Erro de Rede 0x2f76, Não foi possível concluir a operação. Erro: 00002f76

Numa aplicação usando AngularJS me deparei com um erro muito estranho no Internet Explorer o SCRIPT7002: XMLHttpRequest: Erro de Rede 0x2f76, Não foi possível concluir a operação. Erro: 00002f76, nos demais navegadores funcionava ok.

Analisando verifiquei que só acontecia quando retornar o HTTP Status Code 302 - Found, troquei para para 200 - OK e funcionou corretamente.

Coisas do IE.




sábado, 15 de outubro de 2016

Erro ao criar DataSource PostgreSQL em Domain Admin Console do GlassFish

Num projeto usando GlassFish preciso usar um recurso JDBC para acessar o PostgreSQL, então na console em Resources > JDBC > JDBC Resources ao dar new já recebo um class java.lang.RuntimeException, e na opção JDBC Connection Pools a primeira tela abre mas ao ir para a segunda para configurar o acesso ao banco recebo java.lang.IllegalStateException: getOutputStream() has already been called for this response.

Na console então peguei o JDBC Connection Pools > SamplePool e alterei com os dados de minha conexão, um ponto importante é trocar o Datasource Classname para org.postgresql.ds.PGPoolingDataSource. Como a console não permite alterar o nome fui direto no arquivo [diretório do GlassFish]/glassfish/domains/domain1/config/domain.xml.

Também foi necessário colocar o .jar do PostgreSQL em [diretório do GlassFish]/glassfish/domains/domain1/lib.

Isto acontece na versão 4.1.1 na 4.1 isso não acontece.

Erro ao criar DataSource PostgreSQL em Domain Admin Console do GlassFish

Num projeto usando GlassFish preciso usar um recurso JDBC para acessar o PostgreSQL, então na console em Resources > JDBC > JDBC Resources ao dar new já recebo um class java.lang.RuntimeException, e na opção JDBC Connection Pools a primeira tela abre mas ao ir para a segunda para configurar o acesso ao banco recebo java.lang.IllegalStateException: getOutputStream() has already been called for this response.

Na console então peguei o JDBC Connection Pools > SamplePool e alterei com os dados de minha conexão, um ponto importante é trocar o Datasource Classname para org.postgresql.ds.PGPoolingDataSource. Como a console não permite alterar o nome fui direto no arquivo [diretório do GlassFish]/glassfish/domains/domain1/config/domain.xml.

Tombém foi necessário colocar o .jar do PostgreSQL em [diretório do GlassFish]/glassfish/domains/domain1/lib.

Erro ao criar DataSource PostgreSQL em Domain Admin Console do GlassFish

Num projeto usando GlassFish preciso usar um recurso JDBC para acessar o PostgreSQL, então na console em Resources > JDBC > JDBC Resources ao dar new já recebo um class java.lang.RuntimeException, e na opção JDBC Connection Pools a primeira tela abre mas ao ir para a segunda para configurar o acesso ao banco recebo java.lang.IllegalStateException: getOutputStream() has already been called for this response.

Na console então peguei o JDBC Connection Pools > SamplePool e alterei com os dados de minha conexão, um ponto importante é trocar o Datasource Classname para org.postgresql.ds.PGPoolingDataSource. Como a console não permite alterar o nome fui direto no arquivo [diretório do GlassFish]/glassfish/domains/domain1/config/domain.xml.

Tombém foi necessário colocar o .jar do PostgreSQL em [diretório do GlassFish]/glassfish/domains/domain1/lib.

sexta-feira, 9 de setembro de 2016

Layout no Google Chrome

Numa aplicação usando AngularJS e Bootstrap, tenho no topo o menu e no corpo da página os dados do item selecionado no menu que normalmente são botões de ação (Inserir, Editar, etc) e filtros e abaixo a lista com os itens do cadastro.

Usei o margin-top, para posicionar a barra de ações e filtros entre o menu e a lista de itens do cadastro de forma fixa (position: fixed). No firefox funciona ok, mas para minha surpresa no Google Chrome tenho fica atrás do menu.

Entre algumas soluções encontrei o margin-top específico para Google Chrome nesse link

Também existe a opção de algo como:
/* Chrome 22-28 */
@media screen and(-webkit-min-device-pixel-ratio:0) {
    .cssclass {
        margin-top: 170px;
    }
}

/* Chrome 28 and newer */
@supports (-webkit-appearance:none) {
    .cssclass {
        margin-top: 170px;
    }
}

Infelizmente não guardei o link desse para colocar os créditos aqui.

Mas por querer usar sempre o padrão não gostei muito das alternativas, tentei o padding-top mas no meu caso não encontrei um valor que ficasse bom para todos os navegadores.

O top, diferentemente do padding-top achei um valor que ficou bom para todos os navegadores mesmo ficando levemente diferente entre o Google Chrome e os outros navegadores.


sábado, 9 de julho de 2016

Gateway de pagamento on-line

Fiz um gateway de pagamento on-line com cartão de crédito para meu cliente Lexsis, produto que está em produção desde 2014.

De fácil uso via requisições HTTPS / RESTful pode ser usado por qualquer aplicação em qualquer plataforma.

Caso precisem desse recurso em suas apps ou sites só entrar em contato com a Lexsis.

Alguns clientes que estão usando:
E também hotéis e pousadas que usam via portal de reservas on-line que fiz com AngularJS e Bootstrap:

quarta-feira, 6 de abril de 2016

Erro no Jasper referente pasta temp

Estava tendo um problema que acontecia local mas não nos servers, ao rodar um report feito em JasperReports dava o erro java.lang.NoClassDefFoundError : Could not initialize class net.sf.jasperreports.engine.util.JRStyledTextParser, procurando na web encontrei algumas possíveis soluções, um link bem completo com várias possibilidades é esse: jasper reports - Could not initialize class net.sf.jasperreports.engine.util.JRStyledTextParser - Stack Overflow.

Mas em resumo, para mim a solução foi criar a pasta temp no tomcat, como o link acima comenta o JasperReports precisa criar vários arquivos temporários.

terça-feira, 23 de fevereiro de 2016

Verificação de internet ativa para carregar libs JS remotas ou locais

Normalmente libs JS fornecem um caminho CDN e é uma boa prática usá-la porque como o browser faz cache do que baixa se outra aplicação usar a mesma lib o seu carregamento será mais rápido já que esta lib já está no cache do browser.

E hoje normalmente é mais difícil ficar sem internet, mas para evitar contratempos, ainda mais se você trabalha remoto com algum deslocamento é bom verificar se a internet está ativa e pegar as libs do CDN ou local.

Segue abaixo algumas sugestões variando conforme as linguagens de programação utilizadas:

PHP:
$internetON = @fsockopen("www.google.com", 80);

JS:
Algumas libs como jQuery e Angular criam um objeto que pode ser verificado. Esta metodologia não gosto muito porque se tiver que carregar um CSS do bootstrap por exemplo irei ter que tentar carregar a lib js na tab head e depois o css, sendo que, a boa prática recomenda carregar os CSS na tag head e os JS antes do fechamento da tag body.

<script src="http://code.jquery.com/jquery-1.11.3.min.js"/>
<script>
var internetON = (window.jQuery !== undefined);
if (internetON) {
      document.write('<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" >');
} else {
      document.write('<link rel="stylesheet" type="text/css" href="css/libs/bootstrap-3.3.6-dist/css/bootstrap.min.css">');
}
</script>

JSP / JAVA:
ApplicationUtil.java
    public static boolean internetON() {
        try {
            URL url = new URL("http://www.google.com");
            HttpURLConnection urlConnect = (HttpURLConnection)url.openConnection();
            Object objData = urlConnect.getContent();
        } catch (Exception e) { 
            return false;
        }
        
        return true;
    }

JSP
<%@ page import="br.com.lexsis.improvement.ApplicationUtil" %>
<%
    boolean internetON = false;
    if (request.getLocalName().equalsIgnoreCase("localhost")) {
        internetON = ApplicationUtil.internetON();
    } else {
        internetON = true;
    }
%>
...
<% if (internetON) { %>
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<% } else { %>
<link rel="stylesheet" type="text/css" href="js/libs/bootstrap-3.3.6-dist/css/bootstrap.min.css">
<% } %>

JS / JAVA / RESTfull:
Aqui seria uma mescla do JS com JSP / JAVA. Fazer o load do AngularJS e fazer uma requisição RESTful para verificar se a internet está ON, se tiver faz a carga dos demais CSS e JS.


quinta-feira, 18 de fevereiro de 2016

Problema em decode JSON de um PUT em PHP + AngularJS

Numa aplicação PHP+AngularJS estou usando RESTful e aí no POST e PUT o decode estou fazendo da seguinte forma:

$params = json_decode(file_get_contents("php://input"));

no meu ambiente local (XAMPP e PHP versão 5.6.14) funciona 100%.

Já no server da DialHost que o PHP tem a versão 5.5.30 o PUT não funciona, pois chega os dados originais e não os novos se alterar para POST e fazendo um update, o que não é o correto para RESTful, funciona.

Abri chamado com a DialHost que sugeriram usar 

parse_str(file_get_contents("php://input"), $params);

o que funcionou num exemplo de POST e PUT que criaram, mas para mim foi pior, o POST deixou de funcionar.

Olhando melhor o código vi que eu tinha duas linhas iguais com json_decode bem afastadas, deixei só uma e funcionou. Interessante que na minha máquina como comentei acima funciona 100% mas no server gerava problema com o PUT.

Fica a dica.

Vlw pessoal da DialHost pelo pronto atendimento.


terça-feira, 2 de fevereiro de 2016

Route com templateUrl dinâmico

Normalmente os atributos templatetemplateUrl que vemos nos exemplos por aí retornam uma string, mas também pode ser uma function que retorna uma string e recebe um parâmetro com todos os atributos colocados no path. Então pode-se ter o seguinte:

when('/transpextraform/:idEmpresa/:id', {
    templateUrl: function(params) { 
        return 'ag0001.php?id_empresa=' + params.idEmpresa + "&id=" + params.id;
    },
    controller: 'TranspExtraCtrl'
})

Saiba mais:

sábado, 30 de janeiro de 2016

Route + reload e ng-click com bind

Estou usando route numa aplicação AngularJS de um cliente que estou dando manutenção. Usando PHP, AngularJS e Bootstrap.
Ao clicar num link imaginei que iria chamar novamente o controller mas isso não acontece pois utiliza o cache, devido isso tive que pensar de outra forma.
Então, removi o a href e usei o ng-click chamando uma função controlando se o item clicado foi o último clicado e se for o caso fazer o reload, pois limpar o cache também não resolveu.

Rotina pronta, outra situação para contornar o ng-click não aceita muito bem bind, no html até aparece certo mas ao passar para a function vai com os {{. Então tive que usar o parâmetro adicional no html com os parâmetros e a function ler este atributo do elemento target. E um outro detalhe como tenho um img dentro de uma tag a, na function ainda tive que verificar os parâmetros no parent do target porque dependendo de onde clicasse ia a img e não a tag a, ficando assim o código;

HTML
<a id='botao' ng-click="loadOption('transpextraform', $event);" 
                 data-parametros="{{::idEmpresa}}/{{item.id}}" title='Alterar'>
<img class='img_manutencao' src='../img/bt_019.gif' alt='Alterar'> ALTERAR
</a>

JS
function getTargetEvent(event) {
    return event.target || event.srcElement;
}

app.service("appService", function($rootScope, $route, $location, $http) {
    $rootScope.opcaoCorrente = {opcao: "", parametros: ""};
    
    $rootScope.loadOption = function(opcao, $event) {
        var target = $(getTargetEvent($event));
        var parametros = target.attr("data-parametros");
        
        if (!parametros) {
            parametros = target.parent().attr("data-parametros");
        }

        if (opcao === $rootScope.opcaoCorrente.opcao 
&& parametros === $rootScope.opcaoCorrente.parametros) {
            $route.reload();
        } else {
            $rootScope.opcaoCorrente.opcao = opcao;
            $rootScope.opcaoCorrente.parametros = parametros;
            
            if (parametros) {
                $location.path("/" + opcao + "/" + parametros);
            } else {
                $location.path("/" + opcao);
            }
        }
    };
});

sexta-feira, 8 de janeiro de 2016

Upper em PHP com encode

Estou dando manutenção numa app onde os .php e o banco estão em iso-8859-1 em vez de utf-8. Alguns campos precisam gravar em upper então nos inputs usei um css text-transform: uppercase; e ao gravar um strtoupper mas para minha surpresa caracteres acentuados e ç não estava dando upper. 

Procurei por algo onde eu possa informar o encode, aí apareceu o mb_strtoupper onde o segundo parâmetro é o encode desejado e caso não seja informado será usado o da app.