Sistema com Login em Extjs 4 - MVC

by Hirashiki 29. August 2011 19:25

Acho que todos que usam a nova versão do ExtJs estão atrás de uma solução para implementar um sistema de login utilizando o MVC.

A maioria das soluções que eu vi não me agradaram muito. Apesar de serer totalmente funcionais, sempre em algum momento era necessário um "refresh" na página toda ou um redirecionamento para uma nova página.

Pensando neste assunto, e baseado em algumas informações dos tópicos Interface de Login no ExtJs4 e Chamar função de outro controlador criei um esquema para realizar o controle de sessão de uma aplicação e o controle das views sem refresh na página.

Este é um post onde é necessário um certo conhecimento sobre a nova estrutura do ExtJs versão 4 e sua arquitetura MVC. Para quem não

conhece ou deseja se aprofundar antes, recomendo ler MVC Architecture e Construindo um aplicativo com Ext 4 – Parte 1.

Então vamos lá!

Estrutura de Diretórios e arquivos

Esta é uma estrutura básica dos projetos que eu utilizo. Você pode pegar toda essa pasta e jogar em uma "htdocs" da vida que irá funcionar normalmente.

Criando a aplicação (app.js)

O arquivo app.js será a classe de inicialização do sistema:

 

/**
 *
 * Modelo de Login usando MCV
 * Desenvolvido por Ricardo Hirashiki
 * Publicado em: http://www.sitedoricardo.com.br
 * Data: Ago/2011
 *
 */
 
Ext.Loader.setConfig({
  enabled : true,
  paths   : {SampleApp:'app'}
});

        
Ext.application({
  name               : 'SampleApp',
  autoCreateViewport : true,
  paths              :    {'Ext.ux': 'app/ux'},
  requires           : ['Ext.ux.Initialization'],
  appFolder          : 'app',
  controllers        : ['Viewport'],
  enableRouter       : true,
  routes: {
    '/'           : 'viewport#index'        ,
    'login'       : 'authentication#index',
    'home'        : 'home#index'
  },
  launch: function() {
    var hideMask = function () {
      Ext.get('loading').remove();
      Ext.fly('loading-mask').animate({
        opacity : 0,
        remove  : true
      });
    };
    Ext.defer(hideMask, 250);
  }
});

 

 

Não existe a criação de nenhuma viewport, pois há a propriedade autoCreateViewport na linha 18 como true. Com esta propriedade, o ExtJs irá carregar o arquivo em view/Viewport.js.

Na linha 19 é mapeada a pasta para os plugins "Ext.ux" através da propriedade paths. Através do método requires eu informo a primeira classe dependente para este projeto: Ext.ux.Initialization declarada no arquivo Initialization.js (o Código se encontra mais abaixo do post).

Nas linhas 23 a 29 eu configuro os parâmetros utilizados pela classe Ext.ux.Router (Router.js). Definindo 3 "roteamentos":

  1. Ao acessar a "raiz" da aplicação ("/"), executo o método index do controller viewport;
  2. Ao acessar o alias "login", executo o método index do controller authentication;
  3. Ao acessar o alias "home", executo o método index do controller home.


Fora isso, eu crio uma função para esconder algumas tags DIV utilizadas no carregamento da aplicação (linha 31 a 38).

View login (Login.js e CapsWarningTooltip.js)

As views para a tela de login são 2: uma para a construção da janela (Login.js) e outra para uma para uma tooltip de alerta quando o Caps Lock estiver ativado (CapsWarningTooltip.js).

Login.js

 

/**
 *
 * Modelo de Login usando MCV
 * Desenvolvido por Ricardo Hirashiki
 * Publicado em: http://www.sitedoricardo.com.br
 * Data: Ago/2011
 *
 * Baseado na extensao criada por Wemerson Januario
 * http://code.google.com/p/login-window/
 *
 */
 
