angular1 - angularjs restrict directive




Ao escrever uma diretiva no AngularJS, como decido se não preciso de um novo escopo, um novo escopo filho ou um novo escopo isolado? (4)

Minha política pessoal e experiência:

Isolado: uma sandbox privada

Eu quero criar um monte de métodos de escopo e variáveis ​​que são usadas apenas pela minha diretiva e nunca são vistas ou acessadas diretamente pelo usuário. Quero colocar na lista de permissões os dados do escopo disponíveis para mim. Eu posso usar a transclusão para permitir que o usuário retorne ao escopo pai (não afetado) . Eu não quero minhas variáveis ​​e métodos acessíveis em crianças transcluídas.

Criança: uma subseção de conteúdo

Eu quero criar métodos de escopo e variáveis ​​que podem ser acessados ​​pelo usuário, mas não são relevantes para escopos circundantes (irmãos e pais) fora do contexto da minha diretiva. Eu também gostaria de deixar que TODOS os dados do escopo pai caíssem de forma transparente.

Nenhum: diretivas simples, somente leitura

Eu realmente não preciso mexer com métodos ou variáveis ​​de escopo. Eu provavelmente estou fazendo algo que não tem a ver com escopos (como exibir plugins jQuery simples, validação, etc).

Notas

  • Você não deve permitir que ngModel ou outras coisas afetem diretamente sua decisão. Você pode contornar o comportamento estranho fazendo coisas como ng-model=$parent.myVal (child) ou ngModel: '=' (isolate).
  • Isolate + transclude irá restaurar todo o comportamento normal das diretivas irmãs e retornará ao escopo pai, portanto, não deixe que isso afete seu julgamento também.
  • Não mexa no escopo de nenhum porque é como colocar dados no escopo da metade inferior do DOM, mas não na metade superior, o que faz sentido.
  • Preste atenção às prioridades da diretiva (não tenha exemplos concretos de como isso pode afetar as coisas)
  • Injete serviços ou use controladores para se comunicar entre diretivas com qualquer tipo de escopo. Você também pode require: '^ngModel' para procurar nos elementos pai.

Estou procurando algumas diretrizes que podem ser usadas para ajudar a determinar qual tipo de escopo usar ao escrever uma nova diretiva. O ideal é que eu goste de algo semelhante a um fluxograma que me passe por várias perguntas e encontre a resposta correta - nenhum novo novo escopo, novo escopo filho ou novo escopo isolado - mas isso provavelmente está exigindo demais. Aqui está o meu atual conjunto de diretrizes:

Estou ciente de que o uso de uma diretiva com um escopo isolado em um elemento força todas as outras diretivas no mesmo elemento a usar o mesmo (um) escopo isolado, portanto isso não limita severamente quando um escopo isolado pode ser usado?

Eu espero que alguns membros da equipe da Angular-UI (ou outros que escreveram muitas diretivas) possam compartilhar suas experiências.

Por favor, não adicione uma resposta que simplesmente diz "use um escopo isolado para componentes reutilizáveis".


Apenas pensei em adicionar meu entendimento atual e como ele se relaciona com outros conceitos do JS.

Padrão (por exemplo, não declarado ou escopo: falso)

Isso é filosoficamente equivalente ao uso de variáveis ​​globais. Sua diretiva pode acessar tudo no controlador pai, mas também está afetando-os e sendo afetados ao mesmo tempo.

escopo:{}

Isso é como um módulo, qualquer coisa que ele queira usar precisa ser passada explicitamente. Se EVERY diretiva que você usar for um escopo isolado, pode ser o equivalente a fazer com que CADA arquivo JS você escreva seu próprio módulo com muita sobrecarga ao injetar todas as dependências.

escopo: criança

Este é o meio termo entre variáveis ​​globais e passagem explícita. É semelhante à cadeia de protótipos do javascript e apenas estende uma cópia do escopo pai. Se você criar um escopo isolado e passar em todos os atributos e funções do escopo pai, ele será funcionalmente equivalente a isso.

A chave é que qualquer diretiva pode ser escrita de qualquer maneira. As diferentes declarações de escopo estão lá apenas para ajudá-lo a se organizar. Você pode transformar tudo em um módulo ou simplesmente usar todas as variáveis ​​globais e ser muito cuidadoso. Para facilitar a manutenção, é preferível modularizar sua lógica em partes logicamente coerentes. Há um equilíbrio entre um campo aberto e uma cadeia fechada. A razão pela qual isso é complicado, acredito, é que quando as pessoas aprendem sobre isso, pensam que estão aprendendo sobre como as diretivas funcionam, mas na verdade estão aprendendo sobre organização de código / lógica.

