2013-02-23 8 views
28

Ich habe dieses HTML:AngularJS, ist diese Art der Nutzung von Service gut?

<p>Hello {{name}}</p> 

und der Controller ist:

function myCtrl(scope, service) { 
    scope.name = service.getUsername(); // service.getUsername() return "World!" 
} 
myCtrl.$inject = ['$scope', 'originalService']; 

Der Service funktioniert gut, so dass ich füge den Code nicht hier ... In diesem Fall ist das Ergebnis "! Hallo Welt" ist änderte ich den HTML auf diese Weise:

<p>Hello {{service.getUsername()}}</p> 

Aber das geht nicht.

änderte ich den Controller:

function myCtrl(scope, service) { 
    scope.ser = service; 
} 
myCtrl.$inject = ['$scope', 'originalService']; 

und dann die HTML-

<p>Hello {{ser.getUsername();}}</p> 

Das funktioniert!

Also meine Frage ist:

Ist dies der einzige Weg, um die Funktionen eines Dienstes direkt im HTML zu verwenden, oder ich bin etwas fehlt?

Antwort

61

AngularJS-Vorlagen können nur Funktionen aufrufen, die für einen Bereich verfügbar sind. Also, egal welchen Ansatz Sie verwenden, müssen Sie Ihre Funktion auf einem Zielfernrohr haben.

Wenn Sie Ihre Service-Funktionen wollen direkt aus einer Vorlage aufrufbaren werden Sie mehrere Möglichkeiten haben:

Die Sie versucht haben - das heißt, entlarven den gesamten Dienst auf einem Umfang:

$scope.service = service; 

und dann in einer Vorlage:

<p>Hello {{service.getUsername();}}</p> 

Das i s Einzeiler in einem Controller und stellt alle Service-Methoden auf einem Scope und damit auf Vorlagen zur Verfügung.

Methoden Expose eins nach dem anderen

über eine präzise Kontrolle zu haben, was ausgesetzt wird:

$scope.getUsername = service.getUsername; 

und dann in einer Vorlage:

<p>Hello {{getUsername();}}</p> 

Dies erfordert mehr Arbeit Methoden zu belichten, gibt Ihnen aber eine fein abgestimmte Kontrolle darüber, was belichtet wird.

Expose proxing Methoden:

$scope.getMyUsername = function() { 
    //pre/post processing if needed 
    return service.getUsername(); 
}; 

Sie eine dieser Methoden, um sie oder mischen und kombinieren, aber am Ende des Tages eine Funktion muss am Ende auf einem Umfang entweder verwenden können (direkt oder durch ein anderes Objekt, das auf einem Scope angezeigt wird).

+4

Gute Antwort. Ich würde vermeiden, das gesamte Service-Objekt dem Bereich hinzuzufügen, wenn es keine Art von View-Service ist und Ihre Vorlage die gesamte Funktionalität des Service benötigt. Im Allgemeinen möchten Sie nur die Daten/Funktionen auf dem Bereich hinzufügen, den Ihre Vorlage benötigt, und nicht mehr. –

+0

@AndersEkdahl Ich stimme zu, wahrscheinlich wollen Sie diese Methode nicht sehr oft verwenden. Aber ich denke, alles hängt vom Service ab. Ich stelle hier nur Optionen vor, es gibt verschiedene Kompromisse, die berücksichtigt werden müssen. –

+0

@ pkozlowski.opensource danke für die Antwort – Bruno

1

Eine weitere Möglichkeit, Ihren Dienst in Ihrem $ scope verfügbar zu machen, wäre das Hinzufügen eines Funktionszeigers zu Ihrer Servicemethode/Ihrem Datenobjekt.

scope.serviceData = service.data; 
// Or 
scope.getServiceData = service.getData; 

In Ihrer Ansicht können Sie sie dann mit Klammern aufrufen.

<input ng-model="serviceData().key" /> 
// Or 
<input ng-model="getServiceData().key" /> 
// Or 
{{getServiceData().key}} 

Ich persönlich mag diesen Ansatz und ich verwende es zur Zeit um mehrere Ansichten synchron mit den gleichen Daten zu halten. Es bringt jedoch einige Probleme, wie hier erklärt: AngularJS. Best practice concerning proper two way data binding from a service

Wie zu viele Daten ausgesetzt bin ich derzeit versuchen, etwas wie das zu tun.

// Within your view. 
{{getServiceDataByKey('key')}} 

// In your controller. 
scope.getServiceDataByKey = service.getServiceDataByKey; 

// In your service. 
getServiceDataByKey : function (key) { 
    return dataObject[key]; 
} 

Der Grund, warum ich das tue, ist, dass wir die Controller so sauber wie möglich halten wollen und an einem zentralen Ort alle Daten haben. Außerdem sollten die meisten Daten innerhalb des Dienstes offengelegt werden.

13

Ein anderer Weg, es zu tun:

Expose den Dienst auf $ rootScope:

$rootScope.service = service; 

und dann in einer Vorlage:

<p>Hello {{service.getUsername();}}</p> 

Sie kann dies auf tun app.run, und Sie erhalten den Service in allen Ansichten Ihrer App. Sie können diese Methode für Authentifizierungsdienste verwenden.

+7

Das ist schmutzig. Ich liebe es ! –

+0

Denken Sie daran, Tests wie diese werden interessant sein ... –