¿Debo usar `this` o` $ scope`?

251

Hay dos patrones en uso para acceder a las funciones del controlador: thisy $scope.

¿Qué debo usar y cuándo? Entiendo que thisestá configurado para el controlador y $scopees un objeto en la cadena de alcance para las vistas. Pero con la nueva sintaxis "Controlador como Var", puede usar cualquiera de los dos fácilmente. Entonces, ¿qué es lo mejor y cuál es la dirección para el futuro?

Ejemplo:

  1. Utilizando this

    function UserCtrl() {
      this.bye = function() { alert('....'); };
    }
    
    <body ng-controller='UserCtrl as uCtrl'>
      <button ng-click='uCtrl.bye()'>bye</button>
    
  2. Utilizando $scope

    function UserCtrl($scope) {
        $scope.bye = function () { alert('....'); };
    }
    
    <body ng-controller='UserCtrl'>
        <button ng-click='bye()'>bye</button>
    

Personalmente, considero this.nameque es más fácil a la vista y más natural en comparación con otros patrones Javascript OO.

Consejos por favor?

Sentido Profundo
fuente
El uso de 'this' parece ser nuevo a partir de Google I / O 2013 m.youtube.com/watch?v=HCR7i5F5L8c Además, verifique esta respuesta: stackoverflow.com/questions/11605917/…
AlanW
¿Es nueva la sintaxis "UserCtrl as uCtrl"? No lo veo documentado en las páginas 1.0.6 o 1.1.4 ngController.
Mark Rajcok
Está bien, está documentado en la nueva página 1.1.5 ngController .
Mark Rajcok
1
Las mejores explicaciones para $ scope y este codetunnel.io/angularjs-controller-as-or-scope
Sai

Respuestas:

229

Ambos tienen sus usos. Primero, algo de historia ...

$ scope es la técnica "clásica", mientras que "controller as" es mucho más reciente (a partir de la versión 1.2.0 oficialmente, aunque apareció en versiones preliminares inestables antes de esto).

Ambos funcionan perfectamente bien y la única respuesta incorrecta es mezclarlos en la misma aplicación sin una razón explícita. Francamente, mezclarlos funcionará, pero solo aumentará la confusión. Así que elige uno y rueda con él. Lo más importante es ser consistente.

¿Cúal? Eso depende de ti. Hay muchos más ejemplos de $ alcance, pero "controlador como" también está ganando fuerza. ¿Es uno mejor que el otro? Eso es debatible. Entonces, ¿cómo eliges?

Comodidad

Prefiero el "controlador como" porque me gusta ocultar el $ alcance y exponer a los miembros del controlador a la vista a través de un objeto intermediario. Al configurar esto. *, Puedo exponer justo lo que quiero exponer del controlador a la vista. También puede hacer eso con $ scope, solo prefiero usar JavaScript estándar para esto. De hecho, lo codifico así:

var vm = this;

vm.title = 'some title';
vm.saveData = function(){ ... } ;

return vm;

Esto me parece más limpio y hace que sea más fácil ver lo que se expone a la vista. Observe que nombro la variable que devuelvo "vm", que significa viewmodel. Esa es solo mi convención.

Con $ scope puedo hacer lo mismo, así que no estoy agregando o quitando valor con la técnica.

$scope.title = 'some title';
$scope.saveData = function() { ... };

Entonces depende de ti allí.

Inyección

Con $ scope necesito inyectar $ scope en el controlador. No tengo que hacer esto con el controlador como, a menos que lo necesite por alguna otra razón (como $ broadcast o relojes, aunque trato de evitar los relojes en el controlador).

ACTUALIZACIÓN Escribí esta publicación sobre las 2 opciones: http://www.johnpapa.net/do-you-like-your-angular-controllers-with-or-without-sugar/

John papa
fuente
44
Personalmente, también sigo tu enfoque usando vm. El único olor a código que he detectado es cuando necesita interactuar específicamente con $ scope, por ejemplo, suscribirse o transmitir eventos, acceder a variables de validación de formularios dentro de su controlador, etc. Esto lleva a un entorno un tanto mixto donde aún necesita inyectar $ scope aunque use el controlador como característica.
Beyers
99
Correcto. $ scope todavía se usa en ese caso, pero se usa más como un servicio. Cuando inyectamos servicios angulares ($ scope, $ q, etc.) proporcionan alguna característica que necesitamos. $ scope nos permite ver, aplicar, usar mensajes y vincular datos. E incluso cuando se usa el controlador como, $ scope todavía se usa, simplemente se abstrae
John Papa
1
var vm = this;¿también necesita llamarlo 'vm' en la vista? 'controlador como vm'. ¿Tienen que ser iguales?
Javid
2
@JohnPapa - ¿Por qué las plantillas SideWaffle "no devuelven vm"? cuando se utiliza el controlador como?
Kevin
2
@Kevin Controllers efectivamente actúa como un Ctor y por lo tanto devuelve "esto" ya.
John Papa
68

