Qual é a diferença entre ng-if e ng-show / ng-hide

427

Estou tentando entender a diferença entre ng-ife ng-show/ ng-hide, mas eles parecem iguais para mim.

Há uma diferença que devo ter em mente ao optar por usar um ou outro?

Stephane Rolland
fonte

Respostas:

521

ngIf

A ngIfdiretiva remove ou recria uma parte da árvore DOM com base em uma expressão. Se a expressão designada for ngIfavaliada como um valor falso, o elemento será removido do DOM, caso contrário, um clone do elemento será reinserido no DOM.

<!-- when $scope.myValue is truthy (element is restored) -->
<div ng-if="1"></div>

<!-- when $scope.myValue is falsy (element is removed) -->
<div ng-if="0"></div>

Quando um elemento é removido usando ngIfseu escopo é destruído e um novo escopo é criado quando o elemento é restaurado. O escopo criado ngIfherda de seu escopo pai usando herança prototípica.

Se ngModelfor usado dentro ngIfpara ligar a uma primitiva JavaScript definida no escopo pai, quaisquer modificações feitas na variável dentro do escopo filho não afetarão o valor no escopo pai, por exemplo,

<input type="text" ng-model="data">
<div ng-if="true">
    <input type="text" ng-model="data">
</div>        

Para contornar essa situação e atualizar o modelo no escopo pai de dentro do escopo filho, use um objeto:

<input type="text" ng-model="data.input">
<div ng-if="true">
    <input type="text" ng-model="data.input">
</div>

Ou, $parentvariável para referenciar o objeto de escopo pai:

<input type="text" ng-model="data">
<div ng-if="true">
    <input type="text" ng-model="$parent.data">
</div>

ngShow

A ngShowdiretiva mostra ou oculta o elemento HTML fornecido com base na expressão fornecida ao ngShowatributo. O elemento é mostrado ou oculto removendo ou adicionando a ng-hideclasse CSS ao elemento. A .ng-hideclasse CSS é predefinida no AngularJS e define o estilo de exibição como nenhum (usando um !importantsinalizador).

<!-- when $scope.myValue is truthy (element is visible) -->
<div ng-show="1"></div>

<!-- when $scope.myValue is falsy (element is hidden) -->
<div ng-show="0" class="ng-hide"></div>

Quando a ngShowexpressão é avaliada false, a ng-hideclasse CSS é adicionada ao classatributo no elemento, tornando-o oculto. Quando true, a ng-hideclasse CSS é removida do elemento, fazendo com que o elemento não apareça oculto.

AlwaysALearner
fonte
31
Dica: Ao remover o próprio elemento HTML com ng-ifo modelo, adicionado por ng-model, não existe mais.
mrzmyr
3
@CodeHater Utilizei com êxito o ng-if sobre o ng-show / ng-hide em uma página que, de outra forma, teria um grande domínio. Pareceu fazer a página parecer mais rápida, mas não é de forma alguma uma análise científica.
Ed Spencer
A parte que estou tendo problemas para entender completamente é como / por que quando você tem um objeto no modelo, data.inputele funciona ... mas datasozinho no modelo não funciona. @CodeHater
Mark Pieszak - Trilon.io
7
@mcpDESIGNS ngIfcria um novo escopo. Portanto, analisar o exemplo acima do aninhado ngModelcriaria um novo datamodelo, mesmo que exista um modelo com o mesmo nome no escopo pai. Mas quando você usa uma notação de ponto, você faz o JS procurar a cadeia de protótipos do escopo. Portanto, se ele não encontrar o valor no escopo atual, ele tentará procurá-lo no escopo pai e assim por diante. Poucas outras directivas que criam um escopo diferente são ngInclude, ngRepeat. Espero que esteja claro agora. :)
AlwaysALearner
3
Qual é o melhor para o desempenho? Acho ng-show e ng-hide, não é?
tom10271
97

Talvez um ponto interessante a ser destacado seja a diferença entre as prioridades entre os dois.

Até onde eu sei, a diretiva ng-if tem uma das prioridades mais altas (se não a mais alta) de todas as diretivas Angular. O que significa: ele será executado PRIMEIRO antes de todas as outras diretivas de menor prioridade. O fato de rodar PRIMEIRO significa que, efetivamente, o elemento é removido antes que qualquer diretiva interna seja processada. Ou pelo menos: é isso que eu faço.

Eu observei e usei isso na interface do usuário que estou construindo para meu cliente atual. A interface do usuário inteira é bastante compacta e possui ng-show e ng-hide por toda parte. Para não entrar em muitos detalhes, construí um componente genérico, que pode ser gerenciado usando a configuração JSON, então tive que fazer algumas alternâncias dentro do modelo. Há um presente de repetição de ng e, dentro da repetição de ng, é mostrada uma tabela, com muitos shows de ng, ocultas de ng e até comutadores de ng presentes. Eles queriam mostrar pelo menos 50 repetições na lista, o que resultaria em mais ou menos diretrizes 1500-2000 a serem resolvidas. Eu verifiquei o código e o back-end Java + JS personalizado na frente levaria cerca de 150ms para processar os dados e, em seguida, o Angular mastigava cerca de 2-3 segundos antes de exibir. O cliente não reclamou, mas fiquei chocado :-)