Ext.define('SampleApp.view.authentication.Login', {
  extend      : 'Ext.window.Window',
  alias       : 'widget.authenticationlogin',
  layout      : 'fit',
  bodyStyle   : 'padding:10px;',
  title       : 'Autenticação',
  id          : 'authentication-login',
  autoShow    : true,
  labelAlign  : 'left',
  closable    : false,
  draggable   : false,
  constrain   : true,
  resizable   : false,

  initComponent: function() {
    this.items = [
      {
        xtype          : 'form',
        baseCls        : 'x-plain',
        border         : false,
        bodyStyle      : "padding: 10px;",
        waitMsgTarget  : true,
        labelAlign     : "left",
        items: [
          {
            xtype            : 'textfield',
            name             : 'l',
            id               : 'l',
            fieldLabel       : 'Usuário',
            allowBlank       : false,
            blankText        : 'Usuário Obrigatório',
            msgTarget        : 'side',
            selectOnFocus    : true,
            enableKeyEvents  : true
          },{
            xtype            : 'textfield',
            inputType        : 'password', 
            name             : 's',
            id               : 's',
            fieldLabel       : 'Senha',
            allowBlank       : false,
            blankText        : 'Senha Obrigatória',
            msgTarget        : 'side',
            selectOnFocus    : true,
            enableKeyEvents  : true
          }
        ]
      }
    ];
    this.buttons = [
      {
        xtype  : 'label',
        style  : {color:'#ff0000'} ,
        id     : 'msgField',
        width  :200
      },{
        text: '<b>Entrar</b>',
        action: 'trylogin'
      }
    ];
    this.callParent(arguments);
  }
});

 

CapsWarningTooltip.js

 

/**
 *
 * Modelo de Login usando MCV
 * Desenvolvido por Ricardo Hirashiki
 * Publicado em: http://www.sitedoricardo.com.br
 * Data: Ago/2011
 *
 * Baseado na extensao criada por Wemerson Januario
 * http://code.google.com/p/login-window/
 *
 */
 
Ext.define('SampleApp.view.authentication.CapsWarningTooltip', {
  extend       : 'Ext.tip.QuickTip',
  alias        : 'widget.capswarningtooltip',
  target       : 'authentication-login',
  id           : 'toolcaps',
  anchor       : 'left',
  anchorOffset : 60,
  width        : 305,
  dismissDelay : 0,
  autoHide     : false,
  disabled     : false,
  title        : '<b>Caps Lock está ativada</b>',
  html         : '<div>Se Caps lock estiver ativado, isso pode fazer com que você</div>' +
                 '<div>digite a senha incorretamente.</div><br/>' +
                 '<div>Você deve pressionar a tecla Caps lock para desativá-la</div>' +
                 '<div>antes de digitar a senha.</div>' 
});

 

View Home (Home.js)

A view Home é somente um painel com um título. A idéia é que este seja o painel de entrada da aplicação.

 

Ext.define('SampleApp.view.home.Home', {
  extend        : 'Ext.panel.Panel',
  alias         : 'widget.homehome',
  deferredRender: false,
  layout:'fit',
  title:'painel Home'
});

 

 

View Layout (Appview.js)

Aqui está o segredo para o sistema de autenticação funcionar. Na documentação do ExtJs, uma viewport é:

  • Rendenizada diretamente no corpo do HTML (document.body());
  • Automaticamente assume o tamanho do browser e acompanha o redimensionamento da janela
  • Única para a página.

Por ser um viewport, muita gente tenta colocar o seu layout como 'border' e aplicar as regiões de acordo com o layout do seu sistema (region:'west' para menu lateral, region:'north' para os logos e menus, etc...). Ocorre que uma viewport uma vez rendenizada não pode ser alterada, ou seja, se você rendenizou com uma região central e uma lateral, você não pode adicionar dinamicamente um painel para o topo e outro para a parte de baixo, por exemplo.

Mesmo se você chamar o método Close() e/ou destruir uma Viewport, não é possivel criar uma nova.

Para contornar este problema, é necessário criar um painel com layout:'border' (Appview.js) para "simular" uma viewport. Deste modo, eu posso criar e destruir a nossa viewport "simulada" dentro da viewport verdadeira:

 

Ext.define('SampleApp.view.layout.Appview', {
  extend        : 'Ext.panel.Panel',
  alias         : 'widget.layoutappview',
  layout : 'border',
  id : 'layoutappview',
  items:[
  / {xtype:'layoutheader'},
    {xtype:'layoutfooter'},
    {xtype:'layoutleft'},
    {xtype:'layoutright'},
    {xtype:'layoutmiddle'}
  ]
      
});

 

