AngularJS
AngularJS gotchas y trampas
Buscar..
El enlace de datos bidireccional deja de funcionar
Uno debe tener en cuenta que:
- El enlace de datos de Angular se basa en la herencia prototípica de JavaScript, por lo que está sujeto a la sombra variable .
- Un ámbito secundario normalmente se hereda prototípicamente de su ámbito primario. Una excepción a esta regla es una directiva que tiene un alcance aislado, ya que no se hereda prototípicamente.
- Hay algunas directivas que crean un nuevo ámbito secundario:
ng-repeat
,ng-switch
,ng-view
,ng-if
,ng-controller
,ng-include
, etc.
Esto significa que cuando intenta vincular de forma bidireccional algunos datos a una primitiva que se encuentra dentro de un ámbito secundario (o viceversa), es posible que las cosas no funcionen como se espera. Aquí hay un ejemplo de lo fácil que es "romper" AngularJS.
Este problema se puede evitar fácilmente siguiendo estos pasos:
- Tener un "." Dentro de su plantilla HTML cada vez que enlace algunos datos
- Utilice la sintaxis de
controllerAs
ya que promueve el uso de la vinculación a un objeto "punteado" - $ parent se puede usar para acceder a las variables de
scope
principal en lugar de al alcance secundario. como dentro deng-if
podemos usarng-model="$parent.foo"
..
Una alternativa para lo anterior es vincular ngModel
a una función getter / setter que actualizará la versión en caché del modelo cuando se le llame con argumentos, o lo devolverá cuando se le llame sin argumentos. Para utilizar una función getter / setter, debe agregar ng-model-options="{ getterSetter: true }"
al elemento con el atributo ngModal
, y llamar a la función getter si desea mostrar su valor en la expresión ( Ejemplo de trabajo ).
Ejemplo
Ver:
<div ng-app="myApp" ng-controller="MainCtrl">
<input type="text" ng-model="foo" ng-model-options="{ getterSetter: true }">
<div ng-if="truthyValue">
<!-- I'm a child scope (inside ng-if), but i'm synced with changes from the outside scope -->
<input type="text" ng-model="foo">
</div>
<div>$scope.foo: {{ foo() }}</div>
</div>
Controlador:
angular.module('myApp', []).controller('MainCtrl', ['$scope', function($scope) {
$scope.truthyValue = true;
var _foo = 'hello'; // this will be used to cache/represent the value of the 'foo' model
$scope.foo = function(val) {
// the function return the the internal '_foo' varibale when called with zero arguments,
// and update the internal `_foo` when called with an argument
return arguments.length ? (_foo = val) : _foo;
};
}]);
Mejor práctica : es mejor mantener a los captadores rápidamente porque es probable que Angular los llame con más frecuencia que otras partes de su código ( referencia ).
Cosas que hacer cuando se utiliza html5Mode
Cuando se utiliza html5Mode([mode])
es necesario que:
Especifica la URL base para la aplicación con un
<base href="">
en el encabezado de suindex.html
.Es importante que la etiqueta
base
esté antes que cualquier etiqueta con solicitudes de URL. De lo contrario, esto podría dar lugar a este error:"Resource interpreted as stylesheet but transferred with MIME type text/html"
. Por ejemplo:<head> <meta charset="utf-8"> <title>Job Seeker</title> <base href="/"> <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css" /> <link rel="stylesheet" href="/styles/main.css"> </head>
Si no desea especificar una etiqueta
base
, configure$locationProvider
para que no requiera una etiquetabase
pasando un objeto de definición conrequireBase:false
a$locationProvider.html5Mode()
como esto:$locationProvider.html5Mode({ enabled: true, requireBase: false });
Para poder admitir la carga directa de URL de HTML5, debe habilitar la reescritura de URL del lado del servidor. De AngularJS / Guía del desarrollador / Uso de $ location
El uso de este modo requiere la reescritura de URL en el lado del servidor, básicamente, debe volver a escribir todos sus enlaces al punto de entrada de su aplicación (por ejemplo,
index.html
). Requerir una etiqueta<base>
también es importante para este caso, ya que permite a Angular diferenciar entre la parte de la URL que es la base de la aplicación y la ruta que debe ser manejada por la aplicación.Puede encontrar un excelente recurso para ejemplos de reescritura de solicitudes para varias implementaciones de servidores HTTP en las preguntas frecuentes de ui-router: Cómo: Configurar su servidor para que funcione con html5Mode . Por ejemplo, apache
RewriteEngine on # Don't rewrite files or directories RewriteCond %{REQUEST_FILENAME} -f [OR] RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^ - [L] # Rewrite everything else to index.html to allow html5 state links RewriteRule ^ index.html [L]
nginx
server { server_name my-app; root /path/to/app; location / { try_files $uri $uri/ /index.html; } }
Exprimir
var express = require('express'); var app = express(); app.use('/js', express.static(__dirname + '/js')); app.use('/dist', express.static(__dirname + '/../dist')); app.use('/css', express.static(__dirname + '/css')); app.use('/partials', express.static(__dirname + '/partials')); app.all('/*', function(req, res, next) { // Just send the index.html for other files to support HTML5Mode res.sendFile('index.html', { root: __dirname }); }); app.listen(3006); //the port you want to use
7 pecados mortales de AngularJS
A continuación se muestra la lista de algunos errores que los desarrolladores suelen cometer durante el uso de las funcionalidades de AngularJS, algunas lecciones aprendidas y soluciones para ellos.
1. Manipular el DOM a través del controlador.
Es legal, pero hay que evitarlo. Los controladores son los lugares donde define sus dependencias, vincula sus datos a la vista y crea más lógica de negocios. Técnicamente puede manipular el DOM en un controlador, pero siempre que necesite una manipulación similar o similar en otra parte de su aplicación, se necesitará otro controlador. Por lo tanto, la mejor práctica de este enfoque es crear una directiva que incluya todas las manipulaciones y usar la directiva en toda su aplicación. Por lo tanto, el controlador deja la vista intacta y hace su trabajo. En una directiva, la función de enlace es el mejor lugar para manipular el DOM. Tiene acceso completo al alcance y al elemento, por lo que al usar una directiva, también puede aprovechar la reutilización.
link: function($scope, element, attrs) {
//The best place to manipulate DOM
}
Puede acceder a los elementos DOM en la función de vinculación de varias maneras, como el parámetro del element
, el método angular.element()
o el Javascript puro.
2. Enlace de datos en la transclusión.
AngularJS es famoso por su enlace de datos de dos vías. Sin embargo, es posible que a veces descubra que sus datos solo están enlazados en un solo sentido dentro de las directivas. Detente ahí, AngularJS no está mal, pero probablemente tú. Las directivas son lugares poco peligrosos ya que están involucrados los ámbitos de niños y los aislados. Supongamos que tiene la siguiente directiva con una transclusión
<my-dir>
<my-transclusion>
</my-transclusion>
</my-dir>
Y dentro de mi-transclusión, tiene algunos elementos que están vinculados a los datos en el ámbito externo.
<my-dir>
<my-transclusion>
<input ng-model="name">
</my-transclusion>
</my-dir>
El código anterior no funcionará correctamente. Aquí, la transclusión crea un ámbito secundario y puede obtener la variable de nombre, correcto, pero cualquier cambio que realice en esta variable permanecerá allí. Entonces, realmente puedes acceder a esta variable como $ parent.name . Sin embargo, este uso podría no ser la mejor práctica. Un mejor enfoque sería envolver las variables dentro de un objeto. Por ejemplo, en el controlador puedes crear:
$scope.data = {
name: 'someName'
}
Luego, en la transclusión, puede acceder a esta variable a través del objeto 'datos' y ver que el enlace bidireccional funciona perfectamente.
<input ng-model="data.name">
No solo en las transclusiones, sino en toda la aplicación, es una buena idea usar la notación punteada.
3. Directivas múltiples juntas
En realidad, es legal usar dos directivas juntas dentro del mismo elemento, siempre que cumpla con la regla: no pueden existir dos ámbitos aislados en el mismo elemento. En general, al crear una nueva directiva personalizada, asigna un ámbito aislado para facilitar el paso de parámetros. Suponiendo que las directivas myDirA y myDirB tengan ámbitos aislados y myDirC no, el siguiente elemento será válido:
<input my-dir-a my-dirc>
mientras que el siguiente elemento causará error de consola:
<input my-dir-a my-dir-b>
Por lo tanto, las directivas deben usarse con prudencia, teniendo en cuenta los ámbitos.
4. Uso indebido de $ emit
$ emit, $ broadcast y $ on, funcionan en un principio de remitente-receptor. En otras palabras, son un medio de comunicación entre los controladores. Por ejemplo, la siguiente línea emite el 'someEvent' del controlador A, que debe ser capturado por el controlador B en cuestión.
$scope.$emit('someEvent', args);
Y la siguiente línea captura el 'someEvent'
$scope.$on('someEvent', function(){});
Hasta ahora todo parece perfecto. Pero recuerde que, si el controlador B aún no se ha invocado, el evento no se detectará, lo que significa que se deben invocar los controladores de emisor y receptor para que esto funcione. Entonces, una vez más, si no está seguro de que definitivamente tiene que usar $ emit, construir un servicio parece una mejor manera.
5. Uso indebido de $ scope. $ Watch
$ scope. $ watch se usa para ver un cambio de variable. Cada vez que una variable ha cambiado, este método es invocado. Sin embargo, un error común cometido es cambiar la variable dentro de $ scope. $ Watch. Esto causará inconsistencias y un bucle infinito de digestión $ en algún punto.
$scope.$watch('myCtrl.myVariable', function(newVal) {
this.myVariable++;
});
Así que en la función anterior, asegúrese de no tener operaciones en myVariable y newVal.
6. Encuadernación de métodos a vistas.
Este es uno de los pecados más mortíferos. AngularJS tiene enlaces bidireccionales, y siempre que algo cambia, las vistas se actualizan muchas veces. Entonces, si unes un método a un atributo de una vista, ese método podría llamarse cientos de veces, lo que también te vuelve loco durante la depuración. Sin embargo, solo hay algunos atributos que se crean para el enlace de métodos, como ng-click, ng-blur, ng-on-change, etc., que esperan métodos como paremeter. Por ejemplo, suponga que tiene la siguiente vista en su marca:
<input ng-disabled="myCtrl.isDisabled()" ng-model="myCtrl.name">
Aquí usted verifica el estado deshabilitado de la vista a través del método isDisabled. En el controlador myCtrl, tienes:
vm.isDisabled = function(){
if(someCondition)
return true;
else
return false;
}
En teoría, puede parecer correcto, pero técnicamente esto causará una sobrecarga, ya que el método se ejecutará innumerables veces. Para resolver esto, debes enlazar una variable. En su controlador, la siguiente variable debe existir:
vm.isDisabled
Puede volver a iniciar esta variable en la activación del controlador.
if(someCondition)
vm.isDisabled = true
else
vm.isDisabled = false
Si la condición no es estable, puede vincular esto a otro evento. Entonces deberías enlazar esta variable a la vista:
<input ng-disabled="myCtrl.isDisabled" ng-model="myCtrl.name">
Ahora, todos los atributos de la vista tienen lo que esperan y los métodos se ejecutarán solo cuando sea necesario.
7. No usar las funcionalidades de Angular.
AngularJS proporciona una gran comodidad con algunas de sus funcionalidades, no solo simplificando su código sino que también lo hace más eficiente. Algunas de estas características se enumeran a continuación:
- angular.forEach para los bucles (Precaución, no puede "romperla"; solo puede evitar que entre al cuerpo, así que considere el rendimiento aquí).
- Elemento angular para selectores DOM
- angular.copy : use esto cuando no debe modificar el objeto principal
- Las validaciones de formularios ya son impresionantes. Utilice sucio, prístino, tocado, válido, requerido y así sucesivamente.
- Además del depurador Chrome, use la depuración remota para el desarrollo móvil también.
- Y asegúrate de usar Batarang . Es una extensión gratuita de Chrome donde puedes inspeccionar fácilmente los ámbitos. .