Contents tagged with ExtJS

  • Problema de rolagem de HTML em iframe no iOS

    21/06/2016

    O "Causo"

    Recentemente tive um problema que, consultando vários fóruns, confirmei que realmente existe uma situação única de problema de rolagem de conteúdo HTML em um iframe em qualquer browser executado no iOS.


    Como é que funciona?

    Os browsers em dispositivos móveis adequam a rolagem de conteúdo com aquela forma elástica que ocorre quando a gente segura a tela com o dedo e arrasta para cima ou para baixo e então soltando o conteúdo vai rolando na direção que soltou sozinho até parar.

    Nessa condição a scrollbar padrão, aquela feiura antiquada, dá lugar a outra, e o comportamento de clique muda também para se comportar da maneira citada, toque, segura e solta.

    Essa mudança de visual e funcionamento difere da execução em desktop em que aparece a barra de rolagem e o conteúdo rola apenas ao clicar na barra lateral ou com teclas de atalho (page down, up e etc), e se segurar o cursor do mouse com o clique em algum ponto irá marcar texto (alguns browser permitem mudar esse comportamento para tipo o estilo mobile).

    Sim, mas e daí?

    Esbarrei pelo problema usando o Ext.Net (ExtJS), na verdade não é culpa dele, mas sim do iframe em que o conteúdo HTML é embutido. O funcionamento do sistema era abrir rotas/URLs em janelas dentro da principal simulando o funcionamento de janelas do Windows por exemplo, mas para isso a parte interna das janelas é um iframe.

    O fato apenas ocorre no iOS, em qualquer Android funciona, no caso não havia a mudança para o estilo mobile, continuava o HTML com rolagem estilo desktop.

    Então depois de algumas pesquisas em fóruns, vários indicavam a pequena iscrolljs.com.

    Basicamente o funcionamento é o de se colocar uma DIV dentro de outra DIV, cada uma com o seu devido CSS aplicado (tem tudo no site), e no onLoad() da página instanciar um objeto da iScroll (bastante sugestivo o prefixo do nome).

    Na minha aplicação passei por mais problemas, pois trabalhando com o ExtJS vi que não poderia utilizar os Ext.Panels padrões pela injeção de HTML indesejado, cheguei até a testar mas não funcionou, de qualquer maneira consegui contornar usando o iScroll na forma mais simples, pelos próprios exemplos do site dele.

    Eu cheguei a ver algumas soluções baseadas em ExtJS mas achei muito, mas muito complexas, exageradamente...criação de componentes com herança, eventos e etc, muita ladainha para uma necessidade mais direta de aplicar, e olha que no meu caso eu tinha alguns poréns a mais:

    1. Store é atualizada disparando evento DataChanged...
    2. ...DataView atrelada à Store renderiza conteúdo...
    3. ...captura do HTML renderizado na DataView...
    4. ...injeção do HTML dentro da DIV mais interna usada pelo iScroll.

    Só serve para isso?

    Não!

    Existem algumas outras funções bastante interessantes como zoom, scroll infinito (carga de HTML por demanda) e outras, que um dia irei explorar, o importante é saber que há como fazer e o iScroll é a solução atual mais simples e leve de aplicar.

    Mas lembre-se!

    Apenas para ficar ciente, o comportamento do scroll de conteúdo passará a ser "estilo" mobile mesmo em browser no desktop, ou seja, para rolar tem-se que clicar, segurar e jogar o cursor para uma direção, prático como se utiliza um tablet e celular, mas pode ser que alguns usuários estranhem no desktop.


  • WebAPI e retorno de campo DateTime - Request Ajax trazendo valor em formato texto ao invés de objeto tipo DateTime

    16/06/2016

    Detalhando a Situação

    Recentemente passei por um problema de programação que já havia passado antes, mas contornado "via código".

    O problema não é incomum e depende exclusivamente de como você precisa tratar tal tipo de conteúdo em sua View.

    Considere o seguinte fluxo (sem entrar em muitos detalhes): 

    1. View faz o request Ajax a um Método no Controller WebAPI.
    2. Método processa e retorna um registro ou lista do Domínio.
    3. Método converte dados do Domínio para DTO.
    4. Método retorna os dados para a View.

    Uma classe DTO é uma simplificação da classe de Domínio e é usada como container para serialização no retorno dos valores/registros lidos do banco de dados para a View que fez a requisição.

     

    O Problema

    O método da WebAPI retorna para a View usando o método Request.CreateResponse().

    No meu caso utilizo ExtJS como framework como client/browser, então os requests avulsos da view são feitos com a função Ext.Ajax.request(). Não testei usando jQuery, mas creio que não haja diferença.

    Quando um request é feito as propriedades do tipo DateTime retornam o valor como texto no seguinte formato: 2014-01-01T00:00:00. Só que para ser trabalhando na view de maneira direta, ou seja, cálculos, componentes que só recebem valor data/hora (ou data), é preciso que esse texto seja convertido para um objeto de data Javascript, algo como Date {Mon Jan 01 2014 00:00:00 GMT-0200}.

    Considerando um request feito por uma Store do Ext.Net (abstração do ExtJS), se apontamos para o mesmo método no controller da WebAPI, e configurado o Record Field da Store com algo assim: 

    <ext:RecordField Name="PropriedadeDataNoDto" Type="Date" DateFormat="yyyy-MM-ddTh:i:s" />


    Desta maneira a view consegue fazer com que o retorno seja o esperado, um objeto data/hora.

     

     

    A Solução

    A solução definitiva que encontrei, a que implica que todas as requisições no nível de WebAPI fiquem corretas, está relacionada a configurar um "JsonFormatter" aplicado na serialização do conteúdo, mas não encontrei nenhuma solução para a minha necessidade, nem mesmo os "formatters" padrões tipo ISO e outros, então tive que adequar uma.

    Criei uma classe formatter chamada JavaScriptDateTimeConverter (atenção que existe uma classe com mesmo nome).

    public class JavaScriptDateTimeConverter : DateTimeConverterBase
    {
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.Value is DateTime)
            {
                return DateTime.Parse(reader.Value.ToString());
            }
            else
            {
                return reader.Value;
            }
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            if (value == null)
            {
                writer.WriteNull();
            }
            else if (value is DateTime)
            {
                DateTime dateTime = (DateTime)value;
    
                // retornará a data no padrão: new Date(year, month, day, hours, minutes, seconds, milliseconds);
                writer.WriteStartConstructor("Date");
                writer.WriteValue(dateTime.Year);
                writer.WriteValue(dateTime.Month - 1);
                writer.WriteValue(dateTime.Day);
                writer.WriteValue(dateTime.Hour);
                writer.WriteValue(dateTime.Minute);
                writer.WriteValue(dateTime.Second);
                writer.WriteEndConstructor();
            }
            else
            {
                writer.WriteValue(value.ToString());
            }
        }
    }

    E em WebApiConfig.cs a lógica para que a classe seja utilizada.

    public static class WebApiConfig    {
      public static void Register(HttpConfiguration config)
      {
        ...
        config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new SuaNamespace.JavaScriptDateTimeConverter());
        ...
      }
    }

    Um ponto que não avaliei, pode ser que fazendo um request com algum parâmetro a mais o retorno de propriedades/campos DateTime ocorra como o esperado, mas infelizmente não pude testar, de qualquer não encontrei em nenhum artigo referência a essa possibilidade.