Na minha pesquisa, me deparei com a diretiva ng-if. Agora, talvez seja melhor ressaltar que, no momento de conceber essa interface do usuário, não havia ng-se disponível. Como o ng-show e o ng-hide tinham funções neles, que retornavam booleanos, eu poderia substituí-los facilmente por ng-if. Ao fazer isso, todas as diretrizes internas pareciam não ser mais avaliadas. Isso significava que voltei a cerca de um terço de todas as diretivas que estavam sendo avaliadas e, portanto, a interface do usuário acelerou cerca de 500 ms - 1 segundo de carregamento. (Não tenho como determinar segundos exatos)

Observe: o fato de as diretivas não serem avaliadas é um palpite sobre o que está acontecendo por baixo.

Então, na minha opinião: se você precisa que o elemento esteja presente na página (por exemplo, para verificar o elemento, ou o que seja), mas simplesmente esteja oculto, use ng-show / ng-hide. Em todos os outros casos, use ng-if.

gjoris
fonte
1
Sim, acho que esse é o objetivo do ng-if: diminuir o tempo de processamento. Essa diretiva existe com certeza não apenas devido a alguns pseudoseletores de CSS. Bom post! +1
Bartłomiej Zalewski,
16

@EdSpencer está correto. Se você possui muitos elementos e usa o ng-if para instanciar apenas os relevantes, está economizando recursos. O @CodeHater também é um pouco correto, se você deseja remover e mostrar um elemento com muita frequência, ocultá-lo em vez de removê-lo pode melhorar o desempenho.

O principal caso de uso que encontro para o ng-if é que ele permite validar e eliminar de maneira limpa um elemento se o conteúdo for ilegal. Por exemplo, eu poderia fazer referência a uma variável de nome de imagem nula e isso gerará um erro, mas se eu ng-if e verificar se é nula, tudo está bem. Se eu fiz um ng-show, o erro ainda seria acionado.

AturSams
fonte
7

Uma coisa importante a ser observada sobre o ng-if e o ng-show é que, ao usar os controles de formulário, é melhor usar, ng-ifporque remove completamente o elemento do dom.

Essa diferença é importante porque se você criar um campo de entrada com required="true"e depois definir ng-show="false"para ocultá-lo, o Chrome lançará o seguinte erro quando o usuário tentar enviar o formulário:

An invalid form control with name='' is not focusable.

O motivo é o campo de entrada estar presente, requiredmas, como está oculto, o Chrome não pode se concentrar nele. Isso pode literalmente quebrar seu código, pois esse erro interrompe a execução do script. Por isso tem cuidado!

supersan
fonte
Esse é o fato real, se você estiver usando controles de formulário para validação, sofrerá muito se usar ng-show / ng-hide. E se você tiver várias seções ocultas / exibidas com base na expressão. Portanto, se você usar ng-show / hide, os elementos ainda estarão lá e a validação falhará, apesar de não estarem na tela. assim ng-se rescue you :)
NeverGiveUp161
5

@Gajus Kuizinas e @CodeHater estão corretos. Aqui estou apenas dando um exemplo. Enquanto trabalhamos com ng-if, se o valor atribuído for falso, todos os elementos html serão removidos do DOM. e se o valor atribuído for verdadeiro, os elementos html estarão visíveis no DOM. E o escopo será diferente em comparação com o escopo pai. Mas no caso do ng-show, ele apenas mostrará e ocultará os elementos com base no valor atribuído. Mas sempre fica no DOM. Somente a visibilidade muda conforme o valor atribuído.

http://plnkr.co/edit/3G0V9ivUzzc8kpLb1OQn?p=preview

Espero que este exemplo o ajude a entender os escopos. Tente fornecer valores falsos para ng-show e ng-if e verifique o DOM no console. Tente inserir os valores nas caixas de entrada e observe a diferença.

<!DOCTYPE html>

Olá Plunker!

<input type="text" ng-model="data">
<div ng-show="true">
    <br/>ng-show=true :: <br/><input type="text" ng-model="data">
</div>
<div ng-if="true">
    <br/>ng-if=true :: <br/><input type="text" ng-model="data">
</div> 
{{data}}


fonte
2

Fato, essa ng-ifdiretiva, ao contrário ng-show, cria seu próprio escopo, leva a uma diferença prática interessante:

