Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Você ainda não sabe escrever JavaScript para aplicações Rails

Você ainda não sabe escrever JavaScript para aplicações Rails

Uma palestra com as principais tecnologias e técnicas utilizadas para escrever código JavaScript sano para diferentes tipos de aplicações. Uma viagem às antigas soluções Rails até as atuais e nem sempre suficientes jQuery UJS e Turbolinks. Aprenda sobre componentes auto-discoverable, comunicação através de eventos, modularização e gerência de dependências. Tudo isto sem deixar de fora alguns dos conceitos por trás dos principais frameworks MV* do mercado.

Jean Carlo Emer

August 29, 2014
Tweet

More Decks by Jean Carlo Emer

Other Decks in Programming

Transcript

  1. [...] é necessário ir ao passado para a compreensão de

    todos os questionamentos do tempo presente - Historiador Tiago Menta
  2. <%  form_remote_tag  :url  =>  '/'  do  -­‐%>      

       <div><%=  submit_tag  'Save'  %></div>   <%  end  -­‐%> index.erb
  3. <form action="/" method="post" onsubmit="
 new Ajax.Request('/', {asynchronous:true, 
 evalScripts:true, parameters:


    Form.serialize(this)}); return false;"> <input name="commit" type="submit" /> </form> index.html
  4. <%=  observe_field(:local_estado_id,            :update  =>  "local_cidade_id",

               :url  =>  cidades_options_for_select_path,            :with  =>  "estado_id"  %> index.erb
  5. <select  id="local_estado_id"                

       name="local[estado_id]"><!-­‐-­‐  -­‐-­‐></select>   ! <script  type="text/javascript">   //<![CDATA[      new  Form.Element.EventObserver('local_estado_id',         ! ! ! //]]>   </script> !@#$%^@!% index.html
  6. update_page  do  |page|      page.insert_html  :bottom,  'list',    

           "<li>#{@item.name}</li>"      page.visual_effect  :highlight,   'list'   end controller/action.rb
  7. new  Element.insert("list",            {  bottom:  "<li>Some

     item</li>"  });   new  Effect.Highlight("list"); response.js
  8. JavaScript não deve estar no markup Código back-end não deve

    depender de biblioteca front-end. ♥ ♥
  9. Rails 3.0 Fim das chamadas Ajax através de JavaScript inline

    e dos observers https://github.com/rails/prototype_legacy_helper
  10. <%=  link_to  "Other  Site",  "url",         data:

     {  confirm:  "Are  you  sure?"  }  %> index.erb
  11. Considere que o formulário também pode ser enviado sincronamente pelo

    usuário E se não executar o 
 JavaScript?
  12. <%=  link_to  "Destroy",  "url",  
          

                   method:  :delete  %> index.erb
  13. O usuário irá apenas ler a notícia, considere sempre utilizar

    formulários para este tipo de ação E se não executar o 
 JavaScript?
  14. $('#photo_<%=  params[:id]  %>').remove(); destroy.js.erb photo.html <a  href="photo/2"      

       data-­‐method="delete"          data-­‐remote="true">Destroy</a>  
  15. <%-­‐  if  @contact.errors.any?  %>      $('#contact-­‐modal').html('<%=   escape_javascript(render(partial:  'form'))

        )  %>');   <%-­‐  else  %>      $('#contact-­‐modal').html('<%=   !       !   $('#contact-­‐modal').append('<p  class="alert  
 alert-­‐success">Your  message  was  successfully  
 sent  </p>');      setTimeout("$('.close').click();",  2000);   <%-­‐  end  %> !@#$%^@!% create.js.erb
  16. class  Counter      constructor:  (@min  =  0,  @max  =

     10e9)  -­‐>          @current  =  @min      next:  -­‐>          @current  =  Math.min(@max,  @current  +  1)      isFirst:  -­‐>          @current  <=  @min   ! class  CounterPlus  extends  Counter      goToLast:  -­‐>          @current  =  @max counter.coffee
  17. function  Counter(min,  max)  {          this.min  =

     min  !=  null  ?  min  :  0;          this.max  =  max  !=  null  ?  max  :  10e9;          this.current  =  this.min;   }   ! Counter.prototype.next  =  function()  {          return  this.current  =  
       Math.min(this.max,  this.current  +  1)   }   ! Counter.prototype.isFirst  =  function()  {          return  this.current  <=  this.min   }   ! function  CounterPlus()  {   counter.js
  18. ! Counter.prototype.isFirst  =  function()  {          return

     this.current  <=  this.min   }   ! function  CounterPlus()  {          Counter.apply(this,  arguments)   }   ! function  InheritCounter()  {}   InheritCounter.prototype  =  Counter.prototype   ! CounterPlus.prototype  =  new  InheritCounter()   CounterPlus.prototype.constructor  =  CounterPlus   ! CounterPlus.prototype.goToLast  =  function()  {          return  this.current  =  this.max   }
  19. Não é por nada que o EcmaScript 6 usa o

    CoffeeScript como referência
  20. RUBYCONF
 
 CONHEÇA OS PALESTRANTES PROMETE TRAZER NOVIDADES E ASSUNTOS

    PERTINENTES DA ÁREA Requisição Ajax pela página apontada no link
  21. A barra de endereços é atualizada e as páginas visitadas

    são armazenadas (voltar à uma página é imediato)
  22. Assets devem ficar no <head> e precisam ser marcados para

    que modificações sejam monitoradas (e recarregada caso preciso)
  23. Suporte para widgets do Facebook, Twitter, Google+, Google Analytics, AdSense

    e alguns mais http://reed.github.io/turbolinks-compatibility
  24. A cada transição os events handlers e demais callbacks devem

    ser desativados para não interferir na performance
  25. Código JavaScript pode ser executado na troca de páginas Widgets

    e add-ons funcionam de acordo depois de ajustados Memory leaks podem ser evitados ♥ ♥ ♥
  26. O Turbolinks não permite que apenas porções da página sejam

    requisitadas (confira o jquery-pajax para isto)
  27. Turbolinks funciona bem 
 em websites simples (como o 


    desta conferência) e forma uma 
 boa dupla com UJS
  28. O JavaScript não possui sistema de módulos fazendo com que

    diferentes scripts compartilhem o mesmo escopo
  29. file1.js file2.js Sem a criação de um escopo, as variáveis

    ficam expostas var  myVar  =  "bla"; alert(myVar);
  30. (function  ()  {      var  data  =  {};  

       function  parser()  {            //  Code      }   })(); Immediately-Invoked Function Expression viabilizam a criação de escopos http://benalman.com/news/ 2010/11/immediately- invoked-function-expression
  31. App.modules.mediabox  =  (function  ()  {      var  data  =

     {};   !    return  {            data:  data,            parser:  //  ...      }   })(); Namespaces mediabox.js (namespace)
  32. Module('modules.mediabox',  
    function  (Mediabox)  {        

     Mediabox.data  =  {};        Mediabox.parser  =  //  ...      }   ); Biblioteca de módulos do Nando Vieira http://simplesideias.com.br/ escrevendo-javascript-modular mediabox.js (Module.js)
  33. define(      [          'jquery',  

             'util/counter'      ],      function  ($,  Counter)  {          //  ...                  return  {              Mediabox:  Mediabox,              //  ...          };      }
 ); mediabox.js (AMD) Módulos AMD que permitem indicação de dependências https://github.com/ jwhitley/requirejs-rails
  34. Declaração de dependências Path do arquivo como identificador do módulo

    Assíncrono por natureza e adotado
 por jQuery e outras bibliotecas ♥ ♥ ♥
  35. [...] it makes code easier to understand for others and

    yourself re-visting your own code - Chris Coyier
  36. ES6 Modules e CommonJS Modules não possuem suporte adequado 


    ao Asset Pipeline (alguém se habilita?)
  37. main.js //  Setup  product  page   if  ($('body').is('.page-­‐product'))  {  

       $("[data-­‐draggable]").draggable()      $("[data-­‐comments]").comments()   }   ! //  Setup  checkout  page   if  ($('body').is('.page-­‐checkout'))  {      $("[data-­‐draggable]").draggable()      $("[data-­‐datepicker]").datepicker()   }
  38. main.js //  Setup  product  page   if  ($('body').is('.page-­‐product'))  {  

       $("[data-­‐draggable]").draggable()      $("[data-­‐comments]").comments()   }   ! //  Setup  checkout  page   if  ($('body').is('.page-­‐checkout'))  {      $("[data-­‐draggable]").draggable()      $("[data-­‐datepicker]").datepicker()   }
  39. define(function  ()  {      function  Mediabox(container)  {    

         //  ...      }      return  Mediabox;   }); Chamada do construtor
 com o container mediabox.js
  40. Trabalhar com models que emitem eventos é trabalhoso e passível

    a erros (não entenda mal, Backbone.js) ♥
  41. <div  ng-­‐controller="Basket">      <select  ng-­‐model="quantity"  
      

                 ng-­‐init="quantity=1">          <option>1</option><option>10</option>      </select>      <div>Valor:  R$  {{price()}}</div>   </div> index.html function  Basket($scope)  {          $scope.price  =  function  ()  {                  return  $scope.quantity  *  50;                              };   } main.js
  42. <div  ng-­‐app="component">      <tabs>          <pane

     title="Date">              Date:  {{  '2012-­‐04-­‐01'  |  date:'fullDate'  }}          </pane>          <pane  title="Hello">              Hi!          </pane>      </tabs>   </div> Tags são mapeadas para templates e controllers
  43. What’s wrong with Angular.js https://medium.com/este-js-framework/whats- wrong-with-angular-js-97b0a787f903 What I would recommend

    instead of Angular.js? https://medium.com/este-js-framework/what-i- would-recommend-instead-of-angular- js-62b057d8a9e
  44. Estude sobre execução de código assíncrono com callbacks e promises

    https://speakerdeck.com/jcemer/controle-de- fluxo-com-execucao-assincrona 1.
  45. Aceite que o JavaScript do front-end da sua aplicação pode

    dar tanto ou mais trabalho que o back-end 2.