it-swarm.com.de

Was ist die empfohlene Möglichkeit, AngularJS-Controller zu erweitern?

Ich habe drei Controller, die ziemlich ähnlich sind. Ich möchte einen Controller haben, der diese drei Funktionen erweitert und teilt.

189
vladexologija

Vielleicht Sie erweitern keinen Controller, aber es ist möglich, einen Controller zu erweitern oder einen einzelnen Controller zu einem Mix aus mehreren Controllern zu machen.

module.controller('CtrlImplAdvanced', ['$scope', '$controller', function ($scope, $controller) {
    // Initialize the super class and extend it.
    angular.extend(this, $controller('CtrlImpl', {$scope: $scope}));
    … Additional extensions to create a mixin.
}]);

Beim Erstellen des übergeordneten Controllers wird auch die darin enthaltene Logik ausgeführt. Siehe $ controller () für weitere Informationen, aber nur zum $scope Wert muss übergeben werden. Alle anderen Werte werden normal injiziert.

@ mwarren, Ihr Anliegen wird automatisch durch Angular Dependency Injection erledigt. Sie müssen lediglich $ scope injizieren, obwohl Sie die anderen injizierten Werte überschreiben könnten Wenn gewünscht, nehmen Sie das folgende Beispiel:

(function(angular) {

        var module = angular.module('stackoverflow.example',[]);

        module.controller('simpleController', function($scope, $document) {
                this.getOrigin = function() {
                        return $document[0].location.Origin;
                };
        });

        module.controller('complexController', function($scope, $controller) {
                angular.extend(this, $controller('simpleController', {$scope: $scope}));
        });

})(angular);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular.js"></script>

<div ng-app="stackoverflow.example">
    <div ng-controller="complexController as C">
        <span><b>Origin from Controller:</b> {{C.getOrigin()}}</span>
    </div>
</div>

Obwohl $ document nicht an 'simpleController' übergeben wird, wenn es von 'complexController' erstellt wird, wird $ document für uns injiziert.

300
Enzey

Für die Vererbung können Sie standardmäßige JavaScript-Vererbungsmuster verwenden. Hier ist eine Demo, die $injector

function Parent($scope) {
  $scope.name = 'Human';
  $scope.clickParent = function() {
    $scope.name = 'Clicked from base controller';
  }    
}

function Child($scope, $injector) {
  $injector.invoke(Parent, this, {$scope: $scope});
  $scope.name = 'Human Child';
  $scope.clickChild = function(){
    $scope.clickParent();
  }       
}

Child.prototype = Object.create(Parent.prototype);

Falls Sie die controllerAs -Syntax verwenden (die ich sehr empfehle), ist es noch einfacher, das klassische Vererbungsmuster zu verwenden:

function BaseCtrl() {
  this.name = 'foobar';
}
BaseCtrl.prototype.parentMethod = function () {
  //body
};

function ChildCtrl() {
  BaseCtrl.call(this);
  this.name = 'baz';
}
ChildCtrl.prototype = Object.create(BaseCtrl.prototype);
ChildCtrl.prototype.childMethod = function () {
  this.parentMethod();
  //body
};

app.controller('BaseCtrl', BaseCtrl);
app.controller('ChildCtrl', ChildCtrl);

Eine andere Möglichkeit könnte darin bestehen, nur eine "abstrakte" Konstruktorfunktion zu erstellen, die Ihr Basiscontroller sein wird:

function BaseController() {
  this.click = function () {
    //some actions here
  };
}

module.controller('ChildCtrl', ['$scope', function ($scope) {
  BaseController.call($scope);
  $scope.anotherClick = function () {
    //other actions
  };
}]);

Blogeintrag zu diesem Thema

52
Minko Gechev

Nun, ich bin mir nicht ganz sicher, was Sie erreichen wollen, aber in der Regel sind Services der richtige Weg. Sie können auch die Scope-Vererbungseigenschaften von Angular zur gemeinsamen Nutzung von Code zwischen Controllern verwenden:

<body ng-controller="ParentCtrl">
 <div ng-controller="FirstChildCtrl"></div>
 <div ng-controller="SecondChildCtrl"></div>
</body>

function ParentCtrl($scope) {
 $scope.fx = function() {
   alert("Hello World");
 });
}

function FirstChildCtrl($scope) {
  // $scope.fx() is available here
}

function SecondChildCtrl($scope) {
  // $scope.fx() is available here
}
16
Andre Goncalves

Sie erweitern keine Controller. Wenn sie dieselben Grundfunktionen ausführen, müssen diese Funktionen in einen Dienst verschoben werden. Dieser Dienst kann in Ihre Steuerungen eingespeist werden.

15
Bart

Noch eine gute Lösung aus diesem Artikel :

// base controller containing common functions for add/edit controllers
module.controller('Diary.BaseAddEditController', function ($scope, SomeService) {
    $scope.diaryEntry = {};

    $scope.saveDiaryEntry = function () {
        SomeService.SaveDiaryEntry($scope.diaryEntry);
    };

    // add any other shared functionality here.
}])

module.controller('Diary.AddDiaryController', function ($scope, $controller) {
    // instantiate base controller
    $controller('Diary.BaseAddEditController', { $scope: $scope });
}])

