Angularjs - elementos ng-manto / ng-show piscam


231

Eu tenho um problema no angular.js com diretiva / classe ng-cloakou ng-show.

O Chrome funciona bem, mas o Firefox está causando a piscada de elementos com ng-cloakou ng-show. IMHO é causado pela conversão ng-cloak/ ng-showpara style="display: none;", provavelmente o compilador javascript do Firefox é um pouco mais lento, então os elementos aparecem por um tempo e depois ocultam?

Exemplo:

<ul ng-show="foo != null" ng-cloak>..</ul>

1
se você definir o estilo display: none nesses elementos inicialmente, ele corrige o problema?
akonsu

3
Vou tentar isso, eu estava tentando algo semelhante com a adição de classe (que oculta o elemento) e, em seguida, removê-lo via js manualmente, mas parecia ainda mais ruim.
MelkorNemesis

Respostas:


385

Embora a documentação não mencione isso, pode não ser suficiente adicionar a display: none;regra ao seu CSS. Nos casos em que você estiver carregando o angular.js no corpo ou os modelos não forem compilados em breve, use a ng-cloakdiretiva e inclua o seguinte no seu CSS:

/* 
  Allow angular.js to be loaded in body, hiding cloaked elements until 
  templates compile.  The !important is important given that there may be 
  other selectors that are more specific or come later and might alter display.  
 */
[ng\:cloak], [ng-cloak], .ng-cloak {
  display: none !important;
}

Como mencionado no comentário, o !importanté importante. Por exemplo, se você tiver a seguinte marcação

<ul class="nav">
  <li><a href="/foo" ng-cloak>{{bar}}</a></li>
</ul>

e você estiver usando bootstrap.css, o seletor a seguir é mais específico para o seu ng-cloakelemento ed

.nav > li > a {
  display: block;
}

Portanto, se você incluir uma regra com simplicidade display: none;, a regra do Bootstrap terá precedência e displayserá definida como block, para que você veja o piscar antes da compilação do modelo.


3
Observe também que esse mesmo problema pode ocorrer se você estiver carregando o angular.js usando um carregador assíncrono, como o require.js, porque a regra css no arquivo .js não será analisada a tempo. A solução acima corrige esse cenário também.
Johann

84
Não resolve o problema para mim. Não sei - Eu acho que os navegadores são muito ansioso para mostrar as coisas inicialmente ...
Andriy Drozdyuk

7
O navegador NUNCA deve renderizar o DOM sem levar em consideração o css, mesmo na primeira passagem; isso seria altamente ineficiente; Verifique sua configuração: p
AlexG

1
como você reinicializa o dom que foi camuflado por ng, depois de carregar preguiçosamente o código do módulo doms?
FutuToad

Se o css acima não estiver funcionando para você, é provável que o seu :in ng:cloaknão seja escapado corretamente. Para CSS puro, verifique se a barra invertida está lá. Para CSS compilado, por exemplo, Stylus, será [ng\\:cloak]. Verifique seu CSS compilado para garantir que esteja correto.
21415 Joe

47

Conforme mencionado na documentação , você deve adicionar uma regra ao seu CSS para ocultá-la com base no ng-cloakatributo:

[ng\:cloak], [ng-cloak], .ng-cloak {
    display: none;
}

Usamos truques semelhantes no site "Built with Angular", que você pode ver na fonte do Github: https://github.com/angular/builtwith.angularjs.org

Espero que ajude!


4
angular.js adiciona essa regra de estilo ao cabeçalho do documento. Você realmente não precisa adicionar isso ao seu CSS. Dito isto, isso parece funcionar. Meu palpite é que angular.js não adiciona o bloco de estilo à cabeça até depois de carregar o angular.
ntownsend

13
O que é realmente mencionado na documentação é o seguinte: "Para obter o melhor resultado, o script angular.js deve ser carregado na seção head do arquivo html; alternativamente , a regra css (acima) deve ser incluída na folha de estilo externa do aplicativo. "
Andriy Drozdyuk 01/04

4
Em outras palavras, se você estiver adicionando referências ao script na parte inferior da página (como muitas pessoas fazem); depois adicione a regra ao seu CSS.
precisa saber é o seguinte

1
Eu estava adicionando angular.js com require.js, então isso me ajudou.
olive

1
Adicionada a diretiva ng-cloak ao elemento html que hospeda a diretiva ng-app. Funcionou como um encanto. Exemplo: <div ng-cloak ng-app = "my-app">
miniscem

