Data-Binding: Entendendo a mágica do AngularJS

Introdução

Felipe Lopes
Dev Cave
3 min readFeb 9, 2017

--

BEM… Hoje irei explicar como é realizado o Data-Binding por baixo dos panos no AngularJS. Esse “tão” famoso Data-Binding que o AngularJS trouxe transformou a área de Front-End com uma abordagem muito simples.

Droga, alguns de vocês devem estar pensando “poxa, é famoso essa fita de Data-Binding, mas me explica, o que ele faz?”.

Então turma, essa característica do AngularJS funciona da seguinte forma: quando alteramos algo na view (ex: inserção de texto em um input) automaticamente atualiza-se seu correspondente no $scope model.

Exemplo 1: exemplo bem básico da mágica realizada com simples linhas de código HTML e Javascript.

“Bão” demais para ser verdade né. Só para você ver como isso afetou o mundo Front-End, para poder realizar o mesmo feito acima no exemplo antes de ter o AngularJS, muitos utilizavam JQuery para a manipulação de DOM Elements.

Exemplo 2: exemplo realizado em JQuery ilustrando uma maneira de se fazer o que foi feito no exemplo 1

Agora, como que esse “trem” funciona por debaixo dos panos? A resposta para essa pergunta está em um termo…. $digest().

Explicando o $digest()

Ao demarcar tags HTMLs com expressões AngularJS (ex: {{ message }}, data-ng-model="message"), o framework irá associar um watcher para atualizar a view toda vez que o $scope model alterar. Um exemplo de criar um watcher abaixo:

O segundo parâmetro da função é um listener, onde irá ser chamado quando o valor de message for alterado.

OK, agora sabemos que quando demarcamos com expressões o AngularJS criar watchers. Agora a pergunta que não quer calar, quando que é chamado esses watchers? A resposta é… $digest()!

O ciclo $digest inicia todos os watchers criados para verificar se ocorreu mudanças no $scope model para serem atualizados. Ele é executado a partir da função $scope.$digest(). Um exemplo é quando usamos diretivas do AngularJS (ex: ng-click) com associação ao $scope model, automaticamente o AngularJS chama a função para inicializar o ciclo. Existem diretivas/serviços (ex: ng-model, $http) que disparam automaticamente o ciclo $digest.

Explicando o $apply()

“Uai” credo, surgiu outro cara na parada. Quem é esse fera? Calma galera, ele é nosso amigo. Lembra que o $scope.$digest() inicia o ciclo $digest relacionado ao $scope model? Então, o $scope.$apply() chama o $rootScope.$digest() que é o $scope model pai de todos os $scopes. "Tá" mas explica isso direito... em outras palavras ao invés de chamar o $digest() só para $scope model específico, ele chama para todos os que existirem para ver se não estamos perdendo nada.

Agora, vamos assumir que você adicionou um ng-click em um botão passando o nome de uma função no $scope model. O AngularJS irá encapsular essa função dentro de uma chamada $scope.$apply(). Então ele vai chamar a função e no final irá executar o $digest(). Após isso irá ocorrer o que dissemos, irá iniciar os watchers criados e verificará os valores se foram modificados. Se forem modificados, irá executar seus listeners. :)

Quando chamar manualmente o ciclo $digest?

Existem algumas situações onde é necessário a chamada do ciclo manualmente. Um dos casos mais comuns são quando usamos algum plugin JQuery (ex: JQuery DatePicker). No AngularJS, existem diretivas/serviços que fazem parte do contexto onde ele automaticamente chama o ciclo $digest(). Agora esses tipos de situações que não seja dentro do AngularJS, trabalham fora do contexto do AngularJS, ou seja, o AngularJS não sabe das mudanças geradas e com isso não irá disparar o ciclo $digest(). Nesses momentos, devemos realizar a chamada manual para inicializar o ciclo.

Vamos supor que você utilize um setTimeout() para atualizar uma variável do $scope model:

Note que a resposta não aparece na tela porque o AngularJS jamais saberá o que ocorreu mesmo alterando o $scope model.

Para que o AngularJS reconheça a mudança, devemos chamar o $scope.$apply(). Segue abaixo o exemplo modificado:

PS: Ao invés de utilizar o setTimeout(), devemos utilizar o serviço $timeout que o AngularJS disponibiliza e que já realiza a chamada do $scope.$apply() ao termino do timeout.

Conclusão

Depois de toda essa explicação, o ponto principal é que o AngularJS detecta as mudanças que você realizou dentro do contexto. Se não detectar mudanças, então provavelmente ela está fora do contexto dele e então é necessário a chamada manualmente do ciclo $digest.

Fontes

--

--