Estou tentando entender a diferença entre ng-if
e 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?
Estou tentando entender a diferença entre ng-if
e 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?
Respostas:
A ngIf
diretiva remove ou recria uma parte da árvore DOM com base em uma expressão. Se a expressão designada for ngIf
avaliada 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 ngIf
seu escopo é destruído e um novo escopo é criado quando o elemento é restaurado. O escopo criado ngIf
herda de seu escopo pai usando herança prototípica.
Se ngModel
for usado dentro ngIf
para 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, $parent
variá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>
A ngShow
diretiva mostra ou oculta o elemento HTML fornecido com base na expressão fornecida ao ngShow
atributo. O elemento é mostrado ou oculto removendo ou adicionando a ng-hide
classe CSS ao elemento. A .ng-hide
classe CSS é predefinida no AngularJS e define o estilo de exibição como nenhum (usando um !important
sinalizador).
<!-- 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 ngShow
expressão é avaliada false
, a ng-hide
classe CSS é adicionada ao class
atributo no elemento, tornando-o oculto. Quando true
, a ng-hide
classe CSS é removida do elemento, fazendo com que o elemento não apareça oculto.
data.input
ele funciona ... mas data
sozinho no modelo não funciona. @CodeHater
ngIf
cria um novo escopo. Portanto, analisar o exemplo acima do aninhado ngModel
criaria um novo data
modelo, 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. :)
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.
A ng-if
diretiva remove o conteúdo da página e ng-show/ng-hide
usa a display
propriedade CSS para ocultar o conteúdo.
Isso é útil caso você queira usar :first-child
e :last-child
pseudo-seletores para estilizar.
:first-child
and :last-child
developer.mozilla.org/en-US/docs/Web/CSS/:first-child developer.mozilla.org/en-US/docs/Web/CSS/:last-child
@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.
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-if
porque 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, required
mas, 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!
@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>
<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}}
Fato, essa ng-if
diretiva, 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-click
evento, show
variável, do escopo interno / próprio , é alterado, mas ng-if
está assistindo a outra variável do escopo externo com o mesmo nome, para que a solução não funcione. No caso de ng-show
termos a única show
variável, é por isso que funciona. Para corrigir a primeira tentativa, devemos fazer referência ao show
escopo pai / externo via $parent.show
.
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.
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.
ng-if cria um escopo filho, enquanto ng-show / ng-hide não.
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.
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)
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-if
se 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
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. :)
ng-if
o modelo, adicionado porng-model
, não existe mais.