33

Verifique se AngularJS está incluído no headHTML. Consulte o documento ngCloak :

Para o melhor resultado, o script angular.js deve ser carregado na seção head do arquivo html; Como alternativa, a regra css (acima) deve ser incluída na folha de estilo externa do aplicativo.


3
sim! Não consigo entender por que as pessoas em todos os lugares parecem recomendar o carregamento do angular.js no final da página. Eu me sinto melhor se a Angular assumir o controle desde o início. Meu ng-cloakestá trabalhando agora.
Ivan Ferrer Villa

2
Eu concordo - a coisa sobre os scripts sendo carregados no final vem do desenvolvimento normal da Web, em que você deseja que a página exiba algo antes que o js faça, mas no caso do angular, você realmente deseja o contrário.
ver mais nítida

1
E antes que as folhas de estilo sejam carregadas. A inclusão de Angular na headfolha de estilos mas depois inclui, não corrige o problema.
AgmLauncher

27

Eu nunca tive muita sorte usando o ngCloak. Ainda fico tremendo apesar de tudo mencionado acima. A única maneira segura de evitar movimentos rápidos é colocar seu conteúdo em um modelo e incluí-lo. Em um SPA, o único HTML que será avaliado antes de ser compilado pelo Angular é a sua página principal index.html.

Basta pegar tudo dentro do corpo e colá-lo em um arquivo separado e depois:

<ng-include src="'views/indexMain.html'"></ng-include>

Você nunca deve piscar dessa maneira, pois o Angular compila o modelo antes de adicioná-lo ao DOM.


1
Exatamente o que eu uso - limpo e simples, sem hacks dolorosos.
Dmitri Zaitsev

2
Esteja ciente de que ng-includegera uma solicitação AJAX adicional para buscar o conteúdo do servidor. Aprendi da maneira mais difícil que você nunca deve usar por ng-includedentro ng-repeat, por exemplo.
jsuddsjr

1
trabalhou para mim. lembre-se de manter ng-appfora da ng-includemarcação.
GraehamF

2
Esta solução funciona melhor, sem soluços. Se possível, use esta solução.
Idudotnosn

2
Essa solução corrigiu uma situação realmente irritante. Obrigado!
Maxwelll

22

ngBind e ngBindTemplate são alternativas que não requerem CSS:

<div ng-show="foo != null" ng-cloak>{{name}}</div>  <!-- requires CSS -->
<div ng-show="foo != null" ng-bind="name"></div>
<div ng-show="foo != null" ng-bind-template="name = {{name}}"></div>

1
Resposta agradável e simples. ng-bindé uma boa maneira de evitar o 'flash de chaves' ou ter que usar ng-cloakno nível da tag, embora algumas pessoas pensem que isso torna o código menos legível. Para eles, não vejo uma razão para não misturar as duas abordagens.
perfil completo de Dave Everitt

1
ng-bind é muito melhor abordagem para o problema como as outras respostas exigem que você carregue primeiro angular, há chaves piscar em tudo em qualquer circunstância
legramira

20

Além da resposta aceita, se você estiver usando um método alternativo para ativar o ng-cloak ...

Você também pode adicionar algumas especificidades adicionais ao seu CSS / LESS:

[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],
.ng-cloak, .x-ng-cloak,
.ng-hide {
    display: none !important;
}

1
Isso funcionou para o meu caso de uso, quando nenhuma das opções acima parecia fazer o trabalho.
Porlune

15

Eu tive um problema semelhante e descobri que se você tiver uma classe que contém transições, o elemento piscará. Tentei adicionar ng-cloak sem sucesso, mas removendo a transição, o botão parou de piscar.

Eu estou usando estrutura iônica e o contorno do botão tem essa transição

.button-outline {
  -webkit-transition: opacity .1s;
  transition: opacity .1s;
}

Basta substituir a classe para remover a transição e o botão irá parar de piscar.

Atualizar

Novamente no iônico, há uma tremulação ao usar ng-show / ng-hide. Adicionar o seguinte CSS resolve:

.ng-hide-add,
.ng-hide-remove {
  display: none !important;
}

Fonte: http://forum.ionicframework.com/t/beta-14-ng-hide-show/14270/9


1
Mas isso não desativaria as animações das diretivas ng-hide / show?
Kushagra Gour

1
Não me lembro. Você tentou e desativou as animações?
precisa saber é o seguinte