module.controller('Diary.EditDiaryController', function ($scope, $routeParams, DiaryService, $controller) {
    // instantiate base controller
    $controller('Diary.BaseAddEditController', { $scope: $scope });

    DiaryService.GetDiaryEntry($routeParams.id).success(function (data) {
        $scope.diaryEntry = data;
    });
}]);
10

Sie können einen Dienst erstellen und sein Verhalten in einem beliebigen Controller übernehmen, indem Sie ihn einfach einfügen.

app.service("reusableCode", function() {

    var reusableCode = {};

    reusableCode.commonMethod = function() {
        alert('Hello, World!');
    };

    return reusableCode;
});

Dann in Ihrem Controller, den Sie vom oben genannten reusableCode-Dienst erweitern möchten:

app.controller('MainCtrl', function($scope, reusableCode) {

    angular.extend($scope, reusableCode);

    // now you can access all the properties of reusableCode in this $scope
    $scope.commonMethod()

});

DEMO PLUNKER: http://plnkr.co/edit/EQtj6I0X08xprE8D0n5b?p=preview

7
Raghavendra

Sie können so etwas ausprobieren (noch nicht getestet):

function baseController(callback){
    return function($scope){
        $scope.baseMethod = function(){
            console.log('base method');
        }
        callback.apply(this, arguments);
    }
}

app.controller('childController', baseController(function(){

}));
5
karaxuna

Sie können mit einem Service , Werk oder Anbieter . Sie sind gleich, aber unterschiedlich flexibel.

hier ein Beispiel mit factory: http://jsfiddle.net/aaaflyvw/6KVtj/2/

angular.module('myApp',[])

.factory('myFactory', function() {
    var myFactory = {
        save: function () {
            // saving ...
        },
        store: function () {
            // storing ...
        }
    };
    return myFactory;
})

.controller('myController', function($scope, myFactory) {
    $scope.myFactory = myFactory;
    myFactory.save(); // here you can use the save function
});

Und hier können Sie auch die Store-Funktion nutzen:

<div ng-controller="myController">
    <input ng-blur="myFactory.store()" />
</div>
4
aaafly

Sie können direkt $ controller ('ParentController', {$ scope: $ scope}) verwenden. Beispiel

module.controller('Parent', ['$scope', function ($scope) {
    //code
}])

module.controller('CtrlImplAdvanced', ['$scope', '$controller', function ($scope, $controller) {
    //extend parent controller
    $controller('CtrlImpl', {$scope: $scope});
}]);
4
Anand Gargate

Ich habe dazu eine Funktion geschrieben:

function extendController(baseController, extension) {
    return [
        '$scope', '$injector',
        function($scope, $injector) {
            $injector.invoke(baseController, this, { $scope: $scope });
            $injector.invoke(extension, this, { $scope: $scope });
        }
    ]
}

Du kannst es so benutzen:

function() {
    var BaseController = [
        '$scope', '$http', // etc.
        function($scope, $http, // etc.
            $scope.myFunction = function() {
                //
            }

            // etc.
        }
    ];

    app.controller('myController',
        extendController(BaseController,
            ['$scope', '$filter', // etc.
            function($scope, $filter /* etc. */)
                $scope.myOtherFunction = function() {
                    //
                }

                // etc.
            }]
        )
    );
}();

Profis:

  1. Sie müssen den Basiscontroller nicht registrieren.
  2. Keiner der Controller muss über die Dienste $ controller oder $ injector Bescheid wissen.
  3. Es funktioniert gut mit der Array-Injection-Syntax von Angle. Dies ist wichtig, wenn Sie JavaScript minimieren möchten.
  4. Sie können dem Basis-Controller problemlos zusätzliche injizierbare Dienste hinzufügen , ohne dass Sie auch daran denken müssen, sie zu allen Ihren Kindern hinzuzufügen und von diesen weiterzuleiten Steuerungen.

Nachteile:

  1. Der Basiscontroller muss als Variable definiert werden, die den globalen Geltungsbereich gefährden kann. Ich habe dies in meinem Anwendungsbeispiel vermieden, indem ich alles in eine anonyme selbstausführende Funktion eingebunden habe. Dies bedeutet jedoch, dass alle untergeordneten Controller in derselben Datei deklariert werden müssen.
  2. Dieses Muster eignet sich gut für Controller, die direkt aus Ihrem HTML-Code instanziiert werden, ist jedoch nicht so gut für Controller, die Sie mit dem Dienst $ controller () aus Ihrem Code erstellen, da die Abhängigkeit vom Injektor Sie daran hindert, zusätzliche, nicht direkt zu injizieren -Dienstparameter von Ihrem Anrufcode.
1
Dan King

Sie können die Syntax Angular "as" in Kombination mit einer einfachen JavaScript-Vererbung verwenden

Weitere Details finden Sie hier http://blogs.Microsoft.co.il/oric/2015/01/01/base-controller-angularjs/

1
Ori Calvo

Ich halte die Erweiterung von Controllern für eine schlechte Praxis. Stellen Sie Ihre gemeinsame Logik lieber in einen Dienst. Erweiterte Objekte in Javascript neigen dazu, ziemlich komplex zu werden. Wenn Sie die Vererbung verwenden möchten, würde ich TypeScript empfehlen. Dennoch sind Thin-Controller aus meiner Sicht die bessere Lösung.

1
Brecht Billiet