angular.module('app', []).controller('ctrl', function($scope){
  $scope.delete = function(array, item){
    array.splice(array.indexOf(item), 1);
  }
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app='app' ng-controller='ctrl'>
   <h4>ng-if:</h4>
   <ul ng-init='arr1 = [1,2,3]'>
      <li ng-repeat='x in arr1'>
        {{show}}
        <button ng-if='!show' ng-click='show=!show'>Delete {{show}}</button>
        <button ng-if='show' ng-click='delete(arr1, x)'>Yes {{show}}</button>
        <button ng-if='show' ng-click='show=!show'>No</button>
      </li>
   </ul>
   
   <h4>ng-show:</h4>
   <ul ng-init='arr2 = [1,2,3]'>
      <li ng-repeat='x in arr2'>
        {{show}}
        <button ng-show='!show' ng-click='show=!show'>Delete {{show}}</button>
        <button ng-show='show' ng-click='delete(arr2, x)'>Yes {{show}}</button>
        <button ng-show='show' ng-click='show=!show'>No</button>
      </li>
   </ul>
   
   <h4>ng-if with $parent:</h4>
    <ul ng-init='arr3 = [1,2,3]'>
      <li ng-repeat='item in arr3'>
        {{show}}
        <button ng-if='!show' ng-click='$parent.show=!$parent.show'>Delete {{$parent.show}}</button>
        <button ng-if='show' ng-click='delete(arr3, x)'>Yes {{$parent.show}}</button>
        <button ng-if='show' ng-click='$parent.show=!$parent.show'>No</button>
      </li>
   </ul>
</div>

Na primeira lista, o on-clickevento, showvariável, do escopo interno / próprio , é alterado, mas ng-ifestá assistindo a outra variável do escopo externo com o mesmo nome, para que a solução não funcione. No caso de ng-showtermos a única showvariável, é por isso que funciona. Para corrigir a primeira tentativa, devemos fazer referência ao showescopo pai / externo via $parent.show.

Slava Utesinov
fonte
1
  1. ng-if se false removerá elementos do DOM. Isso significa que todos os seus eventos, diretivas anexadas a esses elementos serão perdidos. Por exemplo, ng-clique em um dos elementos filho, quando ng-se for avaliado como falso, esse elemento será removido do DOM e novamente quando for verdadeiro, será recriado.

  2. ng-show / ng-hide não remove os elementos do DOM. Ele usa estilos CSS (.ng-hide) para ocultar / mostrar elementos. Dessa forma, seus eventos, diretrizes anexadas a crianças não serão perdidas.

  3. ng-if cria um escopo filho, enquanto ng-show / ng-hide não.

Amay Kulkarni
fonte
1

ng-show e ng-hide funcionam de maneira oposta. Mas a diferença entre ng-hide ou ng-show com ng-if é, se usarmos ng-if, o elemento será criado no dom, mas com o elemento ng-hide / ng-show será oculto completamente.

ng-show=true/ng-hide=false:
Element will be displayed

ng-show=false/ng-hide=true:
element will be hidden

ng-if =true
element will be created

ng-if= false
element will be created in the dom. 
user1001
fonte
0

Para observar, algo que aconteceu comigo agora: o ng-show oculta o conteúdo via css, sim, mas resultou em estranhas falhas nas div que deveriam ser botões.

Eu tinha um cartão com dois botões na parte inferior e, dependendo do estado real, um é trocado por um terceiro, por exemplo, botão de edição com nova entrada. Usando ng-show = false para ocultar o esquerdo (presente primeiro no arquivo), aconteceu que o botão a seguir terminou com a borda direita fora do cartão. ng-if corrige isso, não incluindo o código. (Apenas verifique aqui se há algumas surpresas ocultas usando ng-if em vez de ng-show)

helius
fonte
0

ngIf faz uma manipulação no DOM removendo ou recriando o elemento.

Enquanto o ngShow aplica regras de CSS para ocultar / mostrar coisas.

Na maioria dos casos (nem sempre) , eu resumiria isso como, se você precisar de uma verificação única para mostrar / ocultar itens, use ng-ifse você precisar mostrar / ocultar itens com base nas ações do usuário na tela (como verificado marque a caixa de seleção, desmarque a caixa de texto, etc.) e useng-show

curiousBoy
fonte
-17

Uma diferença interessante no ng-if e no ng-show é:

SEGURANÇA

Os elementos DOM presentes no bloco ng-if não serão renderizados no caso de seu valor ser falso

onde, como no caso do ng-show, o usuário pode abrir a janela Inspect Element e definir seu valor como TRUE.

E com um grito, todo o conteúdo que deveria ser oculto é exibido, o que é uma violação de segurança. :)

Ashish_B
fonte
27
Essa é uma forma extremamente fraca de segurança. Se o conteúdo é fornecido ao cliente pelo servidor, você deve assumir que o usuário / invasor pode acessá-lo, independentemente de estar ou não presente no DOM. Toda a lógica de autorização deve ser imposta pelo servidor.
tlrobinson
pense no html em vez do jsp ... agora, se você deseja reforçar a segurança nos componentes html ... ou seja, se você deseja ocultar alguns componentes do usuário ... como conseguir isso? E o que no caso de sua configuração é dividido em lado do servidor para o lado de back-end e de cliente para front-end ..
Ashish_B