Understanding Scopes in AngularJS Custom Directives
Uma olhada no uso de escopos compartilhados, herdados e isolados ao trabalhar com diretivas no AngularJS.
Nesta postagem, aprenderemos sobre diferentes tipos de escopos nas diretivas personalizadas do AngularJS. Para começar, começaremos com uma introdução de alto nível de diretivas e, em seguida, nos concentraremos nos escopos.
Directivas
As diretivas são um dos componentes mais importantes do AngularJS 1.X e têm as seguintes finalidades:
- Para dar um significado especial ao elemento existente
- Para criar um novo elemento
- Para manipular o DOM
Além de ng-app, ng-controller e ng-repeat, existem muitas diretivas integradas que vêm com o AngularJS, incluindo:
- ng-maxlength
- ng-minlength
- ng-pattern
- ng-obrigatório
- ng-submit
- ng-blur
- ng-change
- ng-checked
- ng-click
- ng-mouse
- ng-bind
- ng-href
- ng-init
- ng-model
- ng-src
- ng-style
- ng-app
- ng-controller
- ng-disabled
- ng-cloak
- ng-hide
- ng-if
- ng-repeat
- ng-show
- ng-switch
- ng-view
Principalmente, as diretivas executam uma das seguintes tarefas:
- Manipulate DOM
- Iterate through data
- Manipular eventos
- Modify CSS
- Validate data
- Perform Data Binding
Embora haja muitas diretivas internas fornecidas pela equipe Angular, há momentos em que talvez seja necessário criar suas próprias diretivas personalizadas. Uma diretiva personalizada pode ser criada como um elemento, atributo, comentário ou classe. Neste post, uma diretiva personalizada muito simples pode ser criada, conforme mostrado na listagem abaixo:
MyApp.directive('helloWorld', function () {
return {
template: "Hello IG"
};
});
Ao criar diretivas personalizadas, é importante lembrar:
- O nome da diretiva deve estar no caso do camelo;
- Na exibição, a diretiva pode ser usada separando o nome do caso concatenado usando um traço, dois pontos, sublinhado ou uma combinação deles.
Scopes in Custom Directives
Os escopos entram em cena quando passamos dados para diretivas personalizadas. Existem três tipos de escopos, com alguns ilustrados respectivamente com a imagem:
- Shared scope
- Inherited scope
- Isolated scope

Podemos criar uma diretiva personalizada com um escopo herdado definindo a propriedade scope como true, conforme mostrado na listagem abaixo:
MyApp.directive('studentDirective', function () {
return {
template: "
{{student.name}} is {{student.age}} years old !!
",
replace: true,
restrict: 'E',
scope : true ,
controller: function ($scope) {
console.log($scope);
}
}
});
Escopo compartilhado e herdado
O escopo compartilhado e o escopo herdado são relativamente mais fáceis de entender. Em um escopo compartilhado, as diretivas compartilham o escopo com o controlador fechado.
Vamos supor que temos um controlador, conforme mostrado na listagem abaixo:
MyApp.controller("StudentController", [
"$scope",
function ($scope) {
console.log($scope);
$scope.student = {
name: "dj",
age: 32,
subject: ["math", "geography"],
};
$scope.setGrade = function (student) {
student.grade = "A+";
};
},
]);
Next, let’s go ahead and create a custom directive:
MyApp.directive('studentDirective', function () {
return {
template: "
{{student.name}} is {{student.age}} years old !!
",
replace: true,
restrict: 'E',
controller: function ($scope) {
console.log($scope);
}
}
});
Aqui, podemos usar a diretiva student na exibição:
<div ng-controller="StudentController">
<student-directive> </student-directive>
</div>
No trecho acima, estamos usando a diretiva dentro do div, onde a diretiva ng-controller é definida como StudentController. Como não definimos nenhum valor para a propriedade scope na diretiva, por padrão, isso funciona no modo de escopo compartilhado. As diretivas podem acessar as propriedades anexadas ao escopo do controlador. Quaisquer alterações nas propriedades da diretiva seriam refletidas no controlador e vice-versa. Você também notará que estou imprimindo o ID do escopo para o controlador e a diretiva, e ambos os IDs devem ser os mesmos.

Há um problema com o escopo compartilhado: não podemos passar dados explicitamente para a diretiva; A diretiva obtém diretamente os dados do controlador incluso.
No escopo herdado, a diretiva herda o escopo do controlador. Vamos dar uma olhada em como criar uma diretiva com escopo herdado abaixo:
MyApp.directive('studentDirective', function () {
return {
template: "
{{student.name}} is {{student.age}} years old !!
",
replace: true,
restrict: 'E',
scope : true ,
controller: function ($scope) {
console.log($scope);
}
}
});
Um escopo herdado é muito útil em diretivas personalizadas aninhadas.
Isolated Scope
No escopo isolado, a diretiva não compartilha um escopo com o controlador; Tanto a diretiva quanto o controlador têm seu próprio escopo. Os dados, no entanto, podem ser passados para o escopo da diretiva de três maneiras possíveis.
- Os dados podem ser passados como uma string usando o literal @ string
- Os dados podem ser passados como um objeto usando o literal = string
- 3. Os dados podem ser passados como uma função do literal de string &