$scopese está eliminando en Angular 2.0. Por lo tanto, el uso thissería un enfoque que otros quieren seguir a medida que se acerca la fecha de lanzamiento de Angular 2.0.

jason328
fuente
40

Mi opinión es que 'esto' en javascript tiene suficientes problemas por sí mismo, y que agregar otro significado / uso no es una buena idea.

Usaría $ scope, por razones de claridad.

ACTUALIZAR

Ahora existe la sintaxis 'controlador como', discutida aquí . No soy un fanático, pero ahora que es una construcción AngularJS más "oficial" merece algo de atención.

Roy Truelove
fuente
10
Creo que primero debemos entender la nueva sintaxis "UserCtrl as uCtrl" antes de poder decir cuál creemos que es mejor.
Mark Rajcok
Re 'UserCtrl as uCtrl', estoy de acuerdo, esto debe entenderse. Creo que es una mala idea, por la mayoría de las mismas razones que los argumentos presentados aquí: groups.google.com/forum/#!topic/angular/84selECbp1I
Roy Truelove
44
Si está familiarizado con oop en JS , tiene mucho sentido. Un controlador es una clase, y angular utiliza el nuevo operador cada vez que se crea un controlador. Le invitamos a que no le guste, pero afirmar que hay problemas con el uso de 'esto' es engañoso. Es un caso de uso aceptable para 'esto'.
MJ
$ scope no agrega nada a la claridad. De hecho, puede ser muy difícil saber qué sucede en la vista cuando se usa $ scope y tiene ámbitos anidados. El controlador como sintaxis junto con el uso de esto agrega mucha más claridad. En la vista, es agradable y claro de qué alcance del controlador se origina un método o propiedad.
ddelrio1986
1
Estoy de acuerdo con @ ddelrio1986. Acabo de tener un problema con las pestañas de arranque y agular con el uso de var vm = $ scope. Las pestañas tienen su propio alcance y, por lo tanto, no puede usar esto como esperaría, pero con var vm = this, las cosas funcionan como se espera.
user441521
7

La documentación angular le dice explícitamente que thisse recomienda usar . Eso, además del hecho de que $scopese está eliminando, es razón suficiente para que nunca lo use $scope.

tjespe
fuente
4

El "alcance de $ Jason se está eliminando en Angular 2.0" me parece una buena razón. Y encontré otra razón para ayudarme a tomar la decisión: thises más legible : cuando veo fooCtrl.baren HTML, inmediatamente sé dónde encontrar la definición de bar.

Actualizaciones: poco después de cambiar a la thissolución, comencé a perder la $scopeforma que necesita menos escribir

ZZY
fuente
2

Prefiero una combinación

Un simple console.log de $ scope y 'this' después de llenarlos con algunos datos simulados le mostrará eso.

$ scope permite el acceso a las partes debajo de las cubiertas de un controlador, por ejemplo:

$$ChildScope: null;
$$childHead: null;
$$childTail: null;
$$listenerCount: Object;
$$listeners: Object;
$$nextSibling: Scope;
$$prevSibling: null;
$$watchers: null;
$$watcherCount: 0;
$id: 2;
$parent: Object;
foo: 'bar';

** El equipo de Angular no recomienda jugar con las propiedades y los métodos con $$, pero $ puede ser un juego seguro para hacer cosas geniales con $ parent y $ id.

'this' va directo al grano, adjuntando datos y funciones de 2 vías. Solo verás lo que adjuntaste:

foo: 'bar';

Entonces, ¿por qué prefiero una combinación?

En las aplicaciones anidadas de ui-router, puedo acceder al controlador principal, establecer y llamar a valores y funciones universales dentro de un controlador secundario:

En el controlador principal:

// Main Controller
var mainCtrl = this;
mainCtrl.foo = 'Parent at the bar';

En el controlador infantil:

// Child Controller
var mainCtrl = $scope.$parent.mainCtrl;
var childCtrl = this;

// update the parent from within the child
childCtrl.underageDrinking = function(){
    mainCtrl.foo = 'Child at the bar';
}

// And then attach the child back to a property on the parent controller!
mainCtrl.currentCtrl = childCtrl;

¡Ahora, puede acceder al padre desde dentro del niño y al niño desde el padre!

Craig O. Curtis
fuente
1

Ambos funcionan, pero si aplica las cosas que son apropiadas para el alcance a $ scope, y si aplica las cosas que son apropiadas para el controlador al controlador, su código será fácil de mantener. Para las personas que dicen "Ugh solo use el alcance, olvide este controlador como sintaxis" ... Puede funcionar igual, pero me pregunto cómo podrá mantener una aplicación enorme sin perder la noción de las cosas.

Nick Manning
fuente