Outra coisa que me ajudou a descobrir como funcionam as diretivas é aprender sobre o ngInclude. O ngInclude ajuda você a incluir parciais em html. Quando comecei a usar diretivas, descobri que você poderia usar sua opção de modelo para reduzir seu código, mas eu não estava realmente anexando nenhuma lógica.

É claro que entre as diretivas angulares e o trabalho da equipe de angular-ui ainda não tive que criar minha própria diretiva que faça algo substancial, de modo que minha opinião sobre isso pode estar completamente errada.


Eu concordo com o Umur. Em teoria, os escopos isolados parecem maravilhosos e "portáteis", mas ao criar meu aplicativo para envolver funcionalidades não-triviais, deparei-me com a necessidade de incorporar várias diretivas (algumas aninhadas dentro de outras ou adicionando atributos a elas) para escrever HTML próprio, que é o propósito de uma linguagem específica de domínio.

No final, é muito estranho ter que passar cada valor global ou compartilhado para baixo da cadeia com vários atributos em cada chamada DOM de uma diretiva (como é exigido com o escopo isolate). Parece idiota escrever repetidamente tudo isso no DOM e parece ineficiente, mesmo que sejam objetos compartilhados. Também complica desnecessariamente as declarações da directiva. A solução alternativa de usar $ parent para "alcançar" e pegar valores da diretiva HTML parece Very Bad Form.

Eu também acabei mudando o meu aplicativo para ter principalmente diretivas de escopo filho com poucos isolados - apenas aqueles que não precisam acessar QUALQUER COISA do pai, além do que podem ser passados ​​através de atributos simples e não repetitivos.

Tendo sonhado o sonho das linguagens específicas por domínio durante décadas antes de existir tal coisa, estou entusiasmado com o fato de o AngularJS fornecer essa opção e eu sei que, quanto mais desenvolvedores trabalharem nessa área, mais alguns aplicativos interessantes Também é fácil para seus arquitetos escrever, expandir e depurar.

- D


Que ótima pergunta! Eu adoraria ouvir o que os outros têm a dizer, mas aqui estão as diretrizes que uso.

A premissa de alta altitude: o escopo é usado como a "cola" que usamos para se comunicar entre o controlador pai, a diretiva e o modelo de diretiva.

Escopo pai: scope: false , portanto, nenhum novo escopo em tudo

Eu não uso isso com muita frequência, mas, como disse @MarkRajcok, se a diretiva não acessa nenhuma variável de escopo (e obviamente não define nenhuma!), Então está tudo bem no que me diz respeito. Isso também é útil para diretivas filho que são usadas apenas no contexto da diretiva pai (embora sempre haja exceções) e que não tenham um modelo. Basicamente, qualquer coisa com um modelo não pertence ao compartilhamento de um escopo, porque você está expondo inerentemente esse escopo para acesso e manipulação (mas tenho certeza de que há exceções a essa regra).

Como exemplo, criei recentemente uma diretiva que desenha um gráfico de vetor (estático) usando uma biblioteca SVG que estou no processo de gravação. Ele $observe dois atributos ( width e height ) e os usa em seus cálculos, mas não define nem lê variáveis ​​de escopo e não tem modelo. Esse é um bom caso de uso para não criar outro escopo; nós não precisamos de um, então por que se preocupar?

Mas em outra diretiva SVG, no entanto, eu precisei de um conjunto de dados para usar e, além disso, tive que armazenar um pouquinho de estado. Nesse caso, usar o escopo pai seria irresponsável (novamente, em geral). Então, ao invés disso ...

Escopo infantil: scope: true

Diretivas com um escopo filho são sensíveis ao contexto e destinam-se a interagir com o escopo atual.

Obviamente, uma vantagem importante disso sobre um escopo isolado é que o usuário está livre para usar a interpolação em qualquer atributo desejado; por exemplo, usar class="item-type-{{item.type}}" em uma diretiva com um escopo isolate não funcionará por padrão, mas funciona bem em um com escopo filho, porque o que for interpolado ainda pode ser encontrado por padrão o escopo pai. Além disso, a própria diretiva pode avaliar com segurança atributos e expressões no contexto de seu próprio escopo, sem se preocupar com a poluição ou danos aos pais.

