Qual é o significado de require: 'ngModel'?

92

Este é o HTML para minha diretiva:

<textarea data-modal="modal" data-mydir ng:model="abc"></textarea>

Em minha diretriz, tenho o seguinte:

return {
        require: 'ngModel',
        replace: true,
        scope: {
            modal: '=modal',
            ngModel: '=',
            pid: '=pid'
        },

Alguém pode me dizer qual é o significado de require: 'ngModel'? Eu vejo isso em muitas diretivas diferentes. Posso chamar isso de modal de dados?

Estou confuso porque quando mudo para modal de dados recebo uma mensagem do Angular dizendo

Controller 'ngModel', required by directive 'textarea', can't be found!
krusty.ar
fonte
Onde quer que você esteja usando esta diretiva, deve haver um atributo definido comong-model='property'
Chandermani
3
Posso ter um modelo data-ng em vez disso? Além disso, por que às vezes vejo: "require: '? NgModel'," É confuso.

Respostas:

117

A requireinstrução fornece o controlador para a diretiva nomeada como o quarto argumento para sua linkfunção. (Você pode usar ^para procurar o controlador em um elemento pai; ?torna-o opcional.) Portanto, require: 'ngModel'fornece o controlador para a ngModeldiretiva, que é umngModelController .

Os controladores de diretiva podem ser escritos para fornecer APIs que outras diretivas podem usar; com ngModelController, você obtém acesso a uma funcionalidade especial integrada ngModel, incluindo a obtenção e configuração do valor. Considere o seguinte exemplo:

<input color-picker ng-model="project.color">
app.directive('colorPicker', function() {
  return {
    require: 'ngModel',
    link: function(scope, element, attrs, ngModel) {
      element.colorPicker({
        // initialize the color to the color on the scope
        pickerDefault: scope.color,
        // update the ngModel whenever we pick a new color
        onColorChange: function(id, newValue) {
          scope.$apply(function() {
            ngModel.$setViewValue(newValue);
          });
        }
      });

      // update the color picker whenever the value on the scope changes
      ngModel.$render = function() {
        element.val(ngModel.$modelValue);
        element.change();                
      };
    }
  }
});

Esta diretiva usa o ngModelcontrolador para obter e definir o valor da cor do seletor de cores. Veja este exemplo JSFiddle: http://jsfiddle.net/BinaryMuse/AnMhx/

Se você estiver usando require: 'ngModel', provavelmente não deveria usar tambémngModel: '=' em seu escopo isolado; o ngModelControllerdá a você todo o acesso necessário para alterar o valor.

O exemplo inferior na página inicial do AngularJS também usa essa funcionalidade (exceto usando um controlador personalizado, não ngModel).


Quanto à capitalização de uma diretiva, por exemplo, ngModelvs ng-modelvs data-ng-model: enquanto Angular suporta o uso de vários formulários no DOM, quando você se refere a uma diretiva por nome (por exemplo, ao criar uma diretiva ou usando require), você sempre usa o lowerCamelCase forma do nome.

Michelle Tilley
fonte
2
Existe um motivo específico para require: 'ngModel'ser usado ngModel: '='?
ErikAGriffin
33

Conforme declarado na documentação de Criação de diretivas personalizadas : (Em primeiro lugar, para sua pergunta no comentário)

Posso ter um em data-ng-modelvez disso?

A resposta:

Prática recomendada : prefira usar o formato delimitado por traços (por exemplo, ng-bindpara ngBind). Se você quiser usar uma ferramenta de validação de HTML, você pode usar a dataversão prefixada (por exemplo, data-ng-bindpara ngBind). Os outros formulários mostrados acima são aceitos por motivos de legado, mas recomendamos evitá-los.

Exemplos:

<my-dir></my-dir>
<span my-dir="exp"></span>
<!-- directive: my-dir exp -->
<span class="my-dir: exp;"></span>

Em segundo lugar, o que ?ngModelrepresenta?

// Always use along with an ng-model
require: '?ngModel',

Ao usar sua diretiva, ela força seu uso junto com o atributo / controlador ng-model.

O requirecenário

(Extrato do livro AngularJS de Brad Green & Shyam Seshadri)

Outras diretivas podem ter esse controlador passado para eles com a sintaxe de propriedade require . A forma completa de exigir é semelhante a:

require: '^?directiveName'

Opções:

  1. directiveName

    Este nome com maiúsculas e minúsculas especifica de qual diretiva o controlador deve vir. Portanto, se nossa <my-menuitem>diretiva precisar encontrar um controlador em seu pai <my-menu>, nós o escreveremos como myMenu.

  2. ^

    Por padrão, o Angular obtém o controlador da diretiva nomeada no mesmo elemento. Adicionar este ^símbolo opcional indica também que você deve subir na árvore DOM para encontrar a diretiva. Para o exemplo, precisaríamos adicionar este símbolo; a corda final seria ^myMenu.

  3. ?

    Se o controlador necessário não for encontrado, o Angular lançará uma exceção para informá-lo sobre o problema. Adicionar um ?símbolo à string diz que este controlador é opcional e que uma exceção não deve ser lançada se não for encontrada. Embora pareça improvável, se quiséssemos permitir que <my-menu-item>s fosse usado sem um <mymenu>contêiner, poderíamos adicionar isso para uma string de solicitação final de ?^myMenu.

Radim Köhler
fonte
21

O require:'ngModel'e require:'^ngModel'permite que você injete o modelo anexado ao elemento ou seu elemento pai ao qual a diretiva está vinculada.

É basicamente a maneira mais fácil de passar ngModel para a função link / compilar em vez de passá-lo usando uma opção de escopo. Depois de ter acesso ao ngModel, você pode alterar seu valor usando $setViewValue, torná-lo sujo / limpo usando $formatters, aplicar observadores, etc.

Abaixo está um exemplo simples para passar ngModel e alterar seu valor após 5 segundos.

Demo: http://jsfiddle.net/t2GAS/2/

myApp.directive('myDirective', function($timeout) {
  return {
    restrict: 'EA',
    require: 'ngModel',
    link: function(scope, element, attrs, ngModel) {
        ngModel.$render = function() {
            $timeout(function() {
                ngModel.$setViewValue('StackOverflow');  
            }, 5000);                
        };
    }
  };
});
codef0rmer
fonte