मैं अपने AngularJS एप्लिकेशन में कुछ छोटे उपयोगिता कार्य कैसे जोड़ सकता हूं?


146

मैं अपने AngularJS एप्लिकेशन में कुछ उपयोगिता फ़ंक्शंस जोड़ना चाहूंगा। उदाहरण के लिए:

$scope.isNotString = function (str) {
    return (typeof str !== "string");
}

क्या उन्हें सेवा के रूप में जोड़ने का सबसे अच्छा तरीका यह है? मैंने जो पढ़ा है, उससे मैं ऐसा कर सकता हूं, लेकिन फिर मैं अपने HTML पृष्ठों में इनका उपयोग करना चाहूंगा, क्या यह तब भी संभव है जब वे एक सेवा में हों? उदाहरण के लिए मैं निम्नलिखित का उपयोग कर सकता हूं:

 <button data-ng-click="doSomething()"
         data-ng-disabled="isNotString(abc)">Do Something
 </button>

क्या कोई मुझे उदाहरण दे सकता है कि मैं इन्हें कैसे जोड़ सकता हूं। क्या मुझे एक सेवा बनानी चाहिए या ऐसा करने का कोई और तरीका है। सबसे महत्वपूर्ण मैं एक फ़ाइल में इन उपयोगिता कार्यों को चाहूंगा और मुख्य सेट अप के दूसरे भाग के साथ संयुक्त नहीं हूं।

मैं समझता हूं कि कुछ समाधान हैं लेकिन उनमें से कोई भी इतना स्पष्ट नहीं है।

समाधान 1 - शहरी द्वारा प्रस्तावित

$scope.doSomething = ServiceName.functionName;

यहां समस्या यह है कि मेरे पास 20 कार्य और दस नियंत्रक हैं। अगर मैंने ऐसा किया है तो इसका मतलब होगा कि प्रत्येक नियंत्रक के लिए बहुत सारे कोड जोड़ना होगा।