1
Obrigado. Este é um problema muito especial no iônico. Eu adicionei .button-clear, .button-icon, .button-outline { @include transition(opacity 0s); }ao meu scss.
hgoebl

9

Eu tive um problema em que um <div ng-show="expression">seria inicialmente visível por uma fração de segundo, mesmo que "expressão" fosse inicialmente falsa, antes que a diretiva ng-show tivesse a chance de ser executada.

A solução que usei foi adicionar manualmente a classe "ng-hide", como em <div ng-show="expression" ng-hide>, para garantir que ela fosse ocultada inicialmente. A diretiva ng-show adicionará / removerá a classe ng-hide conforme necessário depois disso.


1
Uau, de todas as opções loucas que eu tentei, isso fez o truque. Obrigado!
Nikola

Melhor solução! Isso me deixou louco por vários meses! Obrigado!
Abelabbesnabi 25/05

Eu estou usando quadro iônica e esta é a única resposta que realmente funciona
Mikel

7

Tente desligar o Firebug . Estou falando sério. Isso ajuda no meu caso.

Aplique a resposta aceita e verifique se o Firebug no Firefox está desativado : pressione F12 e, em seguida, desative o Firebug para esta página - pequeno botão no canto superior direito.


Sim, isso fez por mim Obrigado!
MadeInDreams 27/02

Obrigado, isso estava me deixando louco. Erro
Stephen Simpson

6

Na verdade, existem dois problemas separados que podem causar o problema de cintilação e você pode estar enfrentando um ou ambos.

Problema 1: o ng-cloak é aplicado tarde demais

Esse problema foi resolvido conforme descrito em muitas das respostas nesta página, para garantir que o AngularJS seja carregado na cabeça. Consulte o documento ngCloak :

Para o melhor resultado, o script angular.js deve ser carregado na seção head do arquivo html; Como alternativa, a regra css (acima) deve ser incluída na folha de estilo externa do aplicativo.

Problema 2: ng-cloak é removido muito cedo

É provável que esse problema ocorra quando você tiver muito CSS em sua página com regras em cascata umas sobre as outras e as camadas mais profundas do CSS piscarem antes da aplicação da camada superior.

As soluções jQuery nas respostas que envolvem adicionar style="display:none"ao seu elemento resolvem esse problema desde que o estilo seja removido com atraso suficiente (na verdade, essas soluções resolvem os dois problemas). No entanto, se você preferir não adicionar estilos diretamente ao seu HTML, poderá obter os mesmos resultados usando ng-show.

Começando com o exemplo da pergunta:

<ul ng-show="foo != null" ng-cloak>..</ul>

Adicione uma regra ng-show adicional ao seu elemento:

<ul ng-show="isPageFullyLoaded && (foo != null)" ng-cloak>..</ul>

(Você precisa se manter ng-cloakpara evitar o problema 1).

Em seguida, no seu app.run definido isPageFullyLoaded:

app.run(['$rootScope', function ($rootScope) {
    $rootScope.$safeApply = function (fn) {
        $rootScope.isPageFullyLoaded = true;
    }
}]);

Esteja ciente de que, dependendo exatamente do que você está fazendo, o app.run pode ou não ser o melhor local para definir isPageFullyLoaded. O importante é garantir que a isPageFullyLoadedconfiguração seja verdadeira depois que o que você não quiser piscar estiver pronto para ser revelado ao usuário.

Parece que o Problema 1 é o problema que o OP está enfrentando, mas outros estão descobrindo que a solução não funciona ou apenas parcialmente porque está atingindo o Problema 2 ou também.

Nota importante: Certifique-se de aplicar soluções às duas mangas ng que estão sendo aplicadas muito tarde E removidas em breve. Resolver apenas um desses problemas pode não aliviar os sintomas.


1
este fixa-lo para mim "script deve ser colocado na secção da cabeça"
aliopi

4

Encontramos esse problema em nossa empresa e o resolvemos adicionando "display: none" ao estilo CSS dos elementos oscilantes do ng-show. Não precisávamos usar ng-cloak. Ao contrário de outros neste segmento, enfrentamos esse problema no Safari, mas não no Firefox ou Chrome - possivelmente devido ao bug preguiçoso de repintar o Safari no iOS7 .


3

Pelo que vale, tive um problema semelhante que o ng-manto não está funcionando. Pode valer a pena verificar seu aplicativo / site com o cache ativado para reutilizar arquivos de origem para ver se isso ajuda.