No exemplo, cada elemento do Appview.js é um painel com a propriedade region. O painel central (Middle.js) ficaria assim:

 

Ext.define('SampleApp.view.layout.Middle', {
  extend        : 'Ext.panel.Panel',
  alias         : 'widget.layoutmiddle',
  id:'layoutmiddle',
  deferredRender: false,
  region:'center',
  layout: 'card',
	baseCls: 'x-plain'
});

 

O código das outras classes você pode obter fazendo o download do projeto no final do post.

Controller Authentication (Authentication.js)

Este é o controller das funcionalidades do formulário de login. Além de vincular uma ação no botão "Entrar", adicionei mais 2 funcionalidades: a primeira é reconhecer o "Enter" como um click no botão e a segunda é verificar se o CapsLock está acionado e, dependendo do caso, exibir uma mensagem de aviso (CapsWarningTooltip.js):

 

Ext.define('SampleApp.controller.Authentication', {
  extend: 'Ext.app.Controller',
  views: ['authentication.Login', 'authentication.CapsWarningTooltip'],
  init: function() {
    console.log('Authentication.init()');
    this.control({
      'authenticationlogin button[action=trylogin]': {
        click: this.tryLogin
      },
      'authenticationlogin #l': {
        keypress: this.verifyCapsLock,
        keyup   : this.verifyEnter
      },
      'authenticationlogin #s': {
        keypress: this.verifyCapsLock,
        keyup   : this.verifyEnter
      }
    });
  },
  index:function(){
  	
    var middle = Ext.getCmp('viewport_default');
    if (middle){
      middle.removeAll();
    }
    Ext.widget('authenticationlogin');
  },
  tryLogin: function(button){
    var loginWin    = button.up('window');
    var loginForm   = loginWin.down('form');
    if (loginForm.getForm().isValid()){
      var values = loginForm.getValues();
      var ok;
      loginForm.submit({
        url : 'data/trylogin.json'          //Simula OK
        ,method : 'POST'
        ,scope:this
        ,success: function(form, action){
             loginWin.close();
             Ext.ux.Router.redirect('');
        }
        ,failure: function(form, action)
        {
          var lblField = Ext.ComponentQuery.query('authenticationlogin #msgField')[0];
          if (lblField ){
            switch (action.failureType) {
              case Ext.form.action.Action.CLIENT_INVALID:
                lblField.setText("Campos inválidos", false);
                break;
              case Ext.form.action.Action.CONNECT_FAILURE:
                lblField.setText("Falha ao conectar no servidor", false);
                break;
              case Ext.form.action.Action.SERVER_INVALID:
                lblField.setText(action.result.msg||"Usuário e/ou senha inválido", false);
            }
          }
        }
      });
      
    }
  },
  factoryCapsWarningToolTip: function(){
    /*
     * Cria a view do tooltip
     */
    if (!this._capswarningtooltip){
      this._capswarningtooltip = Ext.widget('capswarningtooltip');
    }
    return this._capswarningtooltip;
  },
  verifyCapsLock: function(text, e) {
    var charCode = e.getCharCode();
    if(
      (e.shiftKey && charCode >= 97 && charCode <= 122) ||
      (!e.shiftKey && charCode >= 65 && charCode <= 90)
    ){
      this.factoryCapsWarningToolTip().show();
      return false;
    } else {
      this.factoryCapsWarningToolTip().hide();
    }  
  },
  verifyEnter: function(txt,e){
    if(e.getKey() === e.ENTER){
      e.stopEvent();
      var btn = Ext.ComponentQuery.query('authenticationlogin button[action=trylogin]')[0];
      if (btn){
        this.tryLogin(btn);
      }
    }
  }
});

 

Eu não implementei estas funções dentro da view Login (Login.js) pois quis aproveitar uma das facilidades do modelo MVC. Se algum dia eu não quiser mais esta funcionalidade, basicamente eu devo inibir as ações da view alterando os parâmetros do this.control no método init.

