341 Stimmen

Wohin mit den Modelldaten und dem Verhalten? [tl; dr; Use Services]

Ich arbeite mit AngularJS für mein neuestes Projekt. In der Dokumentation und Tutorials werden alle Modelldaten in den Controller-Bereich gesetzt. Ich verstehe, dass es dort sein muss, um für den Controller und damit innerhalb der entsprechenden Ansichten verfügbar zu sein.

Ich glaube aber nicht, dass das Modell dort tatsächlich umgesetzt werden sollte. Es könnte komplex sein und zum Beispiel private Attribute haben. Außerdem könnte man es in einem anderen Kontext/App wiederverwenden wollen. Wenn man alles in den Controller packt, bricht das MVC-Muster völlig.

Das Gleiche gilt für das Verhalten eines jeden Modells. Wenn ich verwenden würde DCI-Architektur und das Verhalten vom Datenmodell zu trennen, müsste ich zusätzliche Objekte einführen, um das Verhalten zu speichern. Dies würde durch die Einführung von Rollen und Kontexten geschehen.

DCI == D ata C ollaboration I nteraktion

Natürlich könnten die Modelldaten und das Verhalten mit einfachen Javascript-Objekten oder einem beliebigen "Klassen"-Muster implementiert werden. Aber was wäre der AngularJS Weg, es zu tun? Mit Diensten?

Es läuft also auf diese Frage hinaus:

Wie implementiert man Modelle, die vom Controller entkoppelt sind, gemäß den Best Practices von AngularJS?

5voto

TGH Punkte 37777

Eine ältere Frage, aber ich denke, das Thema ist aktueller denn je angesichts der neuen Richtung von Angular 2.0. Ich würde sagen, eine Best Practice ist es, Code mit so wenig Abhängigkeiten von einem bestimmten Framework wie möglich zu schreiben. Verwenden Sie die Framework-spezifischen Teile nur dort, wo sie einen direkten Mehrwert bieten.

Derzeit sieht es so aus, als ob der Angular-Dienst eines der wenigen Konzepte ist, die es in die nächste Generation von Angular schaffen werden, also ist es wahrscheinlich klug, der allgemeinen Richtlinie zu folgen, alle Logik in Dienste zu verlagern. Ich würde jedoch argumentieren, dass man entkoppelte Modelle auch ohne direkte Abhängigkeit von Angular-Diensten erstellen kann. Die Erstellung eigenständiger Objekte mit nur den notwendigen Abhängigkeiten und Verantwortlichkeiten ist wahrscheinlich der richtige Weg. Es macht auch das Leben viel einfacher, wenn man automatisierte Tests durchführt. Einzelne Verantwortlichkeiten sind heutzutage ein großes Thema, aber es macht sehr viel Sinn!

Hier ist ein Beispiel für ein Muster, das ich für gut halte, um das Objektmodell vom Dom zu entkoppeln.

http://www.syntaxsuccess.com/viewarticle/548ebac8ecdac75c8a09d58e

Ein wichtiges Ziel ist es, Ihren Code so zu strukturieren, dass er von einem Unit-Test aus ebenso einfach zu verwenden ist wie von einer Ansicht aus. Wenn Sie das erreichen, sind Sie gut aufgestellt, um realistische und nützliche Tests zu schreiben.

4voto

Ich habe versucht, genau dieses Problem zu lösen in dieser Blogbeitrag .

Grundsätzlich ist das beste Zuhause für die Datenmodellierung in Diensten und Fabriken. Je nachdem, wie Sie Ihre Daten abrufen und wie komplex das benötigte Verhalten ist, gibt es jedoch viele verschiedene Möglichkeiten, die Implementierung vorzunehmen. Angular hat derzeit keine Standard Weg oder die beste Praxis.

In diesem Beitrag werden drei Ansätze behandelt, und zwar $http , $Ressource y Restangular .

Hier ist ein Beispielcode für beide, mit einer benutzerdefinierten getResult() Methode für das Modell Job:

Restangular (kinderleicht):

angular.module('job.models', [])
  .service('Job', ['Restangular', function(Restangular) {
    var Job = Restangular.service('jobs');

    Restangular.extendModel('jobs', function(model) {
      model.getResult = function() {
        if (this.status == 'complete') {
          if (this.passed === null) return "Finished";
          else if (this.passed === true) return "Pass";
          else if (this.passed === false) return "Fail";
        }
        else return "Running";
      };

      return model;
    });

    return Job;
  }]);

$resource (etwas umständlicher):

angular.module('job.models', [])
    .factory('Job', ['$resource', function($resource) {
        var Job = $resource('/api/jobs/:jobId', { full: 'true', jobId: '@id' }, {
            query: {
                method: 'GET',
                isArray: false,
                transformResponse: function(data, header) {
                    var wrapped = angular.fromJson(data);
                    angular.forEach(wrapped.items, function(item, idx) {
                        wrapped.items[idx] = new Job(item);
                    });
                    return wrapped;
                }
            }
        });

        Job.prototype.getResult = function() {
            if (this.status == 'complete') {
                if (this.passed === null) return "Finished";
                else if (this.passed === true) return "Pass";
                else if (this.passed === false) return "Fail";
            }
            else return "Running";
        };

        return Job;
    }]);

$http (hardcore):

angular.module('job.models', [])
    .service('JobManager', ['$http', 'Job', function($http, Job) {
        return {
            getAll: function(limit) {
                var params = {"limit": limit, "full": 'true'};
                return $http.get('/api/jobs', {params: params})
                  .then(function(response) {
                    var data = response.data;
                    var jobs = [];
                    for (var i = 0; i < data.objects.length; i ++) {
                        jobs.push(new Job(data.objects[i]));
                    }
                    return jobs;
                });
            }
        };
    }])
    .factory('Job', function() {
        function Job(data) {
            for (attr in data) {
                if (data.hasOwnProperty(attr))
                    this[attr] = data[attr];
            }
        }

        Job.prototype.getResult = function() {
            if (this.status == 'complete') {
                if (this.passed === null) return "Finished";
                else if (this.passed === true) return "Pass";
                else if (this.passed === false) return "Fail";
            }
            else return "Running";
        };

        return Job;
    });

Der Blogbeitrag selbst geht näher auf die Gründe für die Verwendung der einzelnen Ansätze ein und enthält Codebeispiele für die Verwendung der Modelle in Ihren Controllern:

AngularJS Datenmodelle: $http VS $resource VS Restangular

Es besteht die Möglichkeit, dass Angular 2.0 eine robustere Lösung für die Datenmodellierung bietet, die alle Beteiligten auf dieselbe Seite bringt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X