TL; DR
1) Cuando utiliza una Fábrica , crea un objeto, le agrega propiedades y luego devuelve el mismo objeto. Cuando pasa esta fábrica a su controlador, esas propiedades en el objeto ahora estarán disponibles en ese controlador a través de su fábrica.
app.controller('myFactoryCtrl', function($scope, myFactory){
$scope.artist = myFactory.getArtist();
});
app.factory('myFactory', function(){
var _artist = 'Shakira';
var service = {};
service.getArtist = function(){
return _artist;
}
return service;
});
2) Cuando usa el Servicio , Angular lo instancia detrás de escena con la palabra clave 'nuevo'. Debido a eso, agregará propiedades a 'this' y el servicio devolverá 'this'. Cuando pasa el servicio a su controlador, esas propiedades en 'esto' ahora estarán disponibles en ese controlador a través de su servicio.
app.controller('myServiceCtrl', function($scope, myService){
$scope.artist = myService.getArtist();
});
app.service('myService', function(){
var _artist = 'Nelly';
this.getArtist = function(){
return _artist;
}
});
No TL; DR
1)
Fábricas Las fábricas son la forma más popular de crear y configurar un servicio. Realmente no hay mucho más de lo que dice el TL; DR. Simplemente crea un objeto, le agrega propiedades y luego devuelve el mismo objeto. Luego, cuando pase la fábrica a su controlador, esas propiedades en el objeto ahora estarán disponibles en ese controlador a través de su fábrica. Un ejemplo más extenso está abajo.
app.factory('myFactory', function(){
var service = {};
return service;
});
Ahora, cualquier propiedad que adjuntemos al 'servicio' estará disponible cuando pasemos 'myFactory' a nuestro controlador.
Ahora agreguemos algunas variables 'privadas' a nuestra función de devolución de llamada. Estos no serán accesibles directamente desde el controlador, pero eventualmente configuraremos algunos métodos getter / setter en 'servicio' para poder alterar estas variables 'privadas' cuando sea necesario.
app.factory('myFactory', function($http, $q){
var service = {};
var baseUrl = 'https://itunes.apple.com/search?term=';
var _artist = '';
var _finalUrl = '';
var makeUrl = function(){
_artist = _artist.split(' ').join('+');
_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK';
return _finalUrl
}
return service;
});
Aquí notará que no estamos asociando esas variables / funciones a 'servicio'. Simplemente los estamos creando para usarlos o modificarlos más tarde.
- baseUrl es la URL base que requiere la API de iTunes
- _artist es el artista que deseamos buscar
- _finalUrl es la URL final y totalmente construida a la que haremos la llamada a iTunes makeUrl es una función que creará y devolverá nuestra URL amigable de iTunes.
Ahora que nuestras funciones y variables auxiliares / privadas están en su lugar, agreguemos algunas propiedades al objeto 'servicio'. Independientemente de lo que le demos al 'servicio', podremos usarlo directamente en cualquier controlador al que le pasemos 'myFactory'.
Vamos a crear métodos setArtist y getArtist que simplemente devuelven o configuran al artista. También vamos a crear un método que llame a la API de iTunes con nuestra URL creada. Este método devolverá una promesa que se cumplirá una vez que los datos hayan regresado de la API de iTunes. Si no ha tenido mucha experiencia usando promesas en Angular, le recomiendo que profundice en ellas.
A continuación, setArtist acepta un artista y le permite configurarlo. getArtist devuelve el artista callItunes primero llama a makeUrl () para construir la URL que usaremos con nuestra solicitud $ http. Luego configura un objeto de promesa, realiza una solicitud de $ http con nuestra url final, luego, debido a que $ http devuelve una promesa, podemos llamar a .success o .error después de nuestra solicitud. Luego resolvemos nuestra promesa con los datos de iTunes, o la rechazamos con un mensaje que dice 'Hubo un error'.
app.factory('myFactory', function($http, $q){
var service = {};
var baseUrl = 'https://itunes.apple.com/search?term=';
var _artist = '';
var _finalUrl = '';
var makeUrl = function(){
_artist = _artist.split(' ').join('+');
_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
return _finalUrl;
}
service.setArtist = function(artist){
_artist = artist;
}
service.getArtist = function(){
return _artist;
}
service.callItunes = function(){
makeUrl();
var deferred = $q.defer();
$http({
method: 'JSONP',
url: _finalUrl
}).success(function(data){
deferred.resolve(data);
}).error(function(){
deferred.reject('There was an error')
})
return deferred.promise;
}
return service;
});
Ahora nuestra fábrica está completa. Ahora podemos inyectar 'myFactory' en cualquier controlador y luego podremos llamar a nuestros métodos que adjuntamos a nuestro objeto de servicio (setArtist, getArtist y callItunes).
app.controller('myFactoryCtrl', function($scope, myFactory){
$scope.data = {};
$scope.updateArtist = function(){
myFactory.setArtist($scope.data.artist);
};
$scope.submitArtist = function(){
myFactory.callItunes()
.then(function(data){
$scope.data.artistData = data;
}, function(data){
alert(data);
})
}
});
En el controlador anterior, estamos inyectando en el servicio 'myFactory'. Luego establecemos propiedades en nuestro objeto $ scope que provienen de datos de 'myFactory'. El único código complicado anterior es si nunca antes ha tratado con promesas. Debido a que callItunes está devolviendo una promesa, podemos usar el método .then () y solo establecemos $ scope.data.artistData una vez que nuestra promesa se cumpla con los datos de iTunes. Notarás que nuestro controlador es muy 'delgado'. Todos nuestros datos lógicos y persistentes se encuentran en nuestro servicio, no en nuestro controlador.
2) servicio
Quizás lo más importante que se debe saber cuando se trata de crear un Servicio es que se instancia con la palabra clave 'nueva'. Para sus gurús de JavaScript, esto debería darle una gran pista sobre la naturaleza del código. Para aquellos de ustedes con antecedentes limitados en JavaScript o para aquellos que no están demasiado familiarizados con lo que realmente hace la 'nueva' palabra clave, revisemos algunos fundamentos de JavaScript que eventualmente nos ayudarán a comprender la naturaleza de un Servicio.
Para ver realmente los cambios que ocurren cuando invoca una función con la palabra clave 'nueva', creemos una función e invoquémosla con la palabra clave 'nueva', luego muestremos qué hace el intérprete cuando ve la palabra clave 'nueva'. Los resultados finales serán los mismos.
Primero creemos nuestro Constructor.
var Person = function(name, age){
this.name = name;
this.age = age;
}
Esta es una función típica de constructor de JavaScript. Ahora, cada vez que invoquemos la función Persona usando la palabra clave 'nuevo', 'esto' estará vinculado al objeto recién creado.
Ahora agreguemos un método al prototipo de nuestra Persona para que esté disponible en cada instancia de nuestra 'clase' de Persona.
Person.prototype.sayName = function(){
alert('My name is ' + this.name);
}
Ahora, debido a que ponemos la función sayName en el prototipo, cada instancia de Person podrá llamar a la función sayName para alertar el nombre de esa instancia.
Ahora que tenemos nuestra función de constructor Person y nuestra función sayName en su prototipo, creemos una instancia de Person y luego llamemos a la función sayName.
var tyler = new Person('Tyler', 23);
tyler.sayName(); //alerts 'My name is Tyler'
Entonces, todo el código para crear un constructor de Persona, agregar una función a su prototipo, crear una instancia de Persona y luego llamar a la función en su prototipo se ve así.
var Person = function(name, age){
this.name = name;
this.age = age;
}
Person.prototype.sayName = function(){
alert('My name is ' + this.name);
}
var tyler = new Person('Tyler', 23);
tyler.sayName(); //alerts 'My name is Tyler'
Ahora echemos un vistazo a lo que realmente está sucediendo cuando usa la palabra clave 'nuevo' en JavaScript. Lo primero que debe notar es que después de usar 'nuevo' en nuestro ejemplo, podemos llamar a un método (sayName) en 'tyler' como si fuera un objeto, eso es porque lo es. Primero, sabemos que nuestro constructor de Persona está devolviendo un objeto, ya sea que podamos ver eso en el código o no. En segundo lugar, sabemos que debido a que nuestra función sayName se encuentra en el prototipo y no directamente en la instancia de Person, el objeto que devuelve la función Person debe delegarse en su prototipo en búsquedas fallidas. En términos más simples, cuando llamamos a tyler.sayName () el intérprete dice "OK, voy a buscar el objeto 'tyler' que acabamos de crear, ubicar la función sayName y luego llamarla. Espera un momento, no lo veo aquí, todo lo que veo es nombre y edad, Déjame comprobar el prototipo. Sí, parece que está en el prototipo, déjenme llamarlo ".
A continuación se muestra el código de cómo puede pensar qué está haciendo la palabra clave 'nueva' en JavaScript. Básicamente es un ejemplo de código del párrafo anterior. Puse la 'vista del intérprete' o la forma en que el intérprete ve el código dentro de las notas.
var Person = function(name, age){
//The line below this creates an obj object that will delegate to the person's prototype on failed lookups.
//var obj = Object.create(Person.prototype);
//The line directly below this sets 'this' to the newly created object
//this = obj;
this.name = name;
this.age = age;
//return this;
}
Ahora que conocemos lo que realmente hace la 'nueva' palabra clave en JavaScript, crear un Servicio en Angular debería ser más fácil de entender.
Lo más importante para entender al crear un Servicio es saber que los Servicios se instancian con la palabra clave "nueva". Combinando ese conocimiento con nuestros ejemplos anteriores, ahora debería reconocer que adjuntará sus propiedades y métodos directamente a 'esto', que luego será devuelto por el Servicio mismo. Echemos un vistazo a esto en acción.
A diferencia de lo que hicimos originalmente con el ejemplo de Factory, no necesitamos crear un objeto y luego devolverlo porque, como se mencionó muchas veces antes, usamos la palabra clave 'new' para que el intérprete cree ese objeto, haga que delegue en es prototipo, luego devuélvanoslo sin que tengamos que hacer el trabajo.
Primero lo primero, creemos nuestra función 'privada' y auxiliar. Esto debería parecer muy familiar ya que hicimos exactamente lo mismo con nuestra fábrica. No explicaré qué hace cada línea aquí porque lo hice en el ejemplo de fábrica, si está confundido, vuelva a leer el ejemplo de fábrica.
app.service('myService', function($http, $q){
var baseUrl = 'https://itunes.apple.com/search?term=';
var _artist = '';
var _finalUrl = '';
var makeUrl = function(){
_artist = _artist.split(' ').join('+');
_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
return _finalUrl;
}
});
Ahora, adjuntaremos todos nuestros métodos que estarán disponibles en nuestro controlador a 'esto'.
app.service('myService', function($http, $q){
var baseUrl = 'https://itunes.apple.com/search?term=';
var _artist = '';
var _finalUrl = '';
var makeUrl = function(){
_artist = _artist.split(' ').join('+');
_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
return _finalUrl;
}
this.setArtist = function(artist){
_artist = artist;
}
this.getArtist = function(){
return _artist;
}
this.callItunes = function(){
makeUrl();
var deferred = $q.defer();
$http({
method: 'JSONP',
url: _finalUrl
}).success(function(data){
deferred.resolve(data);
}).error(function(){
deferred.reject('There was an error')
})
return deferred.promise;
}
});
Ahora, al igual que en nuestra fábrica, setArtist, getArtist y callItunes estarán disponibles en cualquier controlador al que pasamos myService. Aquí está el controlador myService (que es casi exactamente el mismo que nuestro controlador de fábrica).
app.controller('myServiceCtrl', function($scope, myService){
$scope.data = {};
$scope.updateArtist = function(){
myService.setArtist($scope.data.artist);
};
$scope.submitArtist = function(){
myService.callItunes()
.then(function(data){
$scope.data.artistData = data;
}, function(data){
alert(data);
})
}
});
Como mencioné antes, una vez que realmente comprende lo que hace 'nuevo', los Servicios son casi idénticos a las fábricas en Angular.