AngularJSのService
、Provider
、およびFactory
の違いは何ですか?
AngularJSメーリングリストから、私は すばらしいスレッド サービス対ファクトリ対プロバイダ、そしてそれらのインジェクションの使い方を説明しています。答えをまとめる:
構文:module.service( 'serviceName', function );
結果:serviceNameを挿入可能な引数として宣言すると、関数のインスタンスが提供されます。言い換えればnew FunctionYouPassedToService()
です。
構文:module.factory( 'factoryName', function );
結果:factoryNameを注入可能な引数として宣言すると、module.factoryに渡された関数参照を呼び出すことによって返される値が提供されます。
構文:module.provider( 'providerName', function );
結果:providerNameを注入可能な引数として宣言すると、(new ProviderFunction()).$get()
が提供されます。コンストラクタ関数は$ getメソッドが呼び出される前にインスタンス化されます - ProviderFunction
はmodule.providerに渡される関数参照です。
プロバイダには、モジュール構成段階で構成できるという利点があります。
提供されたコードについては ここ を参照してください。
これがMiskoによるさらに詳しい説明です。
provide.value('a', 123);
function Controller(a) {
expect(a).toEqual(123);
}
この場合、インジェクタは単に値をそのまま返します。しかし、もしあなたが値を計算したいとしたら?それから工場を使う
provide.factory('b', function(a) {
return a*2;
});
function Controller(b) {
expect(b).toEqual(246);
}
だからfactory
は値を作成する責任がある関数です。ファクトリ関数は他の依存関係を要求できることに注意してください。
しかし、もっとOOになり、Greeterというクラスを作りたいとしたら?
function Greeter(a) {
this.greet = function() {
return 'Hello ' + a;
}
}
それからインスタンス化するためにあなたは書く必要があるでしょう
provide.factory('greeter', function(a) {
return new Greeter(a);
});
それから私達はこのようにコントローラーで 'greeter'を要求することができます
function Controller(greeter) {
expect(greeter instanceof Greeter).toBe(true);
expect(greeter.greet()).toEqual('Hello 123');
}
しかし、それはあまりにも言葉遣いです。これを書くもっと短い方法はprovider.service('greeter', Greeter);
でしょう
しかし、インジェクションの前にGreeter
クラスを設定したいとしたらどうでしょうか。それから私達は書くことができる
provide.provider('greeter2', function() {
var salutation = 'Hello';
this.setSalutation = function(s) {
salutation = s;
}
function Greeter(a) {
this.greet = function() {
return salutation + ' ' + a;
}
}
this.$get = function(a) {
return new Greeter(a);
};
});
それから我々はこれを行うことができます:
angular.module('abc', []).config(function(greeter2Provider) {
greeter2Provider.setSalutation('Halo');
});
function Controller(greeter2) {
expect(greeter2.greet()).toEqual('Halo 123');
}
ちなみに、service
、factory
、およびvalue
はすべてproviderから派生しています。
provider.service = function(name, Class) {
provider.provide(name, function() {
this.$get = function($injector) {
return $injector.instantiate(Class);
};
});
}
provider.factory = function(name, factory) {
provider.provide(name, function() {
this.$get = function($injector) {
return $injector.invoke(factory);
};
});
}
provider.value = function(name, value) {
provider.factory(name, function() {
return value;
});
};
factory
/service
/provider
を使った "Hello world"の例:var myApp = angular.module('myApp', []);
//service style, probably the simplest one
myApp.service('helloWorldFromService', function() {
this.sayHello = function() {
return "Hello, World!";
};
});
//factory style, more involved but more sophisticated
myApp.factory('helloWorldFromFactory', function() {
return {
sayHello: function() {
return "Hello, World!";
}
};
});
//provider style, full blown, configurable version
myApp.provider('helloWorld', function() {
this.name = 'Default';
this.$get = function() {
var name = this.name;
return {
sayHello: function() {
return "Hello, " + name + "!";
}
}
};
this.setName = function(name) {
this.name = name;
};
});
//hey, we can configure a provider!
myApp.config(function(helloWorldProvider){
helloWorldProvider.setName('World');
});
function MyCtrl($scope, helloWorld, helloWorldFromFactory, helloWorldFromService) {
$scope.hellos = [
helloWorld.sayHello(),
helloWorldFromFactory.sayHello(),
helloWorldFromService.sayHello()];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="MyCtrl">
{{hellos}}
</div>
</body>
TL; DR
1) Factory を使用している場合は、オブジェクトを作成し、それにプロパティを追加してから、同じオブジェクトを返します。このファクトリをコントローラに渡すと、オブジェクトのこれらのプロパティはファクトリを通じてそのコントローラで利用できるようになります。
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) Service を使用している場合、AngularJSは「new」キーワードを使用してその背後でインスタンス化します。そのため、「this」にプロパティを追加すると、サービスは「this」を返します。あなたがあなたのコントローラにサービスを渡すとき、「これ」のそれらのプロパティはあなたのサービスを通してそのコントローラで利用可能になります。
app.controller(‘myServiceCtrl’, function($scope, myService){
$scope.artist = myService.getArtist();
});
app.service(‘myService’, function(){
var _artist = ‘Nelly’;
this.getArtist = function(){
return _artist;
}
});
3) プロバイダ は、あなたが.config()関数に渡すことができる唯一のサービスです。利用可能にする前にサービスオブジェクトにモジュール全体の設定を提供する場合は、プロバイダを使用してください。
app.controller(‘myProvider’, function($scope, myProvider){
$scope.artist = myProvider.getArtist();
$scope.data.thingFromConfig = myProvider.thingOnConfig;
});
app.provider(‘myProvider’, function(){
//Only the next two lines are available in the app.config()
this._artist = ‘’;
this.thingFromConfig = ‘’;
this.$get = function(){
var that = this;
return {
getArtist: function(){
return that._artist;
},
thingOnConfig: that.thingFromConfig
}
}
});
app.config(function(myProviderProvider){
myProviderProvider.thingFromConfig = ‘This was set in config’;
});
非TL; DR
1)工場
工場は、サービスを作成および構成するための最も一般的な方法です。 TL、DRが言ったこと以上のものは本当にありません。オブジェクトを作成し、それにプロパティを追加してから、同じオブジェクトを返すだけです。その後、ファクトリをコントローラに渡すと、オブジェクトのこれらのプロパティはファクトリを通じてそのコントローラで利用できるようになります。より広範な例を以下に示します。
app.factory(‘myFactory’, function(){
var service = {};
return service;
});
MyFactoryをコントローラに渡すと、serviceに付加したプロパティはすべて使用できるようになります。
それでは、コールバック関数にいくつかの「非公開」変数を追加しましょう。これらはコントローラから直接アクセスすることはできませんが、必要に応じてこれらの「プライベート」変数を変更できるように、最終的に「service」にゲッター/セッターメソッドを設定します。
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;
});
ここでは、これらの変数や関数を「service」に関連付けていないことに気付くでしょう。後で使用または変更するために、それらを作成するだけです。
これで、ヘルパー/プライベート変数と関数が用意されたので、 'service'オブジェクトにいくつかのプロパティを追加しましょう。 myFactoryを渡したどのコントローラでも、serviceに設定したものはすべて直接使用できます。
アーティストを返すか設定するだけのsetArtistおよびgetArtistメソッドを作成します。作成したURLでiTunes APIを呼び出すメソッドも作成します。このメソッドは、データがiTunes APIから戻ってきたときに実行される約束を返します。 Angular JSでプロミスを使用した経験があまりない場合は、それらについて深く掘り下げることを強くお勧めします。
Below setArtist アーティストを受け入れ、アーティストを設定できます。 getArtist はアーティストを返します。 callItunes はまず$ httpリクエストで使用するURLを作成するためにmakeUrl()を呼び出します。それからpromiseオブジェクトを設定し、最後のURLで$ httpリクエストを行います。そして$ httpがpromiseを返すので、リクエストの後に.successまたは.errorを呼び出すことができます。その後、私たちはiTunesのデータで約束を解決するか、「エラーがありました」というメッセージでそれを拒否します。
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;
});
これで私たちの工場は完成しました。これで「myFactory」を任意のコントローラに注入できるようになり、サービスオブジェクトにアタッチしたメソッドを呼び出すことができるようになります(setArtist、getArtist、および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);
})
}
});
上記のコントローラでは、「myFactory」サービスを注入しています。次に、 'myFactory'からのデータを使用して、$ scopeオブジェクトのプロパティを設定します。上記の唯一のトリッキーなコードは、あなたがこれまで約束を扱ったことがない場合です。 callItunesは約束を返しているので、.then()メソッドを使用して、約束がiTunesデータで満たされた後にのみ$ scope.data.artistDataを設定することができます。あなたは私たちのコントローラーが非常に「薄い」ことに気付くでしょう(これは良いコーディング習慣です)。私たちのロジックと永続データはすべて私たちのサービス内にあり、私たちのコントローラー内にはありません。
2)サービス
おそらく、サービスの作成を扱うときに知っておくべき最大のことは、それが「new」キーワードでインスタンス化されているということです。あなたにとってJavaScriptの達人はこれがあなたにコードの性質への大きなヒントを与えるべきです。 JavaScriptの知識が限られている方、または「new」キーワードが実際に行うことに慣れていない方のために、最終的にサービスの性質を理解するのに役立つJavaScriptの基礎をいくつか見てみましょう。
「new」キーワードを使用して関数を呼び出したときに発生する変更を実際に確認するには、関数を作成して「new」キーワードを使用して呼び出してから、「new」キーワードを見たときのインタプリタの動作を示します。最終結果は両方とも同じになります。
まずコンストラクタを作成しましょう。
var Person = function(name, age){
this.name = name;
this.age = age;
}
これは典型的なJavaScriptコンストラクタ関数です。 「new」キーワードを使用してPerson関数を呼び出すたびに、「this」は新しく作成されたオブジェクトにバインドされます。
それでは、Personのプロトタイプにメソッドを追加して、Personのすべてのインスタンスのクラスで使用できるようにしましょう。
Person.prototype.sayName = function(){
alert(‘My name is ‘ + this.name);
}
プロトタイプにsayName関数を追加したので、Personのすべてのインスタンスは、そのインスタンスの名前を警告するためにsayName関数を呼び出すことができます。
プロトタイプにPersonコンストラクター関数とsayName関数があるので、実際にPersonのインスタンスを作成してから、sayName関数を呼び出します。
var tyler = new Person(‘Tyler’, 23);
tyler.sayName(); //alerts ‘My name is Tyler’
つまり、Personコンストラクタを作成し、そのプロトタイプに関数を追加し、Personインスタンスを作成してから、そのプロトタイプでその関数を呼び出すためのコードは、すべてこのようになります。
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’
それでは、JavaScriptで「new」キーワードを使用したときに実際に何が起きているのかを見てみましょう。この例で「new」を使用した後は、それがオブジェクトであるかのように、「tyler」でメソッド(sayName)を呼び出すことができます。つまり、最初にPersonコンストラクタがオブジェクトを返していることがわかります。それがコード内で確認できるかどうかは関係ありません。次に、sayName関数は直接Personインスタンスではなくプロトタイプにあるため、Person関数が返すオブジェクトは失敗したルックアップでそのプロトタイプに委任する必要があります。もっと簡単に言うと、tyler.sayName()を呼び出すと、インタプリタは「OK、今作成した「tyler」オブジェクトを調べ、sayName関数を見つけて呼び出します」と言います。ちょっと待って、私はここでそれを見ません - 私が見るのは名前と年齢だけです、私はプロトタイプをチェックしましょう。うん、それはプロトタイプの上にあるように見えます、私がそれを呼びましょう。」.
下記は「new」キーワードが実際にJavaScriptで何をしているのかを考えるためのコードです。これは基本的に上の段落のコード例です。私は「インタプリタビュー」、つまりインタプリタがコードの中にコードを見る方法を置きます。
var Person = function(name, age){
//The below line creates an object(obj) 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;
}
JavaScriptで 'new'キーワードが実際に何をするのかについてのこの知識を持っているので、AngularJSでサービスを作成することは理解しやすいはずです。
サービスを作成するときに理解するべき最大のことは、サービスが「new」キーワードでインスタンス化されていることを知っていることです。その知識を上記の例と組み合わせることで、あなたは自分のプロパティとメソッドを「this」に直接付加することになり、それがサービス自体から返されることになります。これを実際に見てみましょう。
Factoryの例で最初に行ったこととは異なり、オブジェクトを作成してからそのオブジェクトを返す必要はありません。これは、前述のように、 'new'キーワードを使用してインタープリタがそのオブジェクトを作成するためです。それはプロトタイプであり、それから私たちがその仕事をする必要なしにそれを私たちのために返します。
まず最初に、私たちの「プライベート」およびヘルパー関数を作成しましょう。私達は私達の工場と全く同じことをしたので、これは非常におなじみのはずです。ここでは各行の動作を説明しません。ファクトリの例で説明したのですが、混乱した場合はファクトリの例をもう一度読んでください。
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」に追加します。
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;
}
});
今や私たちの工場のように、setArtist、getArtist、およびcallItunesはmyServiceを渡したどのコントローラでも利用可能になります。これがmyServiceコントローラーです(これは、ファクトリーコントローラーとほぼ同じです)。
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);
})
}
});
前述したように、「新しい」機能の概要を理解すると、サービスはAngularJSの工場とほぼ同じになります。
3)プロバイダ
プロバイダについて覚えておくべき最大のことは、それらがあなたがあなたのアプリケーションのapp.config部分に渡すことができる唯一のサービスであるということです。アプリケーション内の他の場所で利用できるようになる前にサービスオブジェクトの一部を変更する必要がある場合、これは非常に重要です。サービス/ファクトリに非常に似ていますが、私たちが議論するいくつかの違いがあります。
最初に私達は私達が私達のサービスと工場で行ったのと同じ方法で私達のプロバイダーを設定しました。以下の変数は、私たちの「非公開」およびヘルパー関数です。
app.provider('myProvider', function(){
var baseUrl = 'https://iTunes.Apple.com/search?term=';
var _artist = '';
var _finalUrl = '';
//Going to set this property on the config function below.
this.thingFromConfig = ‘’;
var makeUrl = function(){
_artist = _artist.split(' ').join('+');
_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
return _finalUrl;
}
}
*上記のコードのいずれかの部分が混乱を招くような場合は、Factoryのセクションを見てください。ここで、すべての詳細について説明しています。
プロバイダは3つのセクションを持つと考えることができます。最初のセクションは、後で変更/設定される「非公開の」変数/関数です(上図)。 2番目のセクションは、app.config関数で使用できる変数/関数です。したがって、他の場所でも使用可能になる前に変更することができます(上記も参照)。これらの変数は「this」キーワードに付加する必要があることに注意することが重要です。この例では、app.configファイルで変更できるのはthingFromConfigだけです。 3番目のセクション(下図)は、 'myProvider'サービスをその特定のコントローラーに渡したときに、コントローラーで利用できるすべての変数/関数です。
Providerでサービスを作成するとき、あなたのコントローラで利用できる唯一のプロパティ/メソッドは$ get()関数から返されるそれらのプロパティ/メソッドです。以下のコードは$ getを 'this'にします(これは最終的にその関数から返されることがわかっています)。これで、その$ get関数は、コントローラで利用可能にしたいすべてのメソッド/プロパティを返します。これがコード例です。
this.$get = function($http, $q){
return {
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;
},
setArtist: function(artist){
_artist = artist;
},
getArtist: function(){
return _artist;
},
thingOnConfig: this.thingFromConfig
}
}
今すぐ完全なプロバイダコードはこのようになります
app.provider('myProvider', function(){
var baseUrl = 'https://iTunes.Apple.com/search?term=';
var _artist = '';
var _finalUrl = '';
//Going to set this property on the config function below
this.thingFromConfig = '';
var makeUrl = function(){
_artist = _artist.split(' ').join('+');
_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
return _finalUrl;
}
this.$get = function($http, $q){
return {
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;
},
setArtist: function(artist){
_artist = artist;
},
getArtist: function(){
return _artist;
},
thingOnConfig: this.thingFromConfig
}
}
});
これで、ファクトリやサービスと同じように、setArtist、getArtist、およびcallItunesは、myProviderを渡したどのコントローラでも使用可能になります。これがmyProviderコントローラです(これは、ファクトリ/サービスコントローラとほぼ同じです)。
app.controller('myProviderCtrl', function($scope, myProvider){
$scope.data = {};
$scope.updateArtist = function(){
myProvider.setArtist($scope.data.artist);
};
$scope.submitArtist = function(){
myProvider.callItunes()
.then(function(data){
$scope.data.artistData = data;
}, function(data){
alert(data);
})
}
$scope.data.thingFromConfig = myProvider.thingOnConfig;
});
前述のように、Providerを使用してサービスを作成することの全体的な目的は、最後のオブジェクトがアプリケーションの残りの部分に渡される前に、app.config関数を介していくつかの変数を変更できるようにすることです。その例を見てみましょう。
app.config(function(myProviderProvider){
//Providers are the only service you can pass into app.config
myProviderProvider.thingFromConfig = 'This sentence was set in app.config. Providers are the only service that can be passed into config. Check out the code to see how it works';
});
これで、私たちのプロバイダでは「thingFromConfig」が空の文字列であることがわかりますが、それがDOMに表示されると、「This文が設定されました…」となります。
AngularJSのファクトリ、サービス、およびプロバイダについて
これらはすべて、再利用可能なシングルトンオブジェクトを共有するために使用されています。それはあなたのアプリ/様々なコンポーネント/モジュール間で再利用可能なコードを共有するのを助けます。
Docs Service/Factory から:
- 遅延インスタンス化 - Angularは、アプリケーションコンポーネントが依存する場合にのみサービス/ファクトリをインスタンス化します。
- シングルトン - サービスに依存する各コンポーネントは、サービスファクトリによって生成された単一のインスタンスへの参照を取得します。
ファクトリは、オブジェクトを作成する前にロジックを操作/追加することができる機能で、新しく作成されたオブジェクトが返されます。
app.factory('MyFactory', function() {
var serviceObj = {};
//creating an object with methods/functions or variables
serviceObj.myFunction = function() {
//TO DO:
};
//return that object
return serviceObj;
});
使用方法
それは単なるクラスのような関数の集まりです。したがって、それをあなたのcontroller/factory/directive関数の中にインジェクトするとき、それは異なるコントローラでインスタンス化されることができます。アプリごとに一度だけインスタンス化されます。
サービスを見ながら、単にアレイのプロトタイプについて考えてください。サービスは 'new'キーワードを使って新しいオブジェクトをインスタンス化する関数です。 this
キーワードを使用して、サービスオブジェクトにプロパティと関数を追加できます。ファクトリとは異なり、何も返しません(メソッド/プロパティを含むオブジェクトを返します)。
app.service('MyService', function() {
//directly binding events to this context
this.myServiceFunction = function() {
//TO DO:
};
});
使用方法
アプリケーション全体で単一のオブジェクトを共有する必要があるときに使用します。例えば、認証されたユーザーの詳細、共有可能な方法/データ、ユーティリティ機能など.
プロバイダは、設定可能なサービスオブジェクトを作成するために使用されます。 config関数からサービス設定を構成できます。 $get()
関数を使って値を返します。 $get
関数は、実行フェーズで角度付きで実行されます。
app.provider('configurableService', function() {
var name = '';
//this method can be be available at configuration time inside app.config.
this.setName = function(newName) {
name = newName;
};
this.$get = function() {
var getName = function() {
return name;
};
return {
getName: getName //exposed object to where it gets injected.
};
};
});
使用方法
サービスオブジェクトを利用可能にする前に、モジュール単位の設定を提供する必要がある場合。 dev
、stage
、prod
のように、自分の環境に基づいてAPI URLを設定したいとします。
_ note _
Service&factoryはそうではありませんがプロバイダだけが角度の設定段階で利用可能になります。
これで ファクトリー、サービス、およびプロバイダー についての理解が深まったことを願います。
私にとっては、何かが once を実行し、得られた値を格納し、それから 参照されたときに同じ格納された値 を実行することによって 依存性注入を介して 。
たとえば、
app.factory('a', fn);
app.service('b', fn);
app.provider('c', fn);
この3つの違いは、
a
の格納値は、fn
を実行することによって得られます。b
の保存値はnew
ing fn
から来ます。c
の格納値は、まずnew
をfn
することによってインスタンスを取得し、次にそのインスタンスの$get
メソッドを実行することによって得られます。つまり、AngularJSの内部にはキャッシュオブジェクトのようなものがあります。各インジェクションの値は、最初にインジェクションされたときに一度だけ割り当てられます。
cache.a = fn()
cache.b = new fn()
cache.c = (new fn()).$get()
これが、サービスでthis
を使用し、プロバイダでthis.$get
を定義する理由です。
サービス対プロバイダ対工場:
私はそれを単純にしようとしています。基本的なJavaScriptの概念に関するすべてです。
まずはじめに、AngularJSで services について説明しましょう。
サービスとは: AngularJSでは、 Service は、便利なメソッドやプロパティを格納できるシングルトンJavaScriptオブジェクトに他なりません。このシングルトンオブジェクトはngApp(Angular app)ごとに作成され、現在のアプリ内のすべてのコントローラ間で共有されます。 Angularは、サービスオブジェクトをインスタンス化するときに、このサービスオブジェクトを一意のサービス名で登録します。そのため、サービスインスタンスが必要になるたびに、Angularがこのサービス名のレジストリを検索し、サービスオブジェクトへの参照を返します。メソッドを呼び出したり、サービスオブジェクトのプロパティにアクセスしたりできるようにします。プロパティ、メソッドをコントローラのスコープオブジェクトにも置くことができるかどうか質問があるかもしれません!それでは、なぜあなたはサービスオブジェクトが必要ですか?答えは次のとおりです。サービスは複数のコントローラスコープ間で共有されます。いくつかのプロパティ/メソッドをコントローラのスコープオブジェクトに入れると、それは現在のスコープでのみ利用可能になります。しかし、サービスオブジェクトにメソッドやプロパティを定義すると、それはグローバルに利用可能になり、そのサービスを注入することで任意のコントローラのスコープ内でアクセスできるようになります。
そのため、3つのコントローラスコープがある場合、それをcontrollerA、controllerB、controllerCとすると、すべて同じサービスインスタンスを共有します。
<div ng-controller='controllerA'>
<!-- controllerA scope -->
</div>
<div ng-controller='controllerB'>
<!-- controllerB scope -->
</div>
<div ng-controller='controllerC'>
<!-- controllerC scope -->
</div>
サービスの作り方
AngularJSには、サービスを登録するためのさまざまな方法があります。ここでは3つのメソッドfactory(..)、service(..)、provider(..)に集中します。
ファクトリ関数は以下のように定義できます。
factory('serviceName',function fnFactory(){ return serviceInstance;})
AngularJSは 'factory(' serviceName '、fnFactory)' の2つのパラメータserviceNameとJavaScript関数を取るメソッドを提供します。 Angularは、次のように fnFactory() という関数を呼び出してサービスインスタンスを作成します。
var serviceInstace = fnFactory();
渡された関数はオブジェクトを定義し、そのオブジェクトを返すことができます。 AngularJSは、このオブジェクト参照を最初の引数として渡される変数に単純に格納します。 fnFactoryから返されるものはすべてserviceInstanceにバインドされます。オブジェクトを返す代わりに、関数、値なども返すことができます。返されるものはすべて、インスタンスのサービスに使用できます。
例:
var app= angular.module('myApp', []);
//creating service using factory method
app.factory('factoryPattern',function(){
var data={
'firstName':'Tom',
'lastName':' Cruise',
greet: function(){
console.log('hello!' + this.firstName + this.lastName);
}
};
//Now all the properties and methods of data object will be available in our service object
return data;
});
service('serviceName',function fnServiceConstructor(){})
それは別の方法です、私たちはサービスを登録することができます。唯一の違いは、AngularJSがサービスオブジェクトをインスタンス化する方法です。今回はAngularは 'new'キーワードを使用して以下のようなコンストラクタ関数を呼び出します。
var serviceInstance = new fnServiceConstructor();
コンストラクター関数では、サービスオブジェクトにプロパティ/メソッドを追加するために 'this'キーワードを使用できます。例:
//Creating a service using the service method
var app= angular.module('myApp', []);
app.service('servicePattern',function(){
this.firstName ='James';
this.lastName =' Bond';
this.greet = function(){
console.log('My Name is '+ this.firstName + this.lastName);
};
});
Provider()関数は、サービスを作成するためのもう1つの方法です。ユーザーにグリーティングメッセージを表示するだけのサービスを作成したいと思います。しかし私達はまたユーザーが彼ら自身の挨拶メッセージを設定できるような機能を提供したいと思います。技術的には、設定可能なサービスを作りたいです。どうすればこれができますか?アプリがカスタムのあいさつメッセージを渡すことができ、Angularjsがそれを私たちのサービスインスタンスを作成するファクトリ/コンストラクタ関数で利用できるようにする方法があるはずです。そのような場合、provider()関数が仕事をします。 provider()関数を使用して、設定可能なサービスを作成できます。
以下に示すように、プロバイダ構文を使用して構成可能サービスを作成できます。
/*step1:define a service */
app.provider('service',function serviceProviderConstructor(){});
/*step2:configure the service */
app.config(function configureService(serviceProvider){});
1.Providerオブジェクトは、プロバイダ関数で定義したコンストラクタ関数を使って作成されます。
var serviceProvider = new serviceProviderConstructor();
2. app.config()で渡した関数が実行されます。これは設定段階と呼ばれ、ここで私達は私達のサービスをカスタマイズする機会があります。
configureService(serviceProvider);
3.最後にserviceProviderの$ getメソッドを呼び出してサービスインスタンスを作成します。
serviceInstance = serviceProvider.$get()
var app= angular.module('myApp', []);
app.provider('providerPattern',function providerConstructor(){
//this function works as constructor function for provider
this.firstName = 'Arnold ';
this.lastName = ' Schwarzenegger' ;
this.greetMessage = ' Welcome, This is default Greeting Message' ;
//adding some method which we can call in app.config() function
this.setGreetMsg = function(msg){
if(msg){
this.greetMessage = msg ;
}
};
//We can also add a method which can change firstName and lastName
this.$get = function(){
var firstName = this.firstName;
var lastName = this.lastName ;
var greetMessage = this.greetMessage;
var data={
greet: function(){
console.log('hello, ' + firstName + lastName+'! '+ greetMessage);
}
};
return data ;
};
});
app.config(
function(providerPatternProvider){
providerPatternProvider.setGreetMsg(' How do you do ?');
}
);
要約:
Factory サービスインスタンスを返すファクトリ関数を使用します。 serviceInstance = fnFactory();
Service コンストラクタ関数を使用し、Angularサービスインスタンスを作成するために 'new'キーワードを使用してこのコンストラクタ関数を呼び出します。 serviceInstance = new fnServiceConstructor();
Provider はproviderConstructor関数を定義し、このproviderConstructor関数はファクトリ関数 $ get を定義します。 Angularは$ get()を呼び出してサービスオブジェクトを作成します。プロバイダ構文には、インスタンス化される前にサービスオブジェクトを設定するという追加の利点があります。 serviceInstance = $ get();
ここで何人かの人々によって正しく指摘されているように、ファクトリー、プロバイダー、サービス、さらには値と定数さえ同じもののバージョンです。あなたはより一般的なprovider
をそれらすべてに詳細に分けることができます。そのようです:
この画像の元の記事は次のとおりです。
AngularJSに関数を与えると、AngularJSはファクトリが要求されたときに戻り値をキャッシュして注入します。
例:
app.factory('factory', function() {
var name = '';
// Return value **is** the object that will be injected
return {
name: name;
}
})
使用法:
app.controller('ctrl', function($scope, factory) {
$scope.name = factory.name;
});
AngularJSに関数を指定すると、AngularJSがnewを呼び出してインスタンス化します。サービスが要求されたときにキャッシュおよび挿入されるのは、AngularJSが作成するインスタンスです。 newがサービスのインスタンス化に使用されたため、キーワードthis は有効で、インスタンスを参照します。
例:
app.service('service', function() {
var name = '';
this.setName = function(newName) {
name = newName;
}
this.getName = function() {
return name;
}
});
使用法:
app.controller('ctrl', function($scope, service) {
$scope.name = service.getName();
});
AngularJSに関数を指定すると、AngularJSはその$get
関数を呼び出します。サービスが要求されたときにキャッシュおよび挿入されるのは、$get
関数からの戻り値です。
プロバイダーを使用すると、プロバイダーを構成できますbefore AngularJSは$get
メソッドを呼び出して、注入可能を取得します。
例:
app.provider('provider', function() {
var name = '';
this.setName = function(newName) {
name = newName;
}
this.$get = function() {
return {
name: name
}
}
})
使用法(コントローラーに注入可能なものとして)
app.controller('ctrl', function($scope, provider) {
$scope.name = provider.name;
});
使用法($get
が呼び出される前にプロバイダーを構成して、注入可能オブジェクトを作成します)
app.config(function(providerProvider) {
providerProvider.setName('John');
});
私はプロバイダーと遊んでいるときに面白いことに気づきました。
注射剤の視認性は、サービスや工場の場合とはプロバイダーによって異なります。 AngularJSを「定数」(たとえば、myApp.constant('a', 'Robert');
)として宣言すると、それをサービス、ファクトリ、およびプロバイダに挿入できます。
しかし、AngularJSの "value"(たとえば、myApp.value('b', {name: 'Jones'});
)を宣言すると、それをサービスやファクトリに挿入できますが、プロバイダ作成関数には挿入できません。ただし、プロバイダに定義した$get
関数に挿入することはできます。これはAngularJSのドキュメントに記載されていますが、見逃しがちです。値メソッドと定数メソッドのセクションの%provideページにあります。
http://jsfiddle.net/R2Frv/1/ /
<div ng-app="MyAppName">
<div ng-controller="MyCtrl">
<p>from Service: {{servGreet}}</p>
<p>from Provider: {{provGreet}}</p>
</div>
</div>
<script>
var myApp = angular.module('MyAppName', []);
myApp.constant('a', 'Robert');
myApp.value('b', {name: 'Jones'});
myApp.service('greetService', function(a,b) {
this.greeter = 'Hi there, ' + a + ' ' + b.name;
});
myApp.provider('greetProvider', function(a) {
this.firstName = a;
this.$get = function(b) {
this.lastName = b.name;
this.fullName = this.firstName + ' ' + this.lastName;
return this;
};
});
function MyCtrl($scope, greetService, greetProvider) {
$scope.servGreet = greetService.greeter;
$scope.provGreet = greetProvider.fullName;
}
</script>
これは初心者にとって非常に混乱を招く部分であり、私は簡単な言葉でそれを明確にしようとしました
AngularJS Service: は、コントローラ内のサービス参照とユーティリティ機能を共有するために使用されます。サービスは本質的にシングルトンなので、1つのサービスではブラウザに1つのインスタンスしか作成されず、ページ全体で同じ参照が使用されます。
このサービスでは、this objectを持つプロパティとして関数名を作成します。
AngularJS Factory: Factoryの目的もServiceと同じですが、この場合は新しいオブジェクトを作成し、このオブジェクトのプロパティとして関数を追加して、最後にこのオブジェクトを返します。
AngularJSプロバイダ: この目的は同じですが、プロバイダは$ get関数の出力を返します。
Service、Factory、Providerの定義と使用方法は http://www.dotnetfunda.com/articles/show/3156/difference-between-angularjs-service-factory-and-provider で説明されています。
私にとって違いを理解するための最善かつ最も簡単な方法は次のとおりです。
var service, factory;
service = factory = function(injection) {}
AngularJSが特定のコンポーネントをインスタンス化する方法(簡略化):
// service
var angularService = new service(injection);
// factory
var angularFactory = factory(injection);
したがって、サービスにとってAngularJSコンポーネントとなるのは、サービス宣言関数によって表されるクラスのオブジェクトインスタンスです。ファクトリの場合は、ファクトリ宣言関数から返された結果です。ファクトリはサービスと同じように振る舞うかもしれません:
var factoryAsService = function(injection) {
return new function(injection) {
// Service content
}
}
最も簡単な考え方は次のとおりです。
ファクトリの「クラス」の例は、プロバイダの違いとともに、周りのコメントで提供されています。
この問題に関する私の説明:
基本的に、上記のタイプ(サービス、ファクトリ、プロバイダなど)はすべて、グローバル変数(もちろんアプリケーション全体に対してグローバル)を作成および構成しているだけです。
グローバル変数はお勧めできませんが、これらのグローバル変数の実際の使用法は、変数を関連するコントローラーに渡すことによって 依存性注入 を提供することです。
「グローバル変数」の値を作成する際には、さまざまなレベルの複雑さがあります。
app.config
から使用できます。app.config
ファイルを通して上記のプロパティを設定した後にAngularJSによって実行される独立した$ .get関数を持つ必要があり、そしてこの$ .get関数は振る舞います。上記のfactoryと同じように、その戻り値は「グローバル」変数の初期化に使用されます。私の理解は以下でとても簡単です。
ファクトリ: あなたは単にファクトリの中にオブジェクトを作成してそれを返す。
サービス:
このキーワードを使って関数を定義する標準関数があります。
プロバイダー:
あなたが定義する$get
オブジェクトがあり、それはデータを返すオブジェクトを取得するために使うことができます。
Angular docs からの要約:
SOからのベストアンサー:
https://stackoverflow.com/a/26924234/16567 (<-GOOD) https://stackoverflow.com/a/27263882/16567
https://stackoverflow.com/a/16566144/16567
良い答えはもうありますが、これを共有したいと思います。
まず最初に、Providerは$ injectorによってインジェクトされると想定されるservice
(singletonオブジェクト)を作成する方法/レシピです(AngulaJSはIoCパターンをどう扱うか)。
そしてValue、Factory、ServiceそしてConstant(4つの方法) - Provider way/recepieに対する統語上の糖。
Service vs Factory
の部分がカバーされています: https://www.youtube.com/watch?v=BLzNCkPn3ao
Serviceは実際にはすべてnew
キーワードに関するもので、これは4つのことを行います。
prototype
オブジェクトにリンクしますcontext
をthis
に接続しますthis
を返しますそしてFactoryはすべてFactory Patternに関するものです - そのサービスのようなオブジェクトを返す関数を含みます。
そして、この簡単で短いビデオ:Provider: https://www.youtube.com/watch?v=HvTZbQ_hUZY をカバーしています。
Provider recipeは、アプリが完全に起動または初期化される前に、主にアプリ構成で使用されます。
さらに明確にすると、ファクトリーは関数/プリミティブを作成できますが、サービスはできません。これをチェックしてください jsFiddle Epokkに基づいて: http://jsfiddle.net/skeller88/PxdSP/1351/ 。
ファクトリは呼び出すことができる関数を返します。
myApp.factory('helloWorldFromFactory', function() {
return function() {
return "Hello, World!";
};
});
ファクトリは、呼び出すことができるメソッドでオブジェクトを返すこともできます。
myApp.factory('helloWorldFromFactory', function() {
return {
sayHello: function() {
return "Hello, World!";
}
};
});
サービスは、呼び出すことができるメソッドを持つオブジェクトを返します。
myApp.service('helloWorldFromService', function() {
this.sayHello = function() {
return "Hello, World!";
};
});
詳細については、私が違いについて書いた記事を参照してください。 http://www.shanemkeller.com/tldr-services-vs-factories-in-angular/ /
これらすべての記事を読んだ後、それは私のためにもっと混乱を作成しました。
そして初心者のために理解してください: - これは正しいユースケースではないかもしれませんが、高レベルでこれはこれら3つのユースケースです。
angular.module('myApp').config(function($testProvider){
$testProvider.someFunction();
})
基本的なシナリオでは、factory&Serviceは同じように振る舞います。
AngularjSでオブジェクトファクトリのコードテンプレートとして私が思い付いた、いくつかの定型コードがあります。例としてCar/CarFactoryを使用しました。コントローラに簡単な実装コードを作ります。
<script>
angular.module('app', [])
.factory('CarFactory', function() {
/**
* BroilerPlate Object Instance Factory Definition / Example
*/
this.Car = function() {
// initialize instance properties
angular.extend(this, {
color : null,
numberOfDoors : null,
hasFancyRadio : null,
hasLeatherSeats : null
});
// generic setter (with optional default value)
this.set = function(key, value, defaultValue, allowUndefined) {
// by default,
if (typeof allowUndefined === 'undefined') {
// we don't allow setter to accept "undefined" as a value
allowUndefined = false;
}
// if we do not allow undefined values, and..
if (!allowUndefined) {
// if an undefined value was passed in
if (value === undefined) {
// and a default value was specified
if (defaultValue !== undefined) {
// use the specified default value
value = defaultValue;
} else {
// otherwise use the class.prototype.defaults value
value = this.defaults[key];
} // end if/else
} // end if
} // end if
// update
this[key] = value;
// return reference to this object (fluent)
return this;
}; // end this.set()
}; // end this.Car class definition
// instance properties default values
this.Car.prototype.defaults = {
color: 'yellow',
numberOfDoors: 2,
hasLeatherSeats: null,
hasFancyRadio: false
};
// instance factory method / constructor
this.Car.prototype.instance = function(params) {
return new
this.constructor()
.set('color', params.color)
.set('numberOfDoors', params.numberOfDoors)
.set('hasFancyRadio', params.hasFancyRadio)
.set('hasLeatherSeats', params.hasLeatherSeats)
;
};
return new this.Car();
}) // end Factory Definition
.controller('testCtrl', function($scope, CarFactory) {
window.testCtrl = $scope;
// first car, is red, uses class default for:
// numberOfDoors, and hasLeatherSeats
$scope.car1 = CarFactory
.instance({
color: 'red'
})
;
// second car, is blue, has 3 doors,
// uses class default for hasLeatherSeats
$scope.car2 = CarFactory
.instance({
color: 'blue',
numberOfDoors: 3
})
;
// third car, has 4 doors, uses class default for
// color and hasLeatherSeats
$scope.car3 = CarFactory
.instance({
numberOfDoors: 4
})
;
// sets an undefined variable for 'hasFancyRadio',
// explicitly defines "true" as default when value is undefined
$scope.hasFancyRadio = undefined;
$scope.car3.set('hasFancyRadio', $scope.hasFancyRadio, true);
// fourth car, purple, 4 doors,
// uses class default for hasLeatherSeats
$scope.car4 = CarFactory
.instance({
color: 'purple',
numberOfDoors: 4
});
// and then explicitly sets hasLeatherSeats to undefined
$scope.hasLeatherSeats = undefined;
$scope.car4.set('hasLeatherSeats', $scope.hasLeatherSeats, undefined, true);
// in console, type window.testCtrl to see the resulting objects
});
</script>
これはもっと簡単な例です。私は緯度と経度を公開する "Position"オブジェクトを期待するが、異なるオブジェクトプロパティを介して、いくつかのサードパーティライブラリを使用しています。ベンダーコードをハックしたくなかったので、渡した "Position"オブジェクトを調整しました。
angular.module('app')
.factory('PositionFactory', function() {
/**
* BroilerPlate Object Instance Factory Definition / Example
*/
this.Position = function() {
// initialize instance properties
// (multiple properties to satisfy multiple external interface contracts)
angular.extend(this, {
lat : null,
lon : null,
latitude : null,
longitude : null,
coords: {
latitude: null,
longitude: null
}
});
this.setLatitude = function(latitude) {
this.latitude = latitude;
this.lat = latitude;
this.coords.latitude = latitude;
return this;
};
this.setLongitude = function(longitude) {
this.longitude = longitude;
this.lon = longitude;
this.coords.longitude = longitude;
return this;
};
}; // end class definition
// instance factory method / constructor
this.Position.prototype.instance = function(params) {
return new
this.constructor()
.setLatitude(params.latitude)
.setLongitude(params.longitude)
;
};
return new this.Position();
}) // end Factory Definition
.controller('testCtrl', function($scope, PositionFactory) {
$scope.position1 = PositionFactory.instance({latitude: 39, longitude: 42.3123});
$scope.position2 = PositionFactory.instance({latitude: 39, longitude: 42.3333});
}) // end controller
;
このページと ドキュメンテーション (前回見てから大きく改善されたようです)を参考にして、以下の5つのうち4つのプロバイダのフレーバーを使用する以下の実際の(現実の)世界のデモをまとめました。価値、定数、工場および本格的なプロバイダー。
HTML:
<div ng-controller="mainCtrl as main">
<h1>{{main.title}}*</h1>
<h2>{{main.strapline}}</h2>
<p>Earn {{main.earn}} per click</p>
<p>You've earned {{main.earned}} by clicking!</p>
<button ng-click="main.handleClick()">Click me to earn</button>
<small>* Not actual money</small>
</div>
アプリ
var app = angular.module('angularProviders', []);
// A CONSTANT is not going to change
app.constant('range', 100);
// A VALUE could change, but probably / typically doesn't
app.value('title', 'Earn money by clicking');
app.value('strapline', 'Adventures in ng Providers');
// A simple FACTORY allows us to compute a value @ runtime.
// Furthermore, it can have other dependencies injected into it such
// as our range constant.
app.factory('random', function randomFactory(range) {
// Get a random number within the range defined in our CONSTANT
return Math.random() * range;
});
// A PROVIDER, must return a custom type which implements the functionality
// provided by our service (see what I did there?).
// Here we define the constructor for the custom type the PROVIDER below will
// instantiate and return.
var Money = function(locale) {
// Depending on locale string set during config phase, we'll
// use different symbols and positioning for any values we
// need to display as currency
this.settings = {
uk: {
front: true,
currency: '£',
thousand: ',',
decimal: '.'
},
eu: {
front: false,
currency: '€',
thousand: '.',
decimal: ','
}
};
this.locale = locale;
};
// Return a monetary value with currency symbol and placement, and decimal
// and thousand delimiters according to the locale set in the config phase.
Money.prototype.convertValue = function(value) {
var settings = this.settings[this.locale],
decimalIndex, converted;
converted = this.addThousandSeparator(value.toFixed(2), settings.thousand);
decimalIndex = converted.length - 3;
converted = converted.substr(0, decimalIndex) +
settings.decimal +
converted.substr(decimalIndex + 1);
converted = settings.front ?
settings.currency + converted :
converted + settings.currency;
return converted;
};
// Add supplied thousand separator to supplied value
Money.prototype.addThousandSeparator = function(value, symbol) {
return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, symbol);
};
// PROVIDER is the core recipe type - VALUE, CONSTANT, SERVICE & FACTORY
// are all effectively syntactic sugar built on top of the PROVIDER construct
// One of the advantages of the PROVIDER is that we can configure it before the
// application starts (see config below).
app.provider('money', function MoneyProvider() {
var locale;
// Function called by the config to set up the provider
this.setLocale = function(value) {
locale = value;
};
// All providers need to implement a $get method which returns
// an instance of the custom class which constitutes the service
this.$get = function moneyFactory() {
return new Money(locale);
};
});
// We can configure a PROVIDER on application initialisation.
app.config(['moneyProvider', function(moneyProvider) {
moneyProvider.setLocale('uk');
//moneyProvider.setLocale('eu');
}]);
// The ubiquitous controller
app.controller('mainCtrl', function($scope, title, strapline, random, money) {
// Plain old VALUE(s)
this.title = title;
this.strapline = strapline;
this.count = 0;
// Compute values using our money provider
this.earn = money.convertValue(random); // random is computed @ runtime
this.earned = money.convertValue(0);
this.handleClick = function() {
this.count ++;
this.earned = money.convertValue(random * this.count);
};
});
Working デモ 。
この回答はトピック/質問に対応しています
_または_
基本的には
あなたがfactory()
を作るとき、それはあなたがプロバイダの$get
への2番目の引数で与えられたfunction
をセットしてそれを返す(provider(name, {$get:factoryFn })
)、 あなたが得るのはprovider
だけですが$get
以外のプロパティ/メソッドはありません そのprovider
(これを設定できないことを意味します)
工場のソースコード
function factory(name, factoryFn, enforce) {
return provider(name, {
$get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
});
};
service()
を作成するとき、function
をインジェクトするconstructor
を含むfactory()を返し(サービスで提供したコンストラクタのインスタンスを返し)、それを返します。
サービスのソースコード
function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
};
そのため、基本的にどちらの場合も、最終的には提供された関数にプロバイダ$ getが設定されますが、configブロックのためにprovider()で元々提供されたように$ get以外のものを追加できます。
私はすばらしい答えをたくさん知っていますが、私の使用経験を共有しなければなりません
1。デフォルトのほとんどの場合はservice
2。特定のインスタンスのサービスを作成するために使用されるfactory
// factory.js ////////////////////////////
(function() {
'use strict';
angular
.module('myApp.services')
.factory('xFactory', xFactoryImp);
xFactoryImp.$inject = ['$http'];
function xFactoryImp($http) {
var fac = function (params) {
this._params = params; // used for query params
};
fac.prototype.nextPage = function () {
var url = "/_prc";
$http.get(url, {params: this._params}).success(function(data){ ...
}
return fac;
}
})();
// service.js //////////////////////////
(function() {
'use strict';
angular
.module('myApp.services')
.service('xService', xServiceImp);
xServiceImp.$inject = ['$http'];
function xServiceImp($http) {
this._params = {'model': 'account','mode': 'list'};
this.nextPage = function () {
var url = "/_prc";
$http.get(url, {params: this._params}).success(function(data){ ...
}
}
})();
そして使用:
controller: ['xFactory', 'xService', function(xFactory, xService){
// books = new instance of xFactory for query 'book' model
var books = new xFactory({'model': 'book', 'mode': 'list'});
// accounts = new instance of xFactory for query 'accounts' model
var accounts = new xFactory({'model': 'account', 'mode': 'list'});
// accounts2 = accounts variable
var accounts2 = xService;
...
パーティーには少し遅れました。しかし、これは、ファクトリ、サービス、およびプロバイダの方法論を使用してAngular JSカスタムサービスを開発する上で習得したい(または明確にしたい)人にとってはより役立つと思いました。
AngularJSカスタムサービスを開発するための工場、サービス、およびプロバイダーの方法論について明確に説明しているこのビデオに出会いました。
https://www.youtube.com/watch?v=oUXku28ex-M
ソースコード: http://www.techcbt.com/Post/353/Angular-JS-basics/how-to-develop-angularjs-custom-service
ここに掲載されたコードは、読者のために上記のソースから直接コピーされています。
「ファクトリ」ベースのカスタムサービスのコードは次のとおりです(これは、httpサービスの呼び出しとともに、同期バージョンと非同期バージョンの両方に対応します)。
var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcFactory',
function($scope, calcFactory) {
$scope.a = 10;
$scope.b = 20;
$scope.doSum = function() {
//$scope.sum = calcFactory.getSum($scope.a, $scope.b); //synchronous
calcFactory.getSum($scope.a, $scope.b, function(r) { //aynchronous
$scope.sum = r;
});
};
}
]);
app.factory('calcFactory', ['$http', '$log',
function($http, $log) {
$log.log("instantiating calcFactory..");
var oCalcService = {};
//oCalcService.getSum = function(a,b){
// return parseInt(a) + parseInt(b);
//};
//oCalcService.getSum = function(a, b, cb){
// var s = parseInt(a) + parseInt(b);
// cb(s);
//};
oCalcService.getSum = function(a, b, cb) { //using http service
$http({
url: 'http://localhost:4467/Sum?a=' + a + '&b=' + b,
method: 'GET'
}).then(function(resp) {
$log.log(resp.data);
cb(resp.data);
}, function(resp) {
$log.error("ERROR occurred");
});
};
return oCalcService;
}
]);
カスタムサービスのための「サービス」方法論のためのコード(これは 'factory'に非常に似ていますが、構文の観点からは異なります):
var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcService', function($scope, calcService){
$scope.a = 10;
$scope.b = 20;
$scope.doSum = function(){
//$scope.sum = calcService.getSum($scope.a, $scope.b);
calcService.getSum($scope.a, $scope.b, function(r){
$scope.sum = r;
});
};
}]);
app.service('calcService', ['$http', '$log', function($http, $log){
$log.log("instantiating calcService..");
//this.getSum = function(a,b){
// return parseInt(a) + parseInt(b);
//};
//this.getSum = function(a, b, cb){
// var s = parseInt(a) + parseInt(b);
// cb(s);
//};
this.getSum = function(a, b, cb){
$http({
url: 'http://localhost:4467/Sum?a=' + a + '&b=' + b,
method: 'GET'
}).then(function(resp){
$log.log(resp.data);
cb(resp.data);
},function(resp){
$log.error("ERROR occurred");
});
};
}]);
カスタムサービス用の「プロバイダ」メソドロジのコード(設定可能なサービスを開発したい場合はこれが必要です)。
var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcService', function($scope, calcService){
$scope.a = 10;
$scope.b = 20;
$scope.doSum = function(){
//$scope.sum = calcService.getSum($scope.a, $scope.b);
calcService.getSum($scope.a, $scope.b, function(r){
$scope.sum = r;
});
};
}]);
app.provider('calcService', function(){
var baseUrl = '';
this.config = function(url){
baseUrl = url;
};
this.$get = ['$log', '$http', function($log, $http){
$log.log("instantiating calcService...")
var oCalcService = {};
//oCalcService.getSum = function(a,b){
// return parseInt(a) + parseInt(b);
//};
//oCalcService.getSum = function(a, b, cb){
// var s = parseInt(a) + parseInt(b);
// cb(s);
//};
oCalcService.getSum = function(a, b, cb){
$http({
url: baseUrl + '/Sum?a=' + a + '&b=' + b,
method: 'GET'
}).then(function(resp){
$log.log(resp.data);
cb(resp.data);
},function(resp){
$log.error("ERROR occurred");
});
};
return oCalcService;
}];
});
app.config(['calcServiceProvider', function(calcServiceProvider){
calcServiceProvider.config("http://localhost:4467");
}]);
最後に、上記のサービスのいずれかと連携するUI:
<html>
<head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js" ></script>
<script type="text/javascript" src="t03.js"></script>
</head>
<body ng-app="app">
<div ng-controller="emp">
<div>
Value of a is {{a}},
but you can change
<input type=text ng-model="a" /> <br>
Value of b is {{b}},
but you can change
<input type=text ng-model="b" /> <br>
</div>
Sum = {{sum}}<br>
<button ng-click="doSum()">Calculate</button>
</div>
</body>
</html>
わかりやすくするために、AngularJSのソースから、サービスがファクトリ関数を呼び出し、次にファクトリ関数がプロバイダ関数を呼び出すことを確認できます。
function factory(name, factoryFn) {
return provider(name, { $get: factoryFn });
}
function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
}
メモリの目的に基づいて、コントローラは必要なときにだけインスタンス化され、そうでないときは破棄されます。このため、ルートを切り替えたりページをリロードするたびに、Angularは現在のコントローラをクリーンアップします。ただし、サービスは、アプリケーションの存続期間中データを保持し続けるための手段を提供しながら、一貫した方法でさまざまなコントローラ間でデータを使用することもできます。
Angularは、独自のサービスを作成および登録するための3つの方法を提供します。
1)工場
2)サービス
3)プロバイダー
Factory :factoryはオブジェクトを作成する前にロジックを追加することを可能にする簡単な関数です。作成したオブジェクトを返します。
それは単なるクラスのような関数の集まりです。したがって、コンストラクター関数で使用しているときは、異なるコントローラーでインスタンス化できます。
Service :serviceはnewキーワードを使ってオブジェクトを作成するコンストラクタ関数です。このキーワードを使用して、サービスオブジェクトにプロパティと機能を追加できます。工場とは異なり、何も返されません。
これはシングルトンオブジェクトです。アプリケーション全体で単一のオブジェクトを共有する必要があるときに使用します。たとえば、認証済みユーザーの詳細などです。
プロバイダ :プロバイダは設定可能なサービスオブジェクトを作成するために使用されます。 $ get()関数を使用して値を返します。
サービスオブジェクトを利用可能にする前に、モジュール単位の設定を提供する必要がある場合。
次のコードを実行して出力を確認してください。
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.min.js"></script>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body ng-controller="MyCtrl">
{{serviceOutput}}
<br/><br/>
{{factoryOutput}}
<br/><br/>
{{providerOutput}}
<script>
var app = angular.module( 'app', [] );
var MyFunc = function() {
this.name = "default name";
this.$get = function() {
this.name = "new name"
return "Hello from MyFunc.$get(). this.name = " + this.name;
};
return "Hello from MyFunc(). this.name = " + this.name;
};
// returns the actual function
app.service( 'myService', MyFunc );
// returns the function's return value
app.factory( 'myFactory', MyFunc );
// returns the output of the function's $get function
app.provider( 'myProv', MyFunc );
function MyCtrl( $scope, myService, myFactory, myProv ) {
$scope.serviceOutput = "myService = " + myService;
$scope.factoryOutput = "myFactory = " + myFactory;
$scope.providerOutput = "myProvider = " + myProv;
}
</script>
</body>
</html>
簡単な方法でAngularJSのビジネスロジックを処理する3つの方法について説明しましょう。(YaakovのCoursera AngularJSコースに触発された)
SERVICE:
構文:
app.js
var app = angular.module('ServiceExample',[]);
var serviceExampleController =
app.controller('ServiceExampleController', ServiceExampleController);
var serviceExample = app.service('NameOfTheService', NameOfTheService);
ServiceExampleController.$inject = ['NameOfTheService'] //protects from minification of js files
function ServiceExampleController(NameOfTheService){
serviceExampleController = this;
serviceExampleController.data = NameOfTheService.getSomeData();
}
function NameOfTheService(){
nameOfTheService = this;
nameOfTheService.data = "Some Data";
nameOfTheService.getSomeData = function(){
return nameOfTheService.data;
}
}
index.html
<div ng-controller = "ServiceExampleController as serviceExample">
{{serviceExample.data}}
</div>
サービスの特徴:
工場
まず構文を見てみましょう。
app.js:
var app = angular.module('FactoryExample',[]);
var factoryController = app.controller('FactoryController', FactoryController);
var factoryExampleOne = app.factory('NameOfTheFactoryOne', NameOfTheFactoryOne);
var factoryExampleTwo = app.factory('NameOfTheFactoryTwo', NameOfTheFactoryTwo);
//first implementation where it returns a function
function NameOfTheFactoryOne(){
var factory = function(){
return new SomeService();
}
return factory;
}
//second implementation where an object literal would be returned
function NameOfTheFactoryTwo(){
var factory = {
getSomeService : function(){
return new SomeService();
}
};
return factory;
}
上記の2つをコントローラーで使用します。
var factoryOne = NameOfTheFactoryOne() //since it returns a function
factoryOne.someMethod();
var factoryTwo = NameOfTheFactoryTwo.getSomeService(); //accessing the object
factoryTwo.someMethod();
工場の特徴:
.service()
メソッドはfactoryで、常に同じタイプのサービスを生成します。これはシングルトンであり、その動作を設定する簡単な方法はありません。その.service()
メソッドは通常、設定を一切必要としないものへのショートカットとして使用されます。PROVIDER
もう一度構文を見てみましょう。
angular.module('ProviderModule', [])
.controller('ProviderModuleController', ProviderModuleController)
.provider('ServiceProvider', ServiceProvider)
.config(Config); //optional
Config.$inject = ['ServiceProvider'];
function Config(ServiceProvider) {
ServiceProvider.defaults.maxItems = 10; //some default value
}
ProviderModuleController.$inject = ['ServiceProvider'];
function ProviderModuleController(ServiceProvider) {
//some methods
}
function ServiceProvider() {
var provider = this;
provider.defaults = {
maxItems: 10
};
provider.$get = function () {
var someList = new someListService(provider.defaults.maxItems);
return someList;
};
}
}
プロバイダの機能:
.service
または.factory
メソッドを使ってサービスを設定するときに、プロバイダーメソッドが舞台裏で実行されるものであると述べられています。$get
は、プロバイダインスタンスに直接関連付けられている関数です。その関数はfactory関数です。言い換えれば、それは私たちが.factory
メソッドに provide を提供するのに使っているものとちょうど同じです。その機能の中で、私たちは私たち自身のサービスを作り出します。 この$get
プロパティは関数で、プロバイダをプロバイダにするものです _。 AngularJSは、プロバイダが$ getプロパティを持ち、その値がAngularがファクトリ関数として扱う関数であることを期待しています。 しかし、このプロバイダ全体の設定を非常に特別なものにしているのは、サービスプロバイダの内部に何らかのconfig
オブジェクトを提供できるという事実と、通常は後でアプリケーション全体を設定できるステップで上書きできるデフォルトが付属するということです。 Factory: あなたが実際にファクトリの中にオブジェクトを作成してそれを返すファクトリ。
service: thisキーワードを使用して機能を定義する標準機能のみを使用するサービス。
provider: あなたが定義する$ getプロバイダがあり、それを使ってデータを返すオブジェクトを取得することができます。
基本的に、プロバイダ、ファクトリ、およびサービスはすべてサービスです。 Factoryは、必要なのが$ get()関数だけである場合はサービスの特殊なケースです。
サービス、工場、およびプロバイダーの主な違いはそれらの複雑さです。サービスは最も単純な形式であり、ファクトリはもう少し堅牢であり、そしてプロバイダは実行時に設定可能です。
それぞれを使用する場合の概要は次のとおりです。
工場 :あなたが提供している価値は他のデータに基づいて計算される必要があります。
Service :あなたはメソッドでオブジェクトを返しています。
プロバイダ :あなたは、それが作成される前に作成される予定のオブジェクトを、設定段階で設定できるようにしたいのです。アプリが完全に初期化される前に、主にアプリの設定でプロバイダを使用します。
1.Servicesはシングルトンオブジェクトで、必要に応じて作成され、アプリケーションのライフサイクルが終了するまで(ブラウザが閉じられるまで)クリーンアップされません。コントローラは不要になると破壊されてクリーンアップされます。
2.サービスを作成する最も簡単な方法は、factory()メソッドを使用することです。 factory()メソッドを使用すると、サービス関数とサービスデータを含むオブジェクトを返すことによってサービスを定義できます。サービス定義関数は、$ httpや$ qなど、注入可能なサービスを配置する場所です。例:
angular.module('myApp.services')
.factory('User', function($http) { // injectables go here
var backendUrl = "http://localhost:3000"; var service = {
// our factory definition
user: {},
setName: function(newName) {
service.user['name'] = newName;
},
setEmail: function(newEmail) { service.user['email'] = newEmail;
},
save: function() {
return $http.post(backendUrl + '/users', { user: service.user
}); }
};
return service; });
我々のアプリでfactory()を使う
実行時に必要な場所にファクトリを注入するだけなので、ファクトリをアプリケーションで使用するのは簡単です。
angular.module('myApp')
.controller('MainController', function($scope, User) {
$scope.saveUser = User.save;
});