AngularJS: Warum nicht Logik in den Controller schreiben?

8

Verzeiht mir, wenn das dumm klingt, aber ich benutze AngularJS schon seit einer Weile und überall habe ich Leute gesehen, die mir sagen, dass ich meine Logik in eine Direktive (oder Dienst?) statt in meinen Controller einfügen soll und behalte nur die Bindungen in meinem Controller. Abgesehen vom Wiederverwendbarkeitsaspekt einer Richtlinie gibt es einen anderen Grund?

Bis jetzt habe ich nicht wirklich verstanden, warum das so ist. Ist das Schreiben einer Richtlinie nicht mit viel Aufwand verbunden? Ich habe keine Probleme beim Schreiben von Logik in meinem Controller und es ist einfach. Was sind die Nachteile dieses Ansatzes?

    
Tarun Dugar 16.07.2015, 12:41
quelle

4 Antworten

13

Der Controller ist der richtige Ort, um alles und jeden zu tun, der mit dem Umfang zusammenhängt. Es ist der Ort, wo Sie alle

schreiben %Vor%

und definieren Sie alle $scope -Funktionen, auf die Sie von Ihren Ansichten aus zugreifen müssen (wie Event-Handler). Im Allgemeinen ist der Event-Handler eine Plan-Funktion, die wiederum eine Funktion als Service bezeichnet.

%Vor%

In sehr seltenen Fällen können Sie dort einen Versprechens-Erfolgshandler hinzufügen.

DONT: Schreiben Sie Geschäftslogik in Controller

Es gab einen ganz bestimmten Grund, warum das frühere Beispiel so war. Es zeigte Ihnen eine Funktion $scope , die wiederum eine Funktion in einem Dienst aufruft. Der Controller ist nicht für den Login-Mechanismus oder das Login verantwortlich. Wenn Sie diesen Code in einen Dienst schreiben, entkoppeln Sie den Dienst vom Controller, dh wo auch immer Sie den gleichen Dienst verwenden möchten, müssen Sie nur die Funktion injizieren und wegschleudern.

Regeln für den zukünftigen Controller:

  • Controller sollten keine logische Null haben Controller sollten Referenzen nur an Modelle binden (und Methoden, die von Versprechungen zurückgegeben werden)
  • Controller bringen nur Logik zusammen
  • Controller steuert Modelländerungen und Änderungen anzeigen. Stichwort; Laufwerke, nicht erstellt / persistent, es löst sie aus!
  • Delegieren der Aktualisierung der Logik innerhalb von Fabriken, Auflösen von Daten in einem Controller, Aktualisieren des Werts des Controllers nur mit aktualisierter Factory-Logik. Dadurch wird wiederholter Code für Controller vermieden sowie Factory-Tests vereinfacht
  • Halten Sie die Dinge einfach, ich bevorzuge XXXXCtrl und XXXXFactory, ich weiß genau, was die beiden tun, wir brauchen keine ausgefallenen Namen für Dinge
  • Halten Sie Methoden / Prop-Namen für gemeinsame Methoden konsistent, z. B. this.something = MyFactory.something; sonst wird es verwirrend
  • Fabriken halten das Modell, ändern, erhalten, aktualisieren und behalten die Modelländerungen bei
  • Denken Sie an die Factory als ein Objekt, das Sie persistieren müssen, anstatt in einem Controller zu bestehen
  • Sprich mit anderen Fabriken in deiner Fabrik, halte sie vom Controller fern (Dinge wie Erfolg / Fehlerbehandlung)
  • Versuchen Sie zu vermeiden, $ scope in Controller zu injizieren, im Allgemeinen gibt es bessere Möglichkeiten, um das zu tun, was Sie brauchen, wie z. B. $ scope zu vermeiden. $ watch ()
ngLover 16.07.2015, 13:03
quelle
3

Es gibt zwei gute Gründe für mich, Logik aus einem Controller herauszuhalten:

Wiederverwendbarkeit

Wenn Ihre Anwendung mehrere Controller hat und jeder mit einigen Unterschieden ziemlich genau dasselbe tut, bedeutet das, dass Sie den Code, den Sie schreiben, wiederholen, wenn Sie die Logik im Controller behalten. Es ist besser, wenn Sie sich nicht wiederholen . Indem Sie diese Logik in einen Dienst einfügen, können Sie denselben Code in mehrere Controller einspeisen. Jeder Service (wirklich ein Factory ) wird jedes Mal neu erstellt, wenn er in einen Controller injiziert wird. Indem Sie Logik in einen Service pushen, können Sie Ihren Code modularisieren , was die Wartung und den Test erleichtert (siehe unten).

Testen

Guter Code wird getestet. Nicht nur von Menschen, sondern auch von Unit-Tests, die Sie schreiben. Komponententests geben Ihnen als Entwickler die Gewissheit, dass Ihr Code das tut, was Sie auch erwarten. Sie helfen Ihnen auch, Ihren Code gut zu gestalten.

Wenn Ihr Controller über 20 verschiedene Methoden mit jeweils eigener Logik verfügt, werden Tests (und Ihr Code) zu Spaghetti.

Es ist einfacher, Einheitentests zu schreiben, die eng sind, d. h. sie testen eine Sache nach der anderen. Und glücklicherweise ist es auch gut (aus den oben genannten Gründen), Ihren Code in gekapselte Teile aufzuteilen, d. H., Sie machen eine Sache und können dies isoliert tun. Unit-Tests (vor allem, wenn Sie Ihre Tests zuerst schreiben) zwingen Sie dazu, darüber nachzudenken, wie Sie Ihren Code in wartbare Teile aufteilen können, was Ihre Anwendung in einem guten Zustand lässt, wenn Sie in Zukunft Änderungen vornehmen wollen (Sie führen die Komponententests durch) und kann sehen, wo etwas kaputt ist).