O mesmo vale para adicionar novas funcionalidades. Se algum dia eu quiser um teclado virtual, por exemplo, eu crio a view e eu vinculo com a view de login através de seu controller. Laughing

Controller Viewport (Viewport.js)

O código do controller Viewport.js está listado abaixo:

 

Ext.define('SampleApp.controller.Viewport', {
  extend: 'Ext.app.Controller',
  views: ['layout.Header','layout.Footer','layout.Left','layout.Right','layout.Middle', 'layout.Appview','home.Home'],
  defaultItem:{
        id:'viewport_default',
        region:'center',
        layout:'fit',
        border:0,
        html: 
        "<p align='center'>" +
        "    <img src='images/logo-sencha-sm.png' alt='Logo' />" +
        "</p>"
        },
  init: function() {
    this.control({
       'viewport': {
	   render: this.onViewportRendered
      }
    });
  },
  index:function(){
  	this.render('home.Home');
  },
  onViewportRendered: function(p) {
    console.log("Viewport - onViewportRendered");
    p.add(this.defaultItem);
    this.index();
  }
});

 

Aqui, sempre que eu rendenizo a viewport, o método index é chamado. Este método por sua vez, chama o método this.render, passando como parâmetro a primeira tela do sistema ('home.Home'). Este método é descrito em outro arquivo.....


Classe Ext.ux.Initialization (Initialization.js)

A Classe Ext.ux.Initialization serve para configurar a classe do Controller. Através do método render, o sistema sempre verificará se o usuário está logado ao acessar uma view. A outra função é configurar os listeners da classe Ext.ux.Router.

 

/**
 *
 * Modelo de Login usando MCV
 * Desenvolvido por Ricardo Hirashiki
 * Publicado em: http://www.sitedoricardo.com.br
 * Data: Ago/2011
 *
 * Baseado nos exemplos disponibilizados em
 * https://github.com/brunotavares/Ext.ux.Router
 * 
 */
 
Ext.define('Ext.ux.Initialization', {requires: ['Ext.ux.Router']},
  (function()
  {
	  console.log('Ext.ux.Initialization - begin');
  /* 
   * Override Ext.app.Controller to provide render capability. I believe each application
   * will handle rendering task different (some will render into a viewport, some in tabs, etc...), 
   * so I didn't put this role into Ext.ux.Route responsability.
   */
  Ext.override(Ext.app.Controller, {
      render: function(view)
      {
      	if (!view){
      		view="home.Home";
        }
        Ext.Ajax.request({
          url : 'data/islogged.json',   //Simula ERRO
          method: 'POST',
          scope:this,
          success: function ( result, request ) { 
            var retorno = Ext.decode(result.responseText);
            if (retorno.success)
            {
              var viewport_main = Ext.getCmp('viewport_default');
              var viewport_layoutappview = Ext.getCmp('layoutappview');
              if (!viewport_layoutappview){
                viewport_main.removeAll();
                viewport_main.add(Ext.widget('layoutappview'));
                viewport_main.doLayout();
              }
              var middle = Ext.getCmp('layoutmiddle');
              if (middle){
                middle.removeAll();
                console.log(middle);
                //load view
                if (Ext.isString(view)) {
                  view = this.getView(view);
                }
                   
                //if it already exists, remove
                element = middle.child(view.xtype);
                if(element){
                  middle.remove(element);
                }
                middle.setActive(true,middle.add(view));
                middle.doLayout();                
             }
            }else{
              Ext.ux.Router.redirect('login');
            }
          },
          failure: function ( result, request) { 
            console.log(result);
            console.log(request);
            switch (result.failureType) {
              case Ext.form.action.Action.CLIENT_INVALID:
                Ext.MessageBox.alert('Erro', "Campos inválidos"); 
                break;
              case Ext.form.action.Action.CONNECT_FAILURE:
                Ext.MessageBox.alert('Erro', "Falha ao conectar no servidor"); 
                break;
              case Ext.form.action.Action.SERVER_INVALID:
                this.onAuthenticationFail(sender);
            }
          } 
        });
    }
  });
  
  /* 
   * Ext.ux.Router provides some events for better controlling
   * dispatch flow
   */
  Ext.ux.Router.on({
      routemissed: function(uri)
      {
          Ext.Msg.show({
              title:'Error 404',
              msg: 'Route not found: ' + uri,
              buttons: Ext.Msg.OK,
              icon: Ext.Msg.ERROR
          });
      },
      beforedispatch: function(uri, match, params)
      {
          console.log('beforedispatch ' + uri);
      },
      dispatch: function(uri, match, params, controller)
      {
          console.log('dispatch ' + uri);
          //TIP: you could automize rendering task here, inside dispatch event
      }
  });
  console.log('Ext.ux.Initialization - end');
  })
);