Com o meu encontro com oscilação, eu estava testando com o DevTools aberto e com o cache desativado. Deixar o painel fechado com o cache ativado corrigiu meu problema.


3

Manter as instruções abaixo na tag head corrigiu esse problema

<style type="text/css">
    [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
    display: none !important;
}
</style>

documentação oficial


3

Como não consegui fazer com que nenhum desses métodos funcionasse, fiz o seguinte. Para o elemento que você deseja ocultar inicialmente:

<div <!--...--> style="display: none;" ng-style="style">

Em seguida, no seu controlador, adicione-o no topo ou perto dele:

$scope.style = { display: 'block' };

Dessa forma, o elemento é oculto inicialmente e só é exibido quando o código do controlador foi realmente executado.

Você pode ajustar o canal às suas necessidades, talvez adicionando alguma lógica. No meu caso, eu mudo para um caminho de login, se não estiver conectado no momento, e não queria que minha interface tremeluzesse antes, então defini $scope.styleapós a verificação de login.


2

É melhor usar em ng-ifvez de ng-show. ng-if remove completamente e recria o elemento no DOM e ajuda a evitar que os ng-shows piscem.


mas também destrói todos os plugins que funcionam em que parte do dom ... (por exemplo: jQuery UI)
Geert Bellemans


2

é melhor fazer referência a um documento angular, pois a versão [1.4.9] possui uma atualização abaixo que permite suportar a diretiva data-ng-cloak.

[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
  display: none !important;
}

2

Eu tentei a solução ng-cloak acima, mas ela ainda tem problemas intermitentes com o Firefox. A única solução alternativa que funcionou para mim é atrasar o carregamento do formulário até que o Angular esteja totalmente carregado.

Eu simplesmente adicionei ng-init no aplicativo e use ng-if no lado do formulário para verificar se a variável que eu defini já está carregada.

<div ng-app="myApp" ng-init="loaded='yes'"> 
   <form ng-if="loaded.length > 0">
      <!--all my elements here-->
   </form>
</div>

1

Além de outras respostas, se você achar que o flash do código do modelo ainda está ocorrendo, é provável que você tenha seus scripts na parte inferior da página e isso significa que a diretiva ng-cloak diretiva não funcionará. Você pode mover seus scripts para a cabeça ou criar uma regra CSS.

Os documentos dizem "Para obter o melhor resultado, o script angular.js deve ser carregado na seção principal do documento html; como alternativa, a regra css acima deve ser incluída na folha de estilo externa do aplicativo".

Agora, não precisa ser uma folha de estilo externa, mas apenas um elemento na cabeça.

<style type="text/css">
  .ng-cloak {
    display: none !important;
  }
</style>

fonte: https://docs.angularjs.org/api/ng/directive/ngCloak


1

Eu tentei todas as soluções postadas aqui e ainda fiquei piscando no Firefox.

Se isso ajuda alguém, resolvi adicionando style="display: none;"ao conteúdo principal div e, em seguida, usando o jQuery (eu já estava usando na página) $('#main-div-id').show();depois que tudo foi carregado depois de obter dados do servidor;


Eu descobri que essa era a única solução que funcionava para mim, mas eu queria evitar o uso do JQuery para encontrar uma alternativa. Veja minha resposta aqui: stackoverflow.com/a/42527700/4214694
Andrew Downes

1

Na verdade, achei que a sugestão do Log da Web de Rick Strahl corrigia meu problema perfeitamente (como eu ainda tinha o estranho problema de ng-cloak piscar em bruto {{code}} às vezes, especialmente durante a execução do Firebug):

A opção nuclear: ocultando o conteúdo manualmente

Usar o CSS explícito é a melhor opção; portanto, o seguinte nunca deve ser necessário. Mas vou mencioná-lo aqui, pois fornece algumas dicas de como você pode ocultar / mostrar conteúdo manualmente durante o carregamento para outras estruturas ou em seus próprios modelos baseados em marcação.

Antes de descobrir que eu poderia incorporar explicitamente o estilo CSS na página, tentei descobrir por que o ng-cloak não estava fazendo seu trabalho. Depois de perder uma hora chegando a lugar nenhum, finalmente decidi ocultar e mostrar manualmente o contêiner. A idéia é simples - oculte o contêiner inicialmente e mostre-o assim que o Angular tiver processado e removido a marcação do modelo da página.

Você pode ocultar manualmente o conteúdo e torná-lo visível após o controle da Angular. Para fazer isso, usei:

<div id="mainContainer" class="mainContainer boxshadow"
    ng-app="app" style="display:none">

Observe a exibição: nenhum estilo que oculte explicitamente o elemento inicialmente na página.

Depois que o Angular executar sua inicialização e processar efetivamente a marcação do modelo na página, você poderá mostrar o conteúdo. Para Angular, este evento 'ready' é a função app.run ():

app.run( function ($rootScope, $location, cellService) {        
    $("#mainContainer").show();
    
});

Isso efetivamente remove a exibição: nenhum estilo e o conteúdo são exibidos. No momento em que o app.run () é acionado, o DOM está pronto para ser exibido com dados preenchidos ou pelo menos dados vazios - o Angular obteve controle.


Eu descobri que essa era a única solução que funcionava para mim, mas eu queria evitar o uso do JQuery para encontrar uma alternativa. Veja minha resposta aqui: stackoverflow.com/a/42527700/4214694
Andrew Downes

1

Eu tentei todas as respostas acima e nada funcionou. Usando o ionic para desenvolver um aplicativo híbrido e estava tentando fazer uma mensagem de erro não piscar. Acabei resolvendo meu problema adicionando uma classe ng-hide ao meu elemento. Minha div já tem ng-show para mostrar o elemento quando há um erro. Adicionando ng-hide, defina a div para não ser exibida antes do carregamento angular. Não é necessário usar capa angular ou adicionar angular à cabeça.


1

AS da discussão acima

[ng-cloak] {
                display: none;
            }

é a maneira perfeita de resolver o problema.


1

Estou usando o ng-show em uma diretiva para mostrar e ocultar pop-ups.

<div class="..." ng-show="showPopup">

Nenhuma das opções acima funcionou para mim, e usar ng-if em vez de ng-show seria um exagero. Isso implicaria remover e adicionar todo o conteúdo pop-up ao DOM a cada clique. Em vez disso, adicionei um ng-if ao mesmo elemento para garantir que ele não apareça no carregamento do documento:

<div class="..." ng-show="showPopup" ng-if="popupReady">

Depois, adicionei a inicialização no controlador responsável por essa diretiva com um tempo limite:

$timeout(function () {
    $scope.popupReady = true;
});

Dessa forma, eliminei o problema de oscilação e evitei a operação cara da inserção do DOM a cada clique. Isso custou o uso de duas variáveis ​​de escopo para a mesma finalidade, em vez de uma, mas até agora essa é definitivamente a melhor opção.


1

Tentei, ng-cloakmas ainda breves piscadas. Abaixo o código os livra completamente.

<body style="display:none;" ng-style="{'display':'block'}">

1

Nenhuma das soluções listadas acima funcionou para mim. Decidi então examinar a função real e percebi que, quando "$ scope.watch" era acionado, ele colocava um valor no campo de nome que não era o caso. Então, no código que eu defini, oldValue e newValue então

$scope.$watch('model.value', function(newValue, oldValue) {
if (newValue !== oldValue) {
validateValue(newValue);
}
});

Essencialmente, quando o scope.watch é acionado nesse caso, o AngularJS monitora as alterações na variável name (model.value)


0

Gostaria de envolver o <ul>com um<div ng-cloak>


2
Ele não deveria precisar embrulhar o <ul>. ng-cloakencobrirá qualquer elemento ao qual ele for aplicado, bem como os descendentes desse elemento.
btford

0

Pessoalmente, decidi usar o ng-classatributo em vez do ng-show. Eu tive muito mais sucesso nessa rota, especialmente em janelas pop-up que nem sempre são mostradas por padrão.

O que costumava ser <div class="options-modal" ng-show="showOptions"></div>

é agora: <div class="options-modal" ng-class="{'show': isPrintModalShown}">

com o CSS da classe options-modal sendo display: nonepor padrão. A classe show contém o display:blockCSS.


-2

Evite quebra de linha

<meta http-equiv="Content-Security-Policy"              content="
default-src 'FOO';   
script-src 'FOO';    
style-src  'FOO'; 
font-src 'FOO';">

Funciona com o Firefox 45.0.1

<meta http-equiv="Content-Security-Policy"              content="    default-src 'FOO';    script-src 'FOO';     style-src  'FOO';    font-src 'FOO';">
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.