Beispiel

Formularanwendung:

Sie haben eine Formularanwendung, die mehrere Formulare unterstützt. Sie haben einen Controller für jedes Formular. Wenn der Benutzer das Formular abschickt, werden die Daten über einen Proxy an ein CRM gesendet, das die Informationen in einer Datenbank speichert.

Wenn ein Kunde bereits im CRM vorhanden ist, möchten Sie keine Duplikate erstellen (ja, das CRM sollte die Daten bereinigen, aber Sie wollen das wo möglich vermeiden). Sobald der Benutzer seine Formulardaten übermittelt, muss also eine Logik implementiert werden, die etwa lautet:

  • sucht den Benutzer im CRM über einen API-Endpunkt
  • Wenn der Benutzer vorhanden ist, rufen Sie die Benutzer-ID ab und übergeben Sie sie mit den Formulardaten an einen anderen Endpunkt
  • Wenn sie nicht vorhanden sind, treffen Sie einen anderen Endpunkt und erstellen Sie einen neuen Benutzer, holen Sie sich die Benutzer-ID und senden Sie sie und die Formulardaten, um sie dem Benutzer zuzuordnen

NB: Wahrscheinlich sollte das Ganze von einem Back-End-Service gemacht werden, aber um es exemplarisch zu sagen, lassen Sie uns damit beginnen.

Ihre Bewerbung hat mehrere Formulare. Wenn Sie für jedes Formular dieselbe Logik in jedem Controller fest codieren (ja, Sie sollten pro Formular einen Controller haben, d. H. Einen pro Ansicht), wiederholen Sie sich mehrmals. Und das Schreiben von Tests, die den Controller überprüfen müssen, kann die Grundlagen (Daten posten, Änderungen an der Ansicht verwalten), aber auch das gesamte dieser Logik für jeden Controller testen.

Oder schreiben Sie stattdessen diese Logik einmal, stecken Sie sie in einen Dienst, schreiben Sie einen Test dafür und injizieren Sie sie, wo immer Sie möchten.

Referenzen

Sehen Sie sich die eckige Dokumentation an und sehen Sie sich die Muster an, die Angular implementiert, und warum diese gut zu befolgen sind (< a href="https://en.wikipedia.org/wiki/Design_Patterns"> Design Patterns - die großen sind modular, Dependency Injection, Factory und Singleton).

    
br3w5 16.07.2015 12:59
quelle
2

Das größte Problem mit Controllern ist, dass Sie nicht den HTML-Code definieren, an dem es arbeitet.

Wenn Sie ...

verwenden %Vor%

... dann müssen Sie Ihren HTML-Code in Ihren Controller injizieren, was grundlegend altmodisch ist.

Wenn Sie ...

verwenden %Vor%

... Ihre Direktive und Ihr HTML, an dem sie arbeitet, sind an verschiedenen Stellen definiert. Auch nicht was du willst.

Die Verwendung von Direktiven zwingt Sie, Ihren HTML-Code und den Code, den Sie benötigen, an der gleichen Stelle einzufügen. Da die Richtlinie auch einen eigenen Geltungsbereich hat, werden andere Variablen in Ihrem Code nicht beeinträchtigt. Wenn Sie Variablen von anderswo brauchen, müssen Sie sie auch explizit injizieren, was auch eine gute Sache ist.

Das Wort, das ich dafür verwende, warum das eine gute Sache ist, ist "atomar", aber ich bin mir nicht sicher, ob das das richtige Wort ist. Bedeutung: alle Dinge, die zusammenarbeiten sollten, sind in einer Datei. Mit templateUrl ist das nicht mehr richtig, immer noch ist das Template in der Direktive definiert.

Also in meinen Controllern gibt es keinen Code, der irgendetwas mit dem dom macht. Nur das Nötigste wie ein Code zum Zählen von Seiten / Ansichten oder das Verbinden von API-Daten mit dem Scope oder etwas mit $ routeParam-Daten. Der gesamte andere Code wird entweder in Services / Factories (Geschäftslogik) oder Direktiven (Dom-Logik) eingegeben.

Übrigens: Es ist möglich, einen Controller für Ihre Direktive zu definieren, der normalerweise nur für die 'zwischenrichtliche Kommunikation' verwendet wird (Sie können also den Status teilen), aber Sie verwenden dies nur mit Direktiven, die immer zusammenarbeiten (wie a Tab-Direktive, die innerhalb einer Tabs-Direktive wiederholt wird.)

    
Sander_P 16.07.2015 14:34
quelle
-1

Der Hauptgrund dafür, dass Sie keine Logik in Controller schreiben, ist, dass $scopes in controller get Garbage mit $destroy() bei Routenänderungen gesammelt wird. In der Anweisung ngView , wenn eine $routeChangeSuccess broadcast empfangen wird, gibt es eine Funktion, die nur $ scope für die gerade aktive Ansicht behält, alle anderen $ scopes werden zerstört.

Wenn Sie zum Beispiel eine Einkaufswagen-App haben und Ihre Geschäftslogik der Controller ist, der $ scopes verwendet, verliert der Benutzer das Produkt und alle Formulardaten, die bereits auf der Bestellseite eingegeben wurden, wenn sie die Zurück-Schaltfläche usw. verwenden .

    
cheekybastard 09.08.2015 22:48
quelle