समाधान 2 - मेरे द्वारा प्रस्तावित

    var factory = {

        Setup: function ($scope) {

            $scope.isNotString = function (str) {
                return (typeof str !== "string");
            }

इसका नुकसान यह है कि प्रत्येक कंट्रोलर के शुरू में मेरे पास प्रत्येक सेवा में इनमें से एक या एक से अधिक कॉल होते हैं जो $ गुंजाइश से गुजरते हैं।

समाधान 3 - शहरी द्वारा प्रस्तावित

जेनेरिक सेवा बनाने का शहरी द्वारा प्रस्तावित समाधान अच्छा लग रहा है। यहाँ मेरा मुख्य सेट अप है:

var app = angular
    .module('app', ['ngAnimate', 'ui.router', 'admin', 'home', 'questions', 'ngResource', 'LocalStorageModule'])
    .config(['$locationProvider', '$sceProvider', '$stateProvider',
        function ($locationProvider, $sceProvider, $stateProvider) {

            $sceProvider.enabled(false);
            $locationProvider.html5Mode(true);

क्या मुझे इसके लिए सामान्य सेवा को जोड़ना चाहिए और मैं इसे कैसे कर सकता हूं?


यहाँ मेरा उत्तर जाँच stackoverflow.com/a/51464584/4251431
बशीर अल MOMANI

जवाबों:


107

EDIT 7/1/15:

मैंने इस उत्तर को बहुत पहले लिखा था और थोड़ी देर के लिए कोणीय के साथ बहुत कुछ नहीं रख रहा था, लेकिन ऐसा लगता है कि यह उत्तर अभी भी अपेक्षाकृत लोकप्रिय है, इसलिए मैं इस बिंदु पर बात करना चाहता था कि @nicolas नीचे अच्छे हैं। एक के लिए, $ rootScope को इंजेक्ट करना और वहां सहायकों को संलग्न करना आपको प्रत्येक नियंत्रक के लिए उन्हें जोड़ने से रखेगा। इसके अलावा - मैं मानता हूं कि अगर आप जो जोड़ रहे हैं, उसे कोणीय सेवाओं या फ़िल्टर के रूप में सोचा जाना चाहिए, तो उन्हें उस तरीके से कोड में अपनाया जाना चाहिए।

इसके अलावा, वर्तमान संस्करण 1.4.2 के रूप में, कोणीय "प्रदाता" एपीआई को उजागर करता है, जिसे कॉन्फ़िगर ब्लॉकों में इंजेक्ट करने की अनुमति है। अधिक के लिए ये संसाधन देखें:

https://docs.angularjs.org/guide/module#module-loading-dependencies

मॉड्यूल.कॉन्फिग के अंदर मूल्य का एंगुलरजेएस निर्भरता इंजेक्शन

मुझे नहीं लगता कि मैं नीचे दिए गए वास्तविक कोड ब्लॉक को अपडेट करने जा रहा हूं, क्योंकि मैं वास्तव में इन दिनों सक्रिय रूप से एंगुलर का उपयोग नहीं कर रहा हूं और मैं वास्तव में आरामदायक महसूस किए बिना एक नए उत्तर को खतरे में नहीं डालना चाहता हूं कि यह वास्तव में नए सर्वश्रेष्ठ के अनुरूप है। कार्य करती है। अगर किसी और को यह लगता है, हर तरह से इसके लिए जाना।

EDIT 2/3/14:

इस बारे में सोचने और कुछ अन्य उत्तरों को पढ़ने के बाद, मुझे वास्तव में लगता है कि मैं @Brent Washburne और @Amogh Talpallikar द्वारा लाई गई विधि की भिन्नता को पसंद करता हूं। खासकर यदि आप उपयोगिताओं की तलाश कर रहे हैं जैसे कि NotString () या समान। यहां स्पष्ट लाभों में से एक यह है कि आप उन्हें अपने कोणीय कोड के बाहर फिर से उपयोग कर सकते हैं और आप उन्हें अपने कॉन्फ़िगरेशन फ़ंक्शन (जो आप सेवाओं के साथ नहीं कर सकते हैं) के अंदर उपयोग कर सकते हैं।

यह कहा जा रहा है, अगर आप सेवाओं को फिर से उपयोग करने के लिए एक सामान्य तरीके की तलाश कर रहे हैं, तो मुझे जो जवाब देना चाहिए, वह पुराना है।

अब मैं क्या करूंगा:

app.js:

var MyNamespace = MyNamespace || {};

 MyNamespace.helpers = {
   isNotString: function(str) {
     return (typeof str !== "string");
   }
 };

 angular.module('app', ['app.controllers', 'app.services']).                             
   config(['$routeProvider', function($routeProvider) {
     // Routing stuff here...
   }]);

controller.js:

angular.module('app.controllers', []).                                                                                                                                                                                  
  controller('firstCtrl', ['$scope', function($scope) {
    $scope.helpers = MyNamespace.helpers;
  });

फिर अपने आंशिक में आप उपयोग कर सकते हैं:

<button data-ng-click="console.log(helpers.isNotString('this is a string'))">Log String Test</button>

नीचे पुराना उत्तर:

उन्हें एक सेवा के रूप में शामिल करना सबसे अच्छा हो सकता है। यदि आप उन्हें कई नियंत्रकों में फिर से उपयोग करने जा रहे हैं, तो उनके साथ एक सेवा के रूप में आपको बार-बार कोड रखने से रोकना होगा।

यदि आप अपने html आंशिक में सेवा कार्यों का उपयोग करना चाहते हैं, तो आपको उन्हें उस नियंत्रक के दायरे में जोड़ना चाहिए:

$scope.doSomething = ServiceName.functionName;

फिर अपने आंशिक में आप उपयोग कर सकते हैं:

<button data-ng-click="doSomething()">Do Something</button>

यहाँ एक तरीका है जिससे आप यह सब व्यवस्थित कर सकते हैं और बहुत अधिक परेशानी से मुक्त हो सकते हैं:

अपने कंट्रोलर, सर्विस और राउटिंग कोड / कॉन्फिगरेशन को तीन फाइलों में अलग करें: कंट्रोलर.जेएस, सर्विसेस.जेएस और एप्स। शीर्ष परत मॉड्यूल "ऐप" है, जिसमें निर्भरता के रूप में app.controllers और app.services है। फिर app.controllers और app.services को अपनी फाइलों में मॉड्यूल के रूप में घोषित किया जा सकता है। यह संगठनात्मक संरचना केवल कोणीय बीज से ली गई है :

app.js:

 angular.module('app', ['app.controllers', 'app.services']).                             
   config(['$routeProvider', function($routeProvider) {
     // Routing stuff here...
   }]);  

services.js:

 /* Generic Services */                                                                                                                                                                                                    
 angular.module('app.services', [])                                                                                                                                                                        
   .factory("genericServices", function() {                                                                                                                                                   
     return {                                                                                                                                                                                                              
       doSomething: function() {   
         //Do something here
       },
       doSomethingElse: function() {
         //Do something else here
       }
    });

controller.js:

angular.module('app.controllers', []).                                                                                                                                                                                  
  controller('firstCtrl', ['$scope', 'genericServices', function($scope, genericServices) {
    $scope.genericServices = genericServices;
  });

फिर अपने आंशिक में आप उपयोग कर सकते हैं:

<button data-ng-click="genericServices.doSomething()">Do Something</button>
<button data-ng-click="genericServices.doSomethingElse()">Do Something Else</button>

इस तरह आप प्रत्येक कंट्रोलर में केवल एक लाइन का कोड जोड़ते हैं और उस दायरे तक पहुँच पाने के लिए किसी भी प्रकार के कार्यों को करने में सक्षम होते हैं।


मेरे पास शायद इन कार्यों में से बीस हैं और मैं उन्हें कई नियंत्रकों में उपयोग करना चाहता हूं। मैंने इस बारे में सोचा था लेकिन यह कोड के लिए इतना व्यावहारिक नहीं है, जैसे: $ गुंजाइश.doSomething = ServiceName.functionName; प्रत्येक नियंत्रक के अंदर। मैं अपने प्रश्न को थोड़ा और विवरण के साथ अपडेट करूंगा। धन्यवाद
एलन

हाँ जो समझ में आता है यदि आपको सेवाओं में प्रत्येक फ़ंक्शन के लिए एक पंक्ति जोड़ने की आवश्यकता है, लेकिन यदि आप पूरी सेवा (सभी के कार्यों के साथ) को एक पंक्ति में दायरे में जोड़ सकते हैं, तो मुझे लगता है कि यह समझ में आता है। मैं बहुत स्पष्ट नहीं हूं कि आपके द्वारा बताए गए समाधान 2 कैसे काम कर सकते हैं?
शहरी_क्रोक

1
@ डरबन_राकोन्स: मैंने भी इस तरह से शुरुआत की, लेकिन दुर्भाग्य से आप ऐसी सेवाओं को कॉन्फिगर नहीं कर सकते। मैं हेडर में टोकन जोड़ने के लिए एक इंटरसेप्टर के अंदर अपने SSL_service का उपयोग करना चाहता था, लेकिन तब मुझे एहसास हुआ कि सेवा को इनफ़िगरेशन में इंजेक्ट नहीं किया जा सकता है। केवल स्थिरांक कर सकते हैं। मुझे लगता है कि स्थिरांक में कार्यों को जोड़ना एक बेहतर दृष्टिकोण होना चाहिए।
अमोघ तलपलीकर

1
मैं सिर्फ इसलिए पूछ रहा हूं, क्योंकि मैं मुख्य रूप से JS आदमी नहीं हूं, लेकिन अपने खुद के नामस्थान का उपयोग करके एक कॉपी या एक सिंगलटन का उत्पादन करूंगा? यदि आपके पास एक टन मॉड्यूल है, तो यह एक ही सेवा की प्रतियां होने के लिए स्मृति की बर्बादी की तरह लगता है, खासकर यदि आप केवल अपने सहायक का उपयोग करना चाहते हैं।
एरिक कीटे

3
@EricKeyte नामस्थान एक वस्तु शाब्दिक है, जो कि एक प्रकार का सिंगलटन है जो जेएस में बहुत आम है। विलंबित उत्तर के लिए क्षमा करें :)
शहरी_रोकून

32

इस पुराने धागे पर आकर मैं उस पर जोर देना चाहता था

1 °) यूटिलिटी फ़ंक्शंस (।?) को मॉड्यूल.run के माध्यम से rootcope में जोड़ा जा सकता है। इस उद्देश्य के लिए एक विशेष रूट स्तर नियंत्रक को स्थापित करने की आवश्यकता नहीं है।

angular.module('myApp').run(function($rootScope){
  $rootScope.isNotString = function(str) {
   return (typeof str !== "string");
  }
});

2 °) यदि आप अपने कोड को अलग-अलग मॉड्यूल में व्यवस्थित करते हैं, तो आपको कोणीय सेवाओं या कारखाने का उपयोग करना चाहिए और फिर उन्हें रन ब्लॉक में दिए गए फ़ंक्शन में इंजेक्ट करें, निम्नानुसार:

angular.module('myApp').factory('myHelperMethods', function(){
  return {
    isNotString: function(str) {
      return (typeof str !== 'string');
    }
  }
});

angular.module('myApp').run(function($rootScope, myHelperMethods){ 
  $rootScope.helpers = myHelperMethods;
});

3 °) मेरी समझ यह है कि विचारों में, अधिकांश मामलों के लिए आपको प्रदर्शन करने के लिए इन हेल्पर फंक्शंस की आवश्यकता होती है ताकि किसी प्रकार के फॉर्मेटिंग को लागू किया जा सके। इस अंतिम मामले में आपको क्या चाहिए कोणीय का उपयोग करना है फिल्टर

और यदि आपने कोणीय सेवाओं या कारखाने में कुछ निम्न स्तर के सहायक तरीकों को संरचित किया है, तो बस उन्हें अपने फ़िल्टर कंस्ट्रक्टर के भीतर इंजेक्ट करें:

angular.module('myApp').filter('myFilter', function(myHelperMethods){ 
  return function(aString){
    if (myHelperMethods.isNotString(aString)){
      return 
    }
    else{
      // something else 
    }
  }
);

और आपके विचार में:

{{ aString | myFilter }}   

दोनों समाधान चिंता- runसमय। कॉन्फ़िगर समय के बारे में क्या? क्या हमें वहां उपयोगिताओं की आवश्यकता नहीं है?
सिरिल CHAPON

आप एक प्रदाता (सेवा का एक प्रकार) की जरूरत है कॉन्फ़िगर समय कोणीय जे एस डॉक्टर
निकोलस

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

6

क्या मैं सही ढंग से समझता हूं कि आप केवल कुछ उपयोगिता विधियों को परिभाषित करना चाहते हैं और उन्हें टेम्पलेट्स में उपलब्ध कराना चाहते हैं?

आपको उन्हें हर कंट्रोलर से नहीं जोड़ना है। बस सभी उपयोगिता विधियों के लिए एक एकल नियंत्रक निर्धारित करें और उस नियंत्रक को <html> या <body> (ngController निर्देश का उपयोग करके) संलग्न करें। कोई भी अन्य नियंत्रक जिसे आप <html> (मतलब कहीं भी, अवधि) या <शरीर> (कहीं भी लेकिन <सिर>) के तहत संलग्न करते हैं, उस $ गुंजाइश का वारिस होगा और उन तरीकों तक पहुंच होगी।


1
यह निश्चित रूप से ऐसा करने का सबसे अच्छा तरीका है। बस एक उपयोगिता नियंत्रक है और इसे पूरी परियोजना के रैपर / कंटेनर डिव में डाल दें, सभी नियंत्रक भीतर हो जाएंगे: <div class="main-container" ng-controller="UtilController as util">फिर किसी भी आंतरिक विचार में:<button ng-click="util.isNotString(abc)">
इयान जे मिलर

4

उपयोगिता कार्यों को जोड़ने का सबसे आसान तरीका उन्हें वैश्विक स्तर पर छोड़ना है:

function myUtilityFunction(x) { return "do something with "+x; }

फिर, उपयोगिता फ़ंक्शन को जोड़ने का सबसे सरल तरीका (एक नियंत्रक से) इसे $scopeइस तरह असाइन करना है :

$scope.doSomething = myUtilityFunction;

तो आप इसे इस तरह से कॉल कर सकते हैं:

{{ doSomething(x) }}

या इस तरह:

ng-click="doSomething(x)"

संपादित करें:

मूल प्रश्न यह है कि उपयोगिता फ़ंक्शन को जोड़ने का सबसे अच्छा तरीका एक सेवा है। मैं कहता हूं कि, यदि फ़ंक्शन पर्याप्त सरल है (जैसे isNotString()कि ओपी द्वारा प्रदान किया गया उदाहरण)।

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

प्रलेखन केवल नियंत्रक (जैसे $scope.double) में व्यवहार को परिभाषित करने के लिए कहता है : http://docs.angularjs.org/guide/controller


एक सेवा के रूप में उपयोगिता कार्य करने से आप अपने नियंत्रकों में उन्हें चुनिंदा रूप से एक्सेस कर सकते हैं .. यदि कोई नियंत्रक उनका उपयोग नहीं करता है, तो सेवा त्वरित नहीं होगी।
स्टू

मैं वास्तव में आपके दृष्टिकोण को पसंद करता हूं और इसे अपने संपादित उत्तर में शामिल करता हूं। मुझे लगता है कि वैश्विक कार्य (और नेमस्पेस प्रदूषण) के कारण किसी ने आपको नीचा दिखाया होगा, लेकिन मुझे लगता है कि आपके द्वारा लिखे गए दृष्टिकोण के समान एक दृष्टिकोण को शामिल करने की संभावना होगी यदि आपने सोचा कि बहुत हाथ से पकड़ना आवश्यक था ।
शहरी_क्रेकस

व्यक्तिगत रूप से, मैं सामान्य, छोटे, उपयोगिता कार्यों को वैश्विक बनाने में कोई समस्या नहीं देख सकता। यह आमतौर पर ऐसी चीजें होती हैं, जिनका उपयोग आप अपने कोडबेस पर करते हैं, इसलिए कोई भी उनके साथ बहुत जल्दी परिचित हो जाएगा। उन्हें भाषा के छोटे विस्तार के रूप में देखें।
१६:२६ पर कॉर्नेल मेसन

अपने संपादन में आप उल्लेख करते हैं "प्रलेखन केवल नियंत्रक में व्यवहार को परिभाषित करने के लिए कहता है (जैसे $ गुंजाइश। डबल)"। क्या आप कह रहे हैं कि प्रलेखन नियंत्रकों में उपयोगिता कार्यों को लगाने का सुझाव देता है?
२०:३५ पर losmescaleros

@losmescaleros हाँ, डॉक्युमेंटेशन डॉक्स .angularjs.org
वाशबर्न

4

यहां एक सरल, कॉम्पैक्ट और समझने में आसान विधि है जिसका मैं उपयोग करता हूं।
सबसे पहले, अपने js में एक सेवा जोड़ें।

app.factory('Helpers', [ function() {
      // Helper service body

        var o = {
        Helpers: []

        };

        // Dummy function with parameter being passed
        o.getFooBar = function(para) {

            var valueIneed = para + " " + "World!";

            return valueIneed;

          };

        // Other helper functions can be added here ...

        // And we return the helper object ...
        return o;

    }]);

फिर, अपने कंट्रोलर में, अपनी सहायक वस्तु को इंजेक्ट करें और किसी भी उपलब्ध फंक्शन का उपयोग निम्न प्रकार से करें:

app.controller('MainCtrl', [

'$scope',
'Helpers',

function($scope, Helpers){

    $scope.sayIt = Helpers.getFooBar("Hello");
    console.log($scope.sayIt);

}]);

2
यह स्पष्ट रूप से एक मुद्दा दिखाता है कि मुझे कभी-कभी कोणीय क्यों पसंद नहीं है: "एक सेवा जोड़ें" ... और फिर एक नया कारखाना () बनाने वाले कोड में। डिजाइन पैटर्न से, वे समान चीजें नहीं हैं - कारखाने का उपयोग आमतौर पर नई वस्तुओं के उत्पादन के लिए किया जाता है, और सेवा कुछ कार्यक्षमता या संसाधन के "सेवा" के लिए है। ऐसे क्षणों में मैं "डब्ल्यूटी *, कोणीय" कहना चाहता हूं।
जस्टामार्टिन

1

आप निरंतर सेवा का उपयोग इस तरह भी कर सकते हैं। निरंतर कॉल के बाहर फ़ंक्शन को परिभाषित करना इसे पुनरावर्ती होने के साथ-साथ पुन: व्यवस्थित करने की अनुमति देता है।

function doSomething( a, b ) {
    return a + b;
};

angular.module('moduleName',[])
    // Define
    .constant('$doSomething', doSomething)
    // Usage
    .controller( 'SomeController', function( $doSomething ) {
        $scope.added = $doSomething( 100, 200 );
    })
;

0

कंट्रोलर इनहेरिटेंस का उपयोग क्यों न करें, HeaderCtrl के दायरे में परिभाषित सभी विधियाँ / गुण एनजी-व्यू के अंदर कंट्रोलर में पहुँच योग्य हैं। $ गुंजाइश। ServHelper आपके सभी नियंत्रकों में सुलभ है।

    angular.module('fnetApp').controller('HeaderCtrl', function ($scope, MyHelperService) {
      $scope.servHelper = MyHelperService;
    });


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