Um escopo isolado é muito importante porque nos permite passar dados diferentes para o controlador. Para entender melhor, vamos supor que temos um controlador conforme listado abaixo:
MyApp.controller("ProductController", function ($scope) {
$scope.product1 = {
name: 'Phone',
price: '100',
stock: true
};
$scope.product2 = {
name: 'TV',
price: '1000',
stock: false
};
$scope.product3 = {
name: 'Laptop',
price: '800',
stock: false
};
$scope.ShowData = function () {
alert("Display Data");
}
});
Como você pode ver aqui, temos três produtos diferentes e queremos passá-los de forma diferente.
Passar dados como uma string
No escopo isolado, podemos passar dados como uma string usando o literal de string @. Podemos criar uma diretiva personalizada que aceitará a string como um parâmetro de entrada, conforme demonstrado na listagem abaixo:
MyApp.directive('inventoryProduct', function () {
return {
restrict: 'E',
scope: {
name: '@',
price:'@'
},
template: '
{{name}} costs {{price}} $
Change name
'
};
});
Na listagem acima, estamos passando dois parâmetros de string usando o @ literal, o que significa que uma string será passada na variável name e price. A diretiva pode ser usada na exibição onde, no exemplo, você verá que estamos passando um valor de string para name e o price na diretiva.
<div ng-controller="ProductController">
<h1>{{product1.name}}</h1>
<inventory-product name="{{product1.name}}" price="{{product1.price}}"></inventory-product>
</div>
Ao executar o aplicativo, devemos ver o nome e o preço do produto1.

Quando clicamos no botão Alterar nome, apenas o nome da diretiva será alterado e o objeto product1 do ProductController não será afetado devido ao escopo isolado.

Lembre-se também de que, quando passamos dados em escopo isolado como uma string, eles são passados de maneira unidirecional, portanto, qualquer alteração no escopo do controlador será refletida na diretiva. No entanto, uma alteração na diretiva não seria refletida no controlador.
Pass Data As an Object
No escopo isolado, podemos passar dados como um objeto usando o literal de string the=. Podemos criar uma diretiva personalizada que aceitará um objeto como parâmetro de entrada, conforme mostrado na listagem abaixo:
MyApp.directive('inventoryProduct', function () {
return {
restrict: 'E',
scope: {
data: '='
},
template: '
{{data.name}} costs {{data.price}} $
Change name
'
};
});
Na listagem acima, estamos passando um parâmetro de objeto usando the = literal. Aqui, o objeto será passado para a variável de dados. A diretiva pode ser usada na exibição, conforme mostrado na listagem abaixo. Como vemos, estamos passando um valor de objeto para uma variável de dados na diretiva.
<div ng-controller="ProductController">
<h1>{{product1.name}}</h1>
<inventory-product data="product1"></inventory-product>
<h1>{{product2.name}}</h1>
<inventory-product data="product2"></inventory-product>
<h1>{{product3.name}}</h1>
<inventory-product data="product3"></inventory-product>
</div>
De acordo com a listagem, estamos usando as diretivas três vezes e passando três objetos distintos como entrada. Na execução, veremos a saída conforme mostrado abaixo:

Passar o objeto no escopo isolado funciona no modo de associação bidirecional, o que significa que quaisquer alterações na diretiva seriam refletidas no controlador fechado. Digamos que passamos o produto1 duas vezes, conforme mostrado na listagem abaixo:
<div ng-controller="ProductController">
<inventory-product data="product1"></inventory-product>
<inventory-product data="product1"></inventory-product>
</div>
Quando executarmos o aplicativo, o mesmo objeto será passado para ambas as instâncias da diretiva.

Clicar em qualquer um dos botões Alterar nome mudará o nome de ambas as instâncias das diretivas porque o mesmo objeto é passado e a passagem de um objeto funciona no modo bidirecional. Qualquer alteração na diretiva seria refletida no controlador anexo e vice-versa.

Calling an External Function
Podemos chamar uma função externa na diretiva fechada usando a variável literal &. Conforme observado com o ProductController, há uma função ShowData(). Essa função pode ser chamada em uma diretiva personalizada modificando a diretiva, conforme mostrado abaixo:
MyApp.directive('inventoryProduct', function () {
return {
restrict: 'E',
scope: {
data: '&',
},
template: '
{{data.name}} costs {{data.price}} $
Change name
'
};
});
Aqui, a diretiva pode ser usada na exibição mostrada aqui:
<div ng-controller="ProductController"> <inventory-product data="ShowData()"></inventory-product> </div>
Conclusão
Neste post, começamos com um entendimento básico das diretivas e depois passamos para os escopos, onde aprendemos sobre:
- Escopo compartilhado: diretiva e controladores compartilham o escopo e os dados. Não podemos passar dados explicitamente para a directiva.
- Inherited scope: herda o escopo do controlador. Não podemos passar dados explicitamente para a directiva.
- Escopo isolado: a diretiva e os controladores não compartilham os dados e o escopo. Podemos passar dados como uma string ou um objeto explicitamente para a diretiva.
Espero que você ache este post útil e, depois de trabalhar por conta própria com as diretivas, dê uma olhada em nosso conjunto avançado de controles e componentes de interface do usuário HTML5 e JavaScript, Ignite UI. Você pode baixar o IgniteUI agora e ver o que ele pode fazer por você! Obrigado por ler!