Customização

A única customização necessária foi uma pequena alteração na Classe Ext.ux.Router (Router.js). Internamente, esta classe faz uma chamada ao método getController. De acordo com a documentação do Sencha, este método retorna uma instância do controller e, se necessário, cria o controller. Acontece que os controllers adicionados deste modo não chamam o método init. Então, adicionei uma linha chamando o método:

 

/**
         * Receives an URI Token, parses it, and find a respective route, firing 'dispatch' event. 
         * If no route is found, fires 'routemissed' event.
         * @param {String} uri URI token (e.g. 'home/index', 'users/1/edit')
         */
        processURI: function(uri)
        {
            var controller,
                uriObject = pub.decomposeURI(uri),
                match = this.findMatch(uriObject),
                params = Ext.apply({}, uriObject.params);
            
            if(match === false){
                pub.fireEvent('routemissed', uri);
                return false;
            }
            
            Ext.iterate(match.sections, function(section, i)
            {
                if(regColumn.test(section))
                {
                    section = section.replace(regColumn, '');
                    params[section] = uriObject.sections[i];
                }
            });
            
            Ext.iterate(params, function(key, value)
            {
                params[key] = parseValue(value);
            });
            
            if(pub.fireEvent('beforedispatch', uri, match, params) === false){
                return;
            }
            
            controller  = app.getController(match.controller);
            controller['init'].call(controller, params);
            controller[match.action].call(controller, params);
            pub.fireEvent('dispatch', uri, match, params, controller);
        }

 

 

Execução e Testes

Para ver todas as possibilidades que o exemplo cobre, tente mudar os retornos das chamadas de islogged.json e trylogin.json.

Bom estudo!!

Até logo!

ExtJS_login_MVC.zip (17,75 kb)

Tags: ,

ExtJS

Comments (19) -

Nadjib
Nadjib Algeria
9/8/2011 6:51:42 PM #

Hi,

Thanks a lot for this great tutorial, but I'd like to understand what can I change in  islogged.json  and trylogin.json to see the login form and after I'll see the viewport. In fact, as I am new in Extjs, I found difficult to   follow you code even I'm sure that's an advanced topic. In the other hand, about the security issue : some one can modify the JavaScript  source code just to get the viewport without passing by the login form.

Thanks in advance.

Reply

Hirashiki
Hirashiki Brazil
9/21/2011 3:37:35 AM #

Basically, You need to change the "success" part. For example. when Success:true in islogged.json means that You already authenticated in server. Change it to Success:false and u´ll be redirected to login page. The islogged.json is triggered aways when u refresh a page.

The login page works the same way. When success:true, means that your user and password is valid in server. On the other hand, success:false means that your user and password is invalid in server. The trylogin.json is triggered aways when u press button in login page.

Best Regards

Reply

sharkfive
sharkfive Brazil
9/11/2011 10:58:28 PM #

boa noite Hirashiki,

baixei o seu exemplo aqui, fiz algumas alterações para autenticar o usuário que esta em uma base de dados e tudo ocorreu perfeitamente, abrindo a viewport com a Home Panel.
Mas eu queria fazer diferente, ao invés de abrir a viewport como esta acontecendo após o login, eu gostaria de abrir uma simples window com o código que segue abaixo:


Ext.define('MJD.view.desktop.navegador',{
    
    extend  : 'Ext.window.Window',
    alias   : 'widget.navegador',
    layout  : 'fit',
    id      : 'navegador',
    title   : 'Menu de Navegação',
    width   : '400',
    height  : '250',
    
    initComponent: function(){
        
    }
    
});


Eu sei que é simples para você, mas eu me atrapalhei todo e não conseguir fazer isso. Pode me orientar?

