On Github darioodiaz / presentacionSge
La variable poderosa
Una variable puede ser un valor, funcion, objeto, whatever
Los misterios de undefined
Cualquier valor que no exista se convierte en undefined
Dinamismo everywhere
Cualquier objeto es dinamico, esto es, pueden agregarse nuevas propiedades (atributos y/o metodos) sin que esten definidos previamente
//Creamos una variable que guarde nuestra funcion var soyUnaFuncion = function() { console.log('Js Rulez!'); }; //La llamamos soyUnaFuncion(); //Puede recibir parametros var soyUnaFuncionConParametros = function(nombre, apellido) { console.log('Hola' + nombre + ", " + apellido); }; soyUnaFuncionConParametros("Dario", "Diaz");
//Creamos una variable que guarde nuestra funcion constructora var soyUnConstructor = function(nombre, apellido, miEdad) { this.nombre = nombre; this.apellido = apellido; this.edad = miEdad; this.mostrarDatos = function(variableInterna) { return this.nombre + " - " + this.apellido + " - " + variableInterna; }; }; //Creamos un objeto var objeto = new soyUnConstructor("Dario", "Diaz", 23); //Lo usamos como cualquier objeto console.log(objeto.nombre); console.log(objeto.mostrarDatos());
//Creamos una function con 3 parametros var miFuncion = function(param1, param2, param3) { console.log('Parametro 1: ', param1); console.log('Parametro 2: ', param2); console.log('Parametro 3: ', param3); }; //La llamamos con un parametro de menos miFuncion("Hola", "Mundo");
//Creamos un objeto por cualquier forma var miConstructor = function(param1, param2) { this.nombre = param1; this.apellido = param2; }; //Creamos un objeto var miObj = {}; var miObj2 = new Object(); var objeto = new miConstructor("Dario", "Diaz"); objeto.otraPropiedad = 3; miObj.valorBooleano = true; miObj2.metodo = function(parametro) { console.log("Funcion de miObj2:" , parametro + 1); };
Es una forma de describir objetos en JS
Un JSON puede solo tener atributos (ya sean valores, otros objetos, arrays, etc)
La caracteristica fundamental de un JSON es que se puede escribir (materializar) y leer (desmaterializar) como un String
{ "propiedad": "valor", "otraPropiedad": 3 }
{ "propiedad": "valor", "otraPropiedad": 3, "array": ["elemento1", "elemento2"], "objeto": { "idem": true, "idem2": 345 } }
JS nos provee 2 funciones para transformar String en JSON o convertir nuestros objetos en JSON
JSON.parse(string): trata de transformar un string en objeto JSON, si falla lanza excepcion
JSON.stringify(objeto): transforma un objeto en un String JSON
var respuestaDelServer = '{ "propiedad": "valor", "otraPropiedad": 3 }'; var objParseado = JSON.parse(respuestaDelServer); console.log(objParseado);
//Creamos un objeto normal var obj = {}; obj.nombre = "Dario"; obj["apellido"] = "Diaz"; var parseo = JSON.stringify(obj); console.log(parseo);
Scope: ambito o contexto donde co-existen variables y metodos
Closure Scope: expresiones (normalmente funciones o metodos) que pueden acceder a otros ambitos
Las expresiones en Angular son sentencias comunes de JS con las siguientes restricciones
En Angular un modulo es un conjunto de elementos que coordinan para trabajar
Un modulo Angular puede estar compuesto por
Un modulo Angular se crea de la siguiente forma:
angular.module("NOMBRE", []);
Tambien puede ser guardado en una variable para referirse a el despues
var miModulo = angular.module("NOMBRE", []);
Son los encargados de manipular o brindar los comportamientos necesarios para trabajar con las vistas (paginas para los usuarios) y los datos (modelos). Va a ser el encargado de trabajar en un ambito HTML
Para crear un controlador en Angular:
var miModulo = angular.module("NOMBRE MODULO", []); miModulo.contoller("NombreCtrl", function($scope) { //Codigo del controlador });
En Angular hay 2 formas de brindar servicios. Una es por factory y la otra por service
En esencia son los mismos, la diferencia recabe en que angular tiene una estructura para poder utilizar servicios en distintas etapas de la aplicacion. Por ejemplo, si necesitaramos un servicio durante la configuracion del la aplicacion (app.config block) seria necesario un Provider del servicio y un provider contiene un factory que devuevle un service.
Es decir, usar factory o service a niveles de nuestro uso es indiferente, pero a un uso mas avanzado de angular es necesario saber que un service es devuelto por un factory. (mas info web oficial de angular)
var miModulo = angular.module("NOMBRE MODULO", []); miModulo.factory("NombreFactory", function() { //Los factory devuelven un objeto var miFactory = {}; miFactory.servicio = function() { ... } return miFactory; });
var miModulo = angular.module("NOMBRE MODULO", []); miModulo.service("NombreSrv", function() { //Los service devuelven una funcion que sera usada como constructora, esta funcion puede recibir parametros var miService = function() { }; return miService; });
En angular los scopes trabajan por herencia, es decir, si tenemos anidamiento de scopes/controllers, si una propiedad no existe en el scope hijo se busca en el padre y ambos trabajan sobre el, hasta que el hijo posea la propiedad
Todos los scopes tiene un atributo llamado $root que representa el scope principal del modulo.
Dentro de los controllers se pueden asignar funcionalidad a los scopes a traves de la DI. En angular sus servicios de inyeccion llevan el simbolo $ delante.
MVC (Model View Controller)
En Angular la vista (view) es la pagina HTML/JSP
el controlador (controller) es uno de los definidos mediante modulo.controller(...)
el modelo es implicito y se representa mediante el $scope que es un modelo global que puede tener propiedades (funciones, objetos, atributos) que representarian nuestros modelos de datos para trabajar con los Ctrls y las vista
Ejemplo AngularEvalúa los datos del modelo y los inserta en el contenido HTML
$scope.todos = [ {accion:'Caminar'}, {accion:'Correr'}] <div>Hay {{todos.length}} elementos.</div> <div> Hay <span ng-bind="todos.length"></span> elementos. </div>
<div ng-bind-template="Primero: {{todos[0].accion}}. Segundo: {{todos[1].accion}}"> </div>
Peligroso! Crea una vinculación utilizando la propiedad innerHTML de un elemento HTML.
$scope.contenidoHTML = '<a href="#" class="btn btn-default">Link</a>'; <div><p ng-bind-html="contenidoHTML"></p></div>
Previene que AngularsJS vincule alguna expression
<div ng-non-bindable=""> AngularJS usa {{ y }} caracteres como plantilla. </div>
<div id="todoPanel2" class="panel" ng-controller="defaultCtrl"> <h3 class="panel-header">To Do List</h3> <div class="well"> <div>El primer item es: {{todos[0].accion}}</div> </div> <div class="form-group well"> <label for="primerItem">Set First Item:</label> <input id="primerItem" name="primerItem" class="form-control" ng-model="todos[0].accion"> </div> </div>
El objetivo principal es generar contenido HTML a partir de valores del modelo
<div class="well"> <div class="radio" ng-repeat="button in ['None', 'Table', 'List']"> <label ng-cloak=""> <input type="radio" ng-model="data.mode" value="{{button}}" ng-checked="$first"> {{button}} </label> </div> </div>
src, onload, autoscroll
<ng-include src="'table.html'" onload="" autoscroll=""></ng-include>
$index, $first, $middle, $last, $even, $odd
<table class="table"> <thead> <tr> <th>#</th> <th>Acción</th> <th>Listo</th> </tr> </thead> <tbody> <tr ng-repeat="item in todos"> <td>{{$index + 1}}</td> <td>{{item.accion}}</td> <td>{{item.completo}}</td> </tr> </tbody> </table>
<div class="panel panel-default"> <div class="panel-heading" ng-repeat-start="subMenu in data.menu.subMenu"> <h3 class="panel-title">{{subMenu.titulo}}</h3> </div> <div class="list-group" ng-repeat-end=""> <a ng-repeat="item in subMenu.items" class="list-group-item"> {{item.nombre}}</a> </div> </div>
<div ng-switch="" on="data.mode"> <div ng-switch-when="Table"> <table class="table"> <thead> <tr> <th>#</th> <th>Action</th> <th>Done</th> </tr> </thead> <tbody><tr ng-repeat="item in todos" ng-class="$odd ? 'odd' : 'even'"> <td>{{$index + 1}}</td> <td ng-repeat="prop in item">{{prop}}</td> </tr> </tbody></table> </div> <div ng-switch-when="List"> <ol> <li ng-repeat="item in todos"> {{item.action}}<span ng-if="item.complete"> (Done)</span> </li> </ol> </div> <div ng-switch-default=""> Select another option to display a layout </div> </div>
<table class="table"> <thead> <tr> <th>#</th> <th>Action</th> <th>Done</th> </tr> </thead> <tbody><tr ng-repeat="item in todos" ng-class="active"> <td>{{$index + 1}}</td> <td>{{item.action}}</td> <td ng-style="{'background-color': lightgreen}"> {{item.complete}} </td> </tr> </tbody></table>
<table class="table"> <thead> <tr> <th>#</th> <th>Action</th> <th>Done</th> </tr> </thead> <tbody><tr ng-repeat="item in todos" ng-class-even="settings.Rows" ng-class-odd="settings.Columns"> <td>{{$index + 1}}</td> <td>{{item.action}}</td> <td>{{item.complete}}</td> </tr> </tbody></table>
<table class="table"> <thead> <tr> <th>#</th> <th>Action</th> <th>Done</th> </tr> </thead> <tbody><tr ng-repeat="item in todos"> <td>{{$index + 1}}</td> <td>{{item.action}}</td> <td> <span ng-hide="item.complete">(Incomplete)</span> <span ng-show="item.complete">(Done)</span> </td> </tr> </tbody></table>
<span ng-if="!item.complete">(Incomplete)</span> <span ng-if="item.complete">(Done)</span>
AngularJS aporta directivas para realizar la validación de los formularios
AngularJS aplica las directivas para formularios automaticamente cuando encuentra elementos del tipo form, input, select, y textarea.
Para utilizar las validaciones hace falta utilizar el elemento FORM, el atributo NOVALIDATE es utilizado para que los navegadores con HTML5 no realize validaciones y deje todo en manos de AngularJS
<form name="myForm" novalidate="" ng-submit="addUser(newUser)"></form>
$pristine true si el usuario no interactuó con el elemento/formulario
$dirty true si el usuario interactuó con el elemento/formulario
$valid true si el contenido del elemento/formulario es válido
$invalid true si el contenido del elemento/formulario es inválido
$error provee de información del error producido.
<div>Valid: {{myForm.$valid}}</div> <button type="submit" class="btn btn-primary btn-block" ng-disabled="myForm.$invalid">OK</button>
ng-pristine los elementos con los que no interactuó el usuario son añadidos a esta clase
ng-dirty los elementos con los que interactuó el usuario son añadidos a esta clase
ng-valid los elementos que son válidos son añadidos a esta clase
ng-invalid los elementos que no son válidos son añadidos a esta clase
<div class="well"> Message: {{message}} <div> Valid: <span class="summary" ng-class="myForm.$valid ? 'ng-valid' : 'ng-invalid'">{{myForm.$valid}} </span> </div> </div>
<div id="todoPanel" class="panel" ng-controller="defaultCtrl"> <form name="myForm" novalidate=""> <div class="well"> <div class="form-group"> <label>Text:</label> <input name="sample" class="form-control" ng-model="inputValue" ng-required="requireValue" ng-minlength="3" ng-maxlength="10" ng-pattern="matchPattern"> </div> </div> <div class="well"> <p>Required Error: {{myForm.sample.$error.required}}</p> <p>Min Length Error: {{myForm.sample.$error.minlength}}</p> <p>Max Length Error: {{myForm.sample.$error.maxlength}}</p> <p>Pattern Error: {{myForm.sample.$error.pattern}}</p> <p>Element Valid: {{myForm.sample.$valid}}</p> </div> </form> </div>
<div id="todoPanel1" class="panel" ng-controller="defaultCtrl"> <form name="myForm" novalidate=""> <div class="well"> <div class="checkbox"> <label> <input name="sample" type="checkbox" ng-model="inputValue" ng-true-value="Hurrah!" ng-false-value="Boo!"> This is a checkbox </label> </div> </div> <div class="well"> <p>Model Value: {{inputValue}}</p> </div> </form> </div>
<div class="form-group"> <textarea name="sample" cols="40" rows="3" ng-model="textValue" ng-required="requireValue" ng-minlength="3" ng-maxlength="10" ng-pattern="matchPattern"> </textarea> </div>
<div class="form-group"> <label>Select an Action:</label> <select ng-model="selectValue" ng-options="item.action for item in todos"> </select> </div>
Se puede definir que valor vincular al modelo de la siguiente manera
<select ng-model="selectValue" ng-options="item.id as item.action for item in todos"> <option value="">(Pick One)</option> </select>
se utiliza para agrupar items basados en algun atributo
<div class="well"> <div class="form-group"> <label>Select an Action:</label> <select ng-model="selectValue" ng-options="item.action group by item.place for item in todos"> <option value="">(Pick One)</option> </select> </div> </div> <div class="well"> <p>Selected: {{selectValue || 'None'}}</p> </div>
Hay 3 maneras informar que componente inyectar
function MyController($scope, greeter) { // ... }
var MyController = function(renamed$scope, renamedGreeter) { ... } MyController['$inject'] = ['$scope', 'greeter'];
Maneras informar que componente inyectar
someModule.factory('greeter', ['$window', function(renamed$window) { // ... }]);
angular.module('myModule', []) .factory('serviceId', ['depService', function(depService) { ... }]) .directive('directiveName', ['depService', function(depService) { ... }]) .filter('filterName', ['depService', function(depService) { ... }]);
angular.module('myModule', []) .config(['depProvider', function(depProvider){ ... }]) .run(['depService', function(depService) { ... }]);
someModule.controller('MyController', ['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) { ... $scope.aMethod = function() { ... } ... }]);
Provee una manera diferente de trabajar que ngRoute de AngularJS
Con los estados las vistas no estan acopladas a una URL y permite cambiar de vistas internamente sin la necesidad de cambiar la URL
$stateProvider es el encargado de proveer de los estados en la aplicación y es configurado dentro del .config() del módulo
<!-- in index.html --> <section ui-view="" class="future" style="top: -20px; display: none; "></section> // in app-states.js (or whatever you want to name it) $stateProvider.state('contacts', { template: '<h1>My Contacts</h1>' })
Cuando se activa un estado, la plantilla se inserta en el ui-view de su padre, si no lo tiene entonces se inserta en el index
El controlador no se cargará hasta que no se hayan resuelto todas las dependencias
$stateProvider.state('myState', { controller: function(){}, resolve:{ objetoSimple:function(){ return {value:'asd'}; }, //Retorna un promise, es lo mas utilizado promiseObj: function($http){ return $http({method: 'GET', url: '/someUrl'}); } } }
$stateProvider .state(contacts) .state('contacts.list', { templateUrl: 'contacts.list.html', data: { customData1: 44, customData2: "red" } })
Son disparados desde $rootScope
$stateProvider .state('contacts', {}) .state('contacts.list', {});
También se puede utilizar la propiedad 'parent' para anidar
Los hijos heredan las dependencias resueltas por su padre y los datos que hayan pasado, además si las vistas están anidadas los $scope se heredarán
$stateProvider .state('contacts', { abstract: true, url: '/contacts', // Note: abstract still needs a ui-view for its children to populate. // You can simply add it inline here. template: '<ui-view>' }) .state('contacts.list', { // url will become '/contacts/list' url: '/list' //...more }) .state('contacts.detail', { // url will become '/contacts/detail' url: '/detail', //...more }) </ui-view>
<div ui-view="filters"></div> <div ui-view="tabledata"></div> <div ui-view="graph"></div>
$stateProvider .state('report',{ views: { 'filters': { templateUrl: 'report-filters.html', controller: function($scope){ ... controller stuff just for filters view ... } }, 'tabledata': { templateUrl: 'report-table.html', controller: function($scope){ ... controller stuff just for tabledata view ... } }, 'graph': { templateUrl: 'report-graph.html', controller: function($scope){ ... controller stuff just for graph view ... } }, } })
Se recupera el valor pasado por medio de $stateParams
$stateProvider.state('contacts.detail', { url: '/contacts/:contactId', controller: function($stateParams){ $stateParams.contactId } })
$stateProvider .state('contacts', { url: '/contacts', ... }) .state('contacts.list', { url: '^/list', ... });