AngularJS नियंत्रकों का विस्तार करने के लिए अनुशंसित तरीका क्या है?


193

मेरे पास तीन नियंत्रक हैं जो काफी समान हैं। मैं एक नियंत्रक चाहता हूं जो ये तीनों अपने कार्यों को बढ़ाते हैं और साझा करते हैं।

जवाबों:


302

शायद आप किसी नियंत्रक का विस्तार नहीं करते हैं, लेकिन नियंत्रक का विस्तार करना या एकल नियंत्रक को कई नियंत्रकों का मिश्रण बनाना संभव है।

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.
}]);

जब मूल नियंत्रक बनाया जाता है तो उसके भीतर निहित तर्क भी निष्पादित हो जाता है। $ नियंत्रक देखें () के बारे में अधिक जानकारी के लिए लेकिन केवल$scope मूल्य को पारित करने की आवश्यकता है। अन्य सभी मूल्यों को सामान्य रूप से इंजेक्ट किया जाएगा।

@mwarren , Angular निर्भरता इंजेक्शन द्वारा आपकी चिंता को ऑटो-जादुई रूप से ध्यान रखा जाता है। आप सभी की जरूरत है $ गुंजाइश इंजेक्षन करने के लिए है, हालांकि आप अन्य इंजेक्शन मूल्यों को ओवरराइड कर सकते हैं यदि वांछित। निम्नलिखित उदाहरण लें:

(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>

हालांकि 'डॉक्यूमेंटकंट्रोलर' द्वारा बनाए जाने पर $ डॉक्यूमेंट 'simpleController' में पारित नहीं होता है, लेकिन $ डॉक्यूमेंट हमारे लिए इंजेक्ट किया जाता है।


1
इसके लिए अब तक का सबसे तेज, सबसे साफ और सबसे आसान उपाय! धन्यवाद!
एमके

सही, भयानक समाधान!
कामिल लाच

8
मुझे लगता है कि आपको इसकी आवश्यकता नहीं है $.extend(), आप बस कॉल कर सकते हैं$controller('CtrlImpl', {$scope: $scope});
टॉमहार्टल

5
@tomraithel का उपयोग नहीं angular.extend(या $.extend) वास्तव में $scopeकेवल विस्तार करने का मतलब है , लेकिन यदि आपका आधार नियंत्रक कुछ गुणों (जैसे this.myVar=5) को भी परिभाषित करता है , तो आपके पास केवल उपयोग this.myVarमें आने वाले नियंत्रक तक पहुंच हैangular.extend
schellmax

1
यह भी खूब रही! : बस सुनिश्चित करें कि सभी आवश्यक कार्यों का विस्तार करने के याद करने के लिए करते हैं, यानी मैं की तरह कुछ था handleSubmitClickजो कहेंगे handleLoginजो बारी में था एक loginSuccessऔर loginFail। तो, मेरी विस्तारित नियंत्रक में मैं तो ओवरलोड था handleSubmitClick, handleLoginहै, और loginSucessसही के लिए loginSuccessसमारोह में इस्तेमाल किया जा करने के लिए।
जस्टिन क्रूस

52

उत्तराधिकार के लिए आप मानक जावास्क्रिप्ट वंशानुक्रम पैटर्न का उपयोग कर सकते हैं। यहाँ एक डेमो है जो उपयोग करता है$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);

यदि आप controllerAsसिंटैक्स का उपयोग करते हैं (जो मैं अत्यधिक अनुशंसा करता हूं), तो शास्त्रीय वंशानुक्रम पैटर्न का उपयोग करना और भी आसान है:

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);

एक और तरीका सिर्फ "एब्सट्रैक्ट" कंस्ट्रक्टर फंक्शन बनाना हो सकता है जो आपका बेस कंट्रोलर होगा:

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

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

इस विषय पर ब्लॉग पोस्ट


16

ठीक है, मैं बिल्कुल निश्चित नहीं हूं कि आप क्या हासिल करना चाहते हैं, लेकिन आमतौर पर सेवाएं जाने का रास्ता हैं। आप नियंत्रकों के बीच कोड साझा करने के लिए कोणीय की स्कोप इनहेरिटेंस विशेषताओं का भी उपयोग कर सकते हैं:

<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
}

नियंत्रकों में समान चर और फ़ंक्शन साझा करें जो समान चीजें करते हैं (एक संपादन के लिए है, दूसरा निर्माण आदि ...)। यह निश्चित रूप से एक समाधान है ...
vladexologija