Reply

Hirashiki
Hirashiki Brazil
9/21/2011 3:50:27 AM #

Dentro do "Initialization.js", existe o método render, que por sua vez valida se o usuário está logado (fazendo uma chamada para o islogged.json).

Eu não parei para fazer um teste aqui, mas teoricamente é só colocar o que você quer dentro do Success:

          success: function ( result, request ) {
            var retorno = Ext.decode(result.responseText);
            if (retorno.success)
            {
              //É aqui que você deve colocar.
            }else{
              Ext.ux.Router.redirect('login');
            }
          }

Só vai ter que tomar cuidado para controlar as instâncias da sua Janela. Dependendo do que acontecer, pode ocorrer de criar mais de uma janela.

Espero ter ajudado
abraços

Reply

Bruno Tavares
Bruno Tavares Brazil
10/19/2011 3:45:10 PM #

Gostei da sua codificação! Muito legal ver o Ext.ux.Router sendo aplicado Smile Abs!

Reply

Wallysson Nunes
Wallysson Nunes Brazil
11/18/2011 6:29:45 PM #

Ou, eu baixei o tutorial mas nada funcionou não... O.o
Apenas a tela do Extjs com o loader abriu na tela... Eu estou no Linux e ele é case sensitive com os arquivos e tals... Tem que configurar mais alguma coisa pra funcionar? Ou os arquivos são só para compreender a lógica de como funcionária?

Reply

Hirashiki
Hirashiki Brazil
11/18/2011 7:27:53 PM #

Wallyson,

Não precisa configurar mais nada. Você já deu uma olhada no Firebug se ocorre algum erro?

Reply

Wallysson Nunes
Wallysson Nunes Brazil
11/19/2011 1:46:29 AM #

É tão bom ver alguem respondendo um post em um blog cara! Muito obrigado!!!
Bom, sobre o problema, está assim, quando roda, ele dispara duas mensagens no console que não são erros, apenas avisos do sistema mesmo...

Ext.ux.Initialization - begin
Ext.ux.Initialization - end

Ele carrega os arquivos normalmente, desde o ext-all.css até o Home.js
Aparentemente todos arquivos são carregados, pois não exibe nenhuma falha de requisição, e ao todo 16 páginas são chamadas...

Eu estou meio perdido a como trabalhar com login no Ext (parte da validação com o server side, e pelo que percebi no código, sua idéia das chamadas ajax é uma das melhores). Obrigado por ter disposto o código para download! Em nome de Jesus ele vai funcionar... Laughing
Só descobrir oq ta pegando...

Reply

Wallysson Nunes
Wallysson Nunes Brazil
11/19/2011 1:47:15 AM #

É tão bom ver alguem respondendo um post em um blog cara! Muito obrigado!!!
Bom, sobre o problema, está assim, quando roda, ele dispara duas mensagens no console que não são erros, apenas avisos do sistema mesmo...

Ext.ux.Initialization - begin
Ext.ux.Initialization - end

Ele carrega os arquivos normalmente, desde o ext-all.css até o Home.js
Aparentemente todos arquivos são carregados, pois não exibe nenhuma falha de requisição, e ao todo 16 páginas são chamadas...

Eu estou meio perdido a como trabalhar com login no Ext (parte da validação com o server side, e pelo que percebi no código, sua idéia das chamadas ajax é uma das melhores). Obrigado por ter disposto o código para download! Em nome de Jesus ele vai funcionar... Laughing
Só descobrir oq ta pegando...

Reply

Wallysson Nunes
Wallysson Nunes Brazil
11/19/2011 2:44:41 AM #

Como havia lhe falado, o problema era o case sensitive, ao definir as views você as delcarou como
layout sendo que sua pasta se chamava Layout... Probleminhas também com a home.Home...
Bom, de qualquer modo está tudo certo agora!

Adorei a estrutura que você montou dos painéis... Pensei diversas vezes em como montar o layout e sempre ficava uma zona... T_T
Acabei trabalhando com o layout Card mesmo, mas o  que você fez parece estar muito bom. Só tive uma dúvida, você implementou a requisição dinâmica de controllers certo? Você utiliza o getController em um dos seus arquivos. Como eu faria na aplicação para chamar meus controllers e aplica-los em cada parte do sistema? Por exemplo em uma das sidebars e no conteúdo central...?

