expressions - ''this'' vs $ scope en los controladores AngularJS
angularjs expressions (7)
"¿Cómo funciona
this
y$scope
en los controladores AngularJS?"
Respuesta corta :
-
this
- Cuando se llama a la función de constructor del controlador,
this
es el controlador. - Cuando se llama a una función definida en un objeto
$scope
,this
es el "alcance en efecto cuando se llamó a la función". Este puede (o no puede) ser el$scope
que se define la función. Entonces, dentro de la función,this
y$scope
pueden no ser los mismos.
- Cuando se llama a la función de constructor del controlador,
-
$scope
- Cada controlador tiene un objeto
$scope
asociado. - Una función de controlador (constructor) es responsable de configurar las propiedades del modelo y las funciones / comportamiento en su
$scope
asociado. - Solo los métodos definidos en este objeto de
$scope
(y los objetos de alcance principal, si está en juego la herencia prototípica) son accesibles desde HTML / view. Por ejemplo, desdeng-click
, filtros, etc.
- Cada controlador tiene un objeto
Respuesta larga :
Una función de controlador es una función de constructor de JavaScript. Cuando la función del constructor se ejecuta (por ejemplo, cuando se carga una vista), this
(es decir, el "contexto de la función") se establece en el objeto controlador. Así que en la función constructora del controlador de "pestañas", cuando se crea la función addPane
this.addPane = function(pane) { ... }
se crea en el objeto controlador, no en $ scope. Las vistas no pueden ver la función addPane, solo tienen acceso a las funciones definidas en $ scope. En otras palabras, en el HTML, esto no funcionará:
<a ng-click="addPane(newPane)">won''t work</a>
Después de que se ejecute la función constructora del controlador de "pestañas", tenemos lo siguiente:
La línea negra discontinua indica la herencia prototípica; un ámbito aislado se hereda prototípicamente de Scope . (No se hereda de forma prototípica del ámbito de aplicación en el que se encontró la directiva en el HTML).
Ahora, la función de enlace de la directiva de panel quiere comunicarse con la directiva de pestañas (lo que realmente significa que debe afectar a las pestañas aísla el alcance de $) de alguna manera. Se podrían usar eventos, pero otro mecanismo es hacer que la directiva del panel require
el controlador de pestañas. (Parece que no hay ningún mecanismo para que la directiva del panel require
las pestañas $ scope).
Entonces, esto plantea la pregunta: si solo tenemos acceso al controlador de pestañas, ¿cómo obtenemos acceso a las pestañas aísla $ scope (que es lo que realmente queremos)?
Bueno, la línea roja punteada es la respuesta. El "alcance" de la función addPane () (me refiero al alcance / cierre de la función de JavaScript aquí) le da a la función acceso a las pestañas aísla $ alcance. Es decir, addPane () tiene acceso a las "pestañas IsolateScope" en el diagrama anterior debido a un cierre que se creó cuando se definió addPane (). (Si en su lugar definimos addPane () en el objeto tabs $ scope, la directiva del panel no tendrá acceso a esta función y, por lo tanto, no tendría forma de comunicarse con las pestañas $ scope).
Para responder a la otra parte de su pregunta: how does $scope work in controllers?
:
Dentro de las funciones definidas en $ scope, se establece en "el $ scope en efecto donde / cuando se llamó a la función". Supongamos que tenemos el siguiente HTML:
<div ng-controller="ParentCtrl">
<a ng-click="logThisAndScope()">log "this" and $scope</a> - parent scope
<div ng-controller="ChildCtrl">
<a ng-click="logThisAndScope()">log "this" and $scope</a> - child scope
</div>
</div>
Y el ParentCtrl
( ParentCtrl
) tiene
$scope.logThisAndScope = function() {
console.log(this, $scope)
}
Al hacer clic en el primer enlace, se mostrará que this
y $scope
son iguales, ya que " el alcance en efecto cuando se llamó a la función " es el alcance asociado con ParentCtrl
.
Al hacer clic en el segundo enlace se revelará this
y $scope
no son lo mismo, ya que " el alcance en efecto cuando se llamó a la función " es el alcance asociado con ChildCtrl
. Así que aquí, this
se establece en $scope
ChildCtrl
. Dentro del método, $scope
sigue siendo $scope
ParentCtrl
.
Intento no usar this
dentro de una función definida en $ scope, ya que se confunde qué $ scope está siendo afectado, especialmente considerando que ng-repeat, ng-include, ng-switch, y las directivas pueden crear sus propios ámbitos secundarios. .
En la sección "Crear componentes" de la página de inicio de AngularJS , hay un ejemplo:
controller: function($scope, $element) {
var panes = $scope.panes = [];
$scope.select = function(pane) {
angular.forEach(panes, function(pane) {
pane.selected = false;
});
pane.selected = true;
}
this.addPane = function(pane) {
if (panes.length == 0) $scope.select(pane);
panes.push(pane);
}
}
Observe cómo el método de select
se agrega a $scope
, pero el método addPane
se agrega a this
. Si lo cambio a $scope.addPane
, el código se rompe.
La documentación dice que, de hecho, hay una diferencia, pero no menciona cuál es la diferencia:
Las versiones anteriores de Angular (pre 1.0 RC) le permitieron usar
this
intercambiable con el método$scope
, pero este ya no es el caso. Dentro de los métodos definidos en el alcance,this
y$scope
son intercambiables (angular establecethis
en$scope
), pero no dentro del constructor de su controlador.
¿Cómo funciona this
y $scope
en los controladores AngularJS?
Las versiones anteriores de Angular (pre 1.0 RC) le permitieron usar esto de manera intercambiable con el método $ scope, pero este ya no es el caso. Dentro de los métodos definidos en el alcance, este y $ alcance son intercambiables (angular establece esto en $ alcance), pero no dentro del constructor de su controlador.
Para recuperar este comportamiento (¿alguien sabe por qué se cambió?) Puede agregar:
return angular.extend($scope, this);
al final de su función de controlador (siempre que se haya inyectado $ scope a esta función de controlador).
Esto tiene un buen efecto de tener acceso al ámbito principal a través del objeto controlador que puede obtener en child con require: ''^myParentDirective''
$ scope tiene un ''este'' diferente ''luego el controlador'' este ''. Por lo tanto, si coloca un console.log (este) dentro del controlador, le otorga un objeto (controlador) y this.addPane () agrega el método addPane al objeto controlador. Pero $ scope tiene un alcance diferente y todos los métodos en su alcance deben ser accedidos por $ scope.methodName (). this.methodName()
dentro del controlador significa agregar methos dentro del objeto controlador. $scope.functionName()
está en HTML y dentro
$scope.functionName(){
this.name="Name";
//or
$scope.myname="myname"//are same}
Pega este código en tu editor y abre la consola para ver ...
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>this $sope vs controller</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular.min.js"></script>
<script>
var app=angular.module("myApp",[]);
app.controller("ctrlExample",function($scope){
console.log("ctrl ''this''",this);
//this(object) of controller different then $scope
$scope.firstName="Andy";
$scope.lastName="Bot";
this.nickName="ABot";
this.controllerMethod=function(){
console.log("controllerMethod ",this);
}
$scope.show=function(){
console.log("$scope ''this",this);
//this of $scope
$scope.message="Welcome User";
}
});
</script>
</head>
<body ng-app="myApp" >
<div ng-controller="ctrlExample">
Comming From $SCOPE :{{firstName}}
<br><br>
Comming from $SCOPE:{{lastName}}
<br><br>
Should Come From Controller:{{nickName}}
<p>
Blank nickName is because nickName is attached to
''this'' of controller.
</p>
<br><br>
<button ng-click="controllerMethod()">Controller Method</button>
<br><br>
<button ng-click="show()">Show</button>
<p>{{message}}</p>
</div>
</body>
</html>
Acabo de leer una explicación bastante interesante sobre la diferencia entre los dos, y una creciente preferencia por adjuntar modelos al controlador y alias al controlador para vincular los modelos a la vista. http://toddmotto.com/digging-into-angulars-controller-as-syntax/ es el artículo. No lo menciona, pero al definir directivas, si necesita compartir algo entre varias directivas y no desea un servicio (hay casos legítimos en los que los servicios son una molestia), adjunte los datos al controlador de la directiva principal. El servicio $ scope ofrece muchas cosas útiles, siendo $ watch la más obvia, pero si todo lo que necesita es vincular los datos a la vista, usar el controlador plano y el ''controlador como'' en la plantilla está bien, y posiblemente sea preferible.
En este curso ( https://www.codeschool.com/courses/shaping-up-with-angular-js ) explican cómo usar "esto" y muchas otras cosas.
Si agrega el método al controlador a través de "este" método, debe llamarlo en la vista con el nombre del controlador "dot" su propiedad o método.
Por ejemplo, al usar su controlador en la vista, puede tener un código como este:
<div data-ng-controller="YourController as aliasOfYourController">
Your first pane is {{aliasOfYourController.panes[0]}}
</div>
La razón por la que ''addPane'' se asigna a esto es debido a la directiva <pane>
.
La directiva del pane
require: ''^tabs''
, que coloca el objeto controlador de pestañas desde una directiva principal, en la función de enlace.
addPane
se asigna a this
para que la función de enlace del pane
pueda verlo. Luego, en la función de enlace del pane
, addPane
es solo una propiedad del controlador de tabs
, y es solo tabsControllerObject.addPane. Por lo tanto, la función de enlace de la directiva de panel puede acceder al objeto controlador de pestañas y, por lo tanto, acceder al método addPane.
Espero que mi explicación sea lo suficientemente clara ... es un poco difícil de explicar.
Te recomiendo que leas el siguiente post: AngularJS: "Controller as" o "$ scope"?
Describe muy bien las ventajas de usar "Controlador como" para exponer variables sobre "$ alcance".
Sé que usted preguntó específicamente sobre métodos y no variables, pero creo que es mejor atenerse a una técnica y ser coherente con ella.
En mi opinión, debido al problema de las variables discutido en la publicación, es mejor usar la técnica "Controlador como" y aplicarla a los métodos.