1
$ गुंजाइश वंशानुक्रम इसे करने का सबसे अच्छा तरीका है, स्वीकृत उत्तर की तुलना में बहुत बेहतर है।
स्नेज

अंत में यह जाने का सबसे कोणीय तरीका लग रहा था। मेरे पास तीन अलग-अलग पन्नों पर तीन बहुत ही संक्षिप्त पैरेंटकंट्रोलर हैं जो सिर्फ एक $ गुंजाइश मूल्य निर्धारित करते हैं जो चाइल्डकंट्रोलर उठा सकता है। चाइल्डकंट्रोलर, जिसे मैंने मूल रूप से विस्तारित करने के बारे में सोचा था, इसमें सभी नियंत्रक तर्क शामिल हैं।
मेवर्रेन

यह करने के $scope.$parent.fx( ) लिए एक बहुत क्लीनर तरीका नहीं होगा, क्योंकि यह वह जगह है जहां यह वास्तव में परिभाषित किया गया है?
आकाश

15

आप नियंत्रकों का विस्तार नहीं करते हैं। यदि वे एक ही मूल कार्य करते हैं तो उन कार्यों को एक सेवा में ले जाने की आवश्यकता होती है। उस सेवा को आपके नियंत्रकों में इंजेक्ट किया जा सकता है।


3
धन्यवाद, लेकिन मेरे 4 कार्य हैं जो पहले से ही सेवाओं का उपयोग करते हैं (सहेजें, हटाएं, आदि ..) और सभी तीन नियंत्रकों में मौजूद हैं। यदि विस्तार करना एक विकल्प नहीं है, तो क्या 'मिक्सिन' के लिए कोई संभावना है?
vladexologija

4
@vladexologija मैं यहां बार्ट से सहमत हूं। मुझे लगता है कि सेवाएं मिक्सी की हैं। आपको नियंत्रक से जितना संभव हो उतना तर्क को स्थानांतरित करने का प्रयास करना चाहिए (सेवाओं में)। इसलिए यदि आपके पास 3 कंट्रोलर हैं जो कि सिमिलेटेड कार्यों को करने की आवश्यकता है, तो एक सेवा लेने के लिए सही तरीका है। नितंबों का विस्तार करना कोणीय में स्वाभाविक लगता है।
गणराज

6
@vladexologija यहाँ मेरा क्या मतलब है इसका एक उदाहरण है: jsfiddle.net/ERGU3 यह बहुत बुनियादी है लेकिन आपको यह विचार मिलेगा।
बार्ट

3
बिना किसी तर्क और आगे की व्याख्या के जवाब बहुत ही बेकार है। मुझे भी लगता है कि आपको ओपी की बात याद आती है। पहले से ही एक साझा सेवा है। केवल एक चीज जो आप करते हैं वह सीधे उस सेवा को उजागर करना है। मुझे नहीं पता कि यह एक अच्छा विचार है। यदि स्कोप की आवश्यकता है तो आपका दृष्टिकोण भी विफल हो जाता है। लेकिन आपके तर्क के बाद, मैं स्पष्ट रूप से इस दायरे को देखने की गुंजाइश की संपत्ति के रूप में उजागर करूंगा ताकि इसे एक तर्क के रूप में पारित किया जा सके।
एक बेहतर जैतून

6
एक क्लासिक उदाहरण तब होगा जब आपकी साइट पर दो फॉर्म-संचालित रिपोर्टें होंगी, जिनमें से प्रत्येक एक ही डेटा के बहुत सारे पर निर्भर करती है, और जिनमें से प्रत्येक बहुत सी साझा सेवाओं का उपयोग करती है। आप सैद्धांतिक रूप से दर्जनों AJAX कॉल के साथ अपनी सभी अलग-अलग सेवाओं को एक बड़ी सेवा में डाल सकते हैं, और फिर 'getEverythingINeedForReport1' और 'getEverythingINeedForReport2' जैसे सार्वजनिक तरीके रख सकते हैं, और यह सब एक विशाल दायरे की वस्तु पर सेट कर सकते हैं, लेकिन फिर आप वास्तव में आपकी सेवा में अनिवार्य रूप से नियंत्रक तर्क है। नियंत्रकों का विस्तार बिल्कुल कुछ परिस्थितियों में उपयोग का मामला है।
टोबेलारोनी 20

10

इस लेख से लिया गया एक और अच्छा समाधान :

// 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;
    });
}]);

1
इसने मेरे लिए बहुत अच्छा काम किया। यह उस स्थिति से आसान रीफ़ैक्टरिंग का लाभ है जहां आपने एक नियंत्रक के साथ शुरू किया था, एक और बहुत समान बनाया, और फिर कोड ड्रायर बनाना चाहता था। आपको कोड बदलने की आवश्यकता नहीं है, बस इसे बाहर निकालें और किया जाए।
एली अल्बर्ट

7

आप एक सेवा बना सकते हैं और किसी भी नियंत्रक में बस उसे इंजेक्ट करके उसके व्यवहार को विरासत में ले सकते हैं।

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

    var reusableCode = {};

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

    return reusableCode;
});

फिर अपने नियंत्रक में जिसे आप उपरोक्त पुन: प्रयोज्यकोड सेवा से विस्तारित करना चाहते हैं:

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

    angular.extend($scope, reusableCode);

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

});

डेमो प्लानर: http://plnkr.co/edit/EQtj6I0X08xprE8D0n5b?p=preview


5

आप कुछ इस तरह की कोशिश कर सकते हैं (परीक्षण नहीं किया गया है):

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

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

}));

1
हाँ। विस्तार करने की आवश्यकता नहीं है, बस संदर्भ के साथ आह्वान करें
टेलरमैक

4

आप सेवाओं , कारखानों या प्रदाताओं के साथ विस्तार कर सकते हैं । वे समान हैं लेकिन लचीलेपन के विभिन्न डिग्री के साथ।

यहाँ कारखाने का उपयोग कर एक उदाहरण है: 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
});

और यहाँ आप स्टोर फ़ंक्शन का उपयोग कर सकते हैं:

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

4

आप सीधे $ नियंत्रक ('पेरेंटकंट्रोलर', {$ गुंजाइश: $ गुंजाइश}) उदाहरण का उपयोग कर सकते हैं

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

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


1

मैंने ऐसा करने के लिए एक फ़ंक्शन लिखा:

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

आप इसे इस तरह से उपयोग कर सकते हैं:

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.
            }]
        )
    );
}();

पेशेवरों:

  1. आपको आधार नियंत्रक को पंजीकृत करने की आवश्यकता नहीं है।
  2. किसी भी नियंत्रक को $ नियंत्रक या $ इंजेक्टर सेवाओं के बारे में जानने की आवश्यकता नहीं है।
  3. यह कोणीय के सरणी इंजेक्शन सिंटैक्स के साथ अच्छी तरह से काम करता है - जो जरूरी है अगर आपकी जावास्क्रिप्ट को छोटा किया जा रहा है।
  4. आप बेस कंट्रोलर में आसानी से अतिरिक्त इंजेक्टेबल सेवाएं जोड़ सकते हैं, बिना उन्हें याद करने के लिए भी, और उन्हें अपने सभी चाइल्ड कंट्रोलर से पास कर सकते हैं।

विपक्ष:

  1. आधार नियंत्रक को एक चर के रूप में परिभाषित किया जाना है, जो वैश्विक दायरे को प्रदूषित करने का जोखिम रखता है। मैंने अपने उपयोग के उदाहरण में इसे एक अनाम स्व-निष्पादित फ़ंक्शन में सब कुछ लपेटकर टाला है, लेकिन इसका मतलब यह है कि सभी बाल नियंत्रकों को एक ही फ़ाइल में घोषित किया जाना है।
  2. यह पैटर्न उन नियंत्रकों के लिए अच्छी तरह से काम करता है, जो सीधे आपके html से त्वरित होते हैं, लेकिन नियंत्रकों के लिए इतना अच्छा नहीं है कि आप अपने कोड से $ नियंत्रक () सेवा के माध्यम से बनाएं, क्योंकि यह इंजेक्टर पर निर्भरता आपको अतिरिक्त, गैर इंजेक्शन लगाने से सीधे रोकती है अपने कॉलिंग कोड से -service पैरामीटर।

1

मैं मौजूदा नियंत्रकों को बुरा व्यवहार मानता हूं। बल्कि अपने साझा तर्क को एक सेवा में लगाएं। जावास्क्रिप्ट में विस्तारित वस्तुएं बल्कि जटिल होती हैं। यदि आप विरासत का उपयोग करना चाहते हैं, तो मैं टाइपस्क्रिप्ट की सिफारिश करूंगा। फिर भी, मेरे दृष्टिकोण में जाने के लिए पतले नियंत्रक बेहतर हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.