Reply

Hirashiki
Hirashiki Brazil
11/23/2011 7:37:46 PM #

@Wallysson
No começo é assim mesmo.. você quebra um pouco a cabeça pra entender os problemas... Algum depurador de Javascript é um requisito para trabalhar com o ExtJs... *r*
Quanto as requisições, eu utilizei o módulo Ext.ux.Router do Bruno Tavares. Você define as rotas no app.js e chama através do método
Ext.ux.Router.redirect(rota);
Dá uma olhada no site dele: https://github.com/brunotavares/Ext.ux.Router
Abraços

Reply

Israel
Israel Brazil
11/22/2011 10:19:15 PM #

Programo em Delhi, mas gostaria de aprender essa ferramenta para programar para web... De tudo que já vi, este framework foi o que mais me chamou a atenção... Onde posso fazer um bom curso ?

Reply

Hirashiki
Hirashiki Brazil
11/23/2011 7:41:18 PM #

@Israel,

No fórum do extjs tem um monte de exemplo para estudo. O próprio framework fornece alguns exemplos básicos.
Se você já tem uma noção de Json e "Javascript Orientado a Objetos" já pode começar a estudar o framework, caso contrário, sugiro começar por estes pontos:Tudo no ext é orientação a objetos e json.

abraços

Reply

Carlos Clay
Carlos Clay Brazil
11/24/2011 3:00:20 AM #

Um assunto avançado para demonstrações simples. Parabéns!

Reply

Junior
Junior Brazil
12/11/2011 8:11:15 PM #

Olá. Tudo bem?
Não consegui fazer seu exemplo rodar. Deu o seguinte erro:
XMLHttpRequest cannot load file:///C:/xampp/htdocs/testelogin/data/islogged.json. Origin null is not allowed by Access-Control-Allow-Origin.

O que poderia ser? Me parece que ele não está conseguindo carregar o json do arquivo islogged.json

Se tiver como me orientar, ficaria grato.

Reply

Junior
Junior Brazil
12/11/2011 8:22:50 PM #

Consegui identificar meu erro. Vou estudar seu exemplo. Obrigado.

Reply

Marcos Hemann
Marcos Hemann Brazil
12/13/2011 1:32:30 PM #

Poderia enviar o sistema para mim ja arrumado pois to apanhando e não consegui resolver o problema do case sensitive. To tentando rodar num MAC Os.

Se possivel enviar para marcos@mhemann.com.br

Obrigado

Reply

Daniel
Daniel Brazil
12/23/2011 5:35:29 PM #

Ola  Hirashiki o login funcionou sem problemas.

Mas depois que implementei o menu e as primeiras classes, o IE nao consegue entrar no sistema e o firebug começou a mostrar os erros:
"missing ; before statement"
e
"The following classes are not declared even if their files have been loaded".

O mais estranho é que no firefox, se eu der F5(refresh) o firebug vai mudando a classe js que contem o erro, até consegue entrar no sistema.

Conferi a sitexe e os nomes de classe em todo sistema e não consegui resolver.
Será que poderia me dar uma força?

Obrigado

Reply

Rodrigo Schiavo de Rezende
Rodrigo Schiavo de Rezende Brazil
12/26/2011 12:47:41 PM #

Boa Tarde,
Estou com uma dúvida, quando eu rodo a forma de login, ele chega a exibir a imagem que você colocou para carregar a página, e logo depois ele exibe a imagem do sencha....consegui rodar ate essa parte...como eu só leigo no EXTJS, eu gostaria de saber como que eu faço para exibir o login e senha...ou ate mesmo a visualização dos .js...já que eles são procedimentos que devo chamar em cera parte do evento...
Obrigado !

Reply

Add comment




  Country flag
biuquote
  • Comment
  • Preview
Loading


Anunciante

Calendário

<<  February 2012  >>
MoTuWeThFrSaSu
303112345
6789101112
13141516171819
20212223242526
2728291234
567891011

View posts in large calendar

RecentPosts