Por exemplo, uma dica de ferramenta é algo que acaba de ser adicionado; um escopo isolado não funcionaria (por padrão, veja abaixo) porque é esperado que usemos outras diretivas ou atributos interpolados aqui. A dica de ferramenta é apenas um aprimoramento. Mas a dica de ferramenta também precisa definir algumas coisas no escopo para usar com uma sub-diretiva e / ou modelo e, obviamente, para gerenciar seu próprio estado, portanto, seria muito ruim usar o escopo pai. Nós estamos poluindo ou danificando-o, e também não é bom.

Eu me vejo usando escopos filho com mais freqüência do que isolar ou escopos pai.

Isolar escopo: scope: {}

Isso é para componentes reutilizáveis. :-)

Mas, falando sério, penso em "componentes reutilizáveis" como "componentes independentes". A intenção é que eles sejam usados ​​para uma finalidade específica, portanto, combiná-los com outras diretivas ou adicionar outros atributos interpolados ao nó DOM inerentemente não faz sentido.

Para ser mais específico, qualquer coisa necessária para essa funcionalidade autônoma é fornecida através de atributos especificados avaliados no contexto do escopo pai; elas são strings unidirecionais ('@'), expressões unidirecionais ('&') ou vinculações variáveis ​​bidirecionais ('=').

Em componentes independentes, não faz sentido precisar aplicar outras diretivas ou atributos porque existe por si só. Seu estilo é governado por seu próprio modelo (se necessário) e pode ter o conteúdo apropriado transcluído (se necessário). É independente, então colocamos em um escopo isolado também para dizer: "Não mexa com isso. Estou dando a você uma API definida por meio desses poucos atributos".

Uma boa prática recomendada é excluir o máximo possível de material baseado em modelo do link da diretiva e das funções do controlador. Isso fornece outro ponto de configuração "API-like": o usuário da diretiva pode simplesmente substituir o modelo! A funcionalidade permaneceu a mesma, e sua API interna nunca foi tocada, mas podemos mexer no estilo e na implementação DOM o quanto for necessário. O ui / bootstrap é um ótimo exemplo de como fazer isso bem porque Peter & Pawel são incríveis.

Escopos isolados também são ótimos para uso com transclusão. Tome abas; elas não são apenas a funcionalidade total, mas o que estiver dentro dela pode ser avaliado livremente a partir do escopo pai, deixando as guias (e painéis) para fazer o que quiserem. As guias claramente têm seu próprio estado , que pertence ao escopo (para interagir com o modelo), mas esse estado não tem nada a ver com o contexto em que foi usado - é inteiramente interno ao que torna uma diretiva de guia uma diretiva de guia. Além disso, não faz muito sentido usar qualquer outra diretiva com as guias. Eles são guias - e nós já temos essa funcionalidade!

Envolva-o com mais funcionalidade ou transclude mais funcionalidades, mas a diretiva é o que já é.

Tudo o que disse, devo observar que existem maneiras de contornar algumas das limitações (ou seja, características) de um escopo isolado, como sugerido @ProLoser em sua resposta. Por exemplo, na seção de escopo filho, mencionei a interpolação em atributos não diretivos quebrando ao usar um escopo isolado (por padrão). Mas o usuário poderia, por exemplo, simplesmente usar class="item-type-{{$parent.item.type}}" e funcionaria novamente. Portanto, se houver uma razão convincente para usar um escopo isolado em um escopo filho, mas você estiver preocupado com algumas dessas limitações, saiba que é possível contornar praticamente todas elas, se necessário.

Resumo

Diretivas sem novo escopo são somente leitura; eles são totalmente confiáveis ​​(ou seja, internos ao aplicativo) e não tocam em jack. Diretivas com escopo filho adicionam funcionalidade, mas não são a única funcionalidade. Por fim, escopos isolados são para diretivas que são o objetivo inteiro; eles são autônomos, então está tudo bem (e mais "correto") para deixá-los desonestos.

Eu queria ter meus pensamentos iniciais, mas como penso em mais coisas, atualizarei isso. Mas caramba - isso é muito tempo para uma resposta SO ...

PS: Totalmente tangencial, mas já que estamos falando de escopos, eu prefiro dizer "prototípico", enquanto outros preferem "prototypal", que parece ser mais preciso, mas apenas rola para fora da língua de forma alguma boa. :-)





angularjs-scope