विरासत कोड से AngularJS को कॉल करें


180

मैं HTML नियंत्रणों का निर्माण करने के लिए AngularJS का उपयोग कर रहा हूं जो एक विरासत फ्लेक्स एप्लिकेशन के साथ बातचीत करते हैं। Flex ऐप से सभी कॉलबैक DOM विंडो से जुड़े होने चाहिए।

उदाहरण के लिए (AS3 में)

ExternalInterface.call("save", data);

फोन करेगा

window.save = function(data){
    // want to update a service 
    // or dispatch an event here...
}

जेएस आकार समारोह के भीतर से मैं एक घटना है कि एक नियंत्रक सुन सकते हैं भेजना चाहते हैं। ऐसा लगता है कि एक सेवा बनाना एक रास्ता है। क्या आप AngularJS के बाहर से कोई सेवा अपडेट कर सकते हैं? क्या कोई नियंत्रक किसी सेवा की घटनाओं के लिए सुन सकता है? एक प्रयोग में (फिडेल के लिए क्लिक करें) मुझे ऐसा लगा जैसे मैं किसी सेवा तक पहुंच सकता हूं, लेकिन सेवा के डेटा को अपडेट करने से दृश्य में परिलक्षित नहीं होता है (उदाहरण में एक <option>को जोड़ा जाना चाहिए <select>)।

धन्यवाद!


1
ध्यान दें कि इंजेक्टर के ऊपर jsfiddle में ऐप का उपयोग करने वाले तत्व को लक्षित किए बिना प्राप्त किया जाता है var injector = angular.injector(['ng', 'MyApp']);। ऐसा करने से आपको एक नया संदर्भ और एक डुप्लिकेट मिलेगा myService। इसका मतलब है कि आप सेवा और मॉडल के दो उदाहरणों के साथ समाप्त हो जाएंगे और गलत स्थान पर डेटा जोड़ देंगे। आपको इसके बजाय एप्लिकेशन के भीतर एक तत्व का उपयोग करना चाहिए angular.element('#ng-app').injector(['ng', 'MyApp'])। इस बिंदु पर आप तब मॉडल परिवर्तन को लपेटने के लिए $ लागू का उपयोग कर सकते हैं।
थान गुयेन

जवाबों:


293

कोणीय के बाहर से कोणीय तक का अंतराल कोणीय अनुप्रयोग को डीबग करने या तृतीय पक्ष लाइब्रेरी के साथ एकीकृत करने के समान है।

किसी भी DOM तत्व के लिए आप यह कर सकते हैं:

  • angular.element(domElement).scope() तत्व के लिए वर्तमान गुंजाइश पाने के लिए
  • angular.element(domElement).injector() वर्तमान एप्लिकेशन इंजेक्टर पाने के लिए
  • angular.element(domElement).controller()ng-controllerउदाहरण के लिए एक पकड़ पाने के लिए।

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

ध्यान रखें कि कोणीय मॉडल या कार्यक्षेत्र पर किसी भी तरीके के बदलाव को इस तरह से लपेटने की आवश्यकता है $apply():

$scope.$apply(function(){
  // perform any model changes or method invocations here on angular app.
});

1
यह काम करता है, लेकिन मैं चाहता हूं कि मॉड्यूल से सीधे इसे प्राप्त करने के लिए कुछ गुंजाइश थी - क्या यह संभव है? वापस जाने के बाद [ng-app]रूट-नोड का चयन करने से पीछे लगता है जब मेरे पास पहले से ही मॉड्यूल का संदर्भ है ...
mindplay.dk

5
मुझे यह काम करने के लिए नहीं मिल रहा है: मैं बुला रहा हूं angular.element(document.getElementById(divName)).scope(), लेकिन मैं इसमें से किसी भी फ़ंक्शन को लागू करने में सक्षम नहीं हूं, यह सिर्फ कंसोल में "अपरिभाषित" देता है।
एमिल

1
यहां तक ​​कि मैं @Emil द्वारा ऊपर बताई गई समान समस्या का सामना कर रहा हूं, यह अपरिभाषित है। कोई मदद ?
बिबिन

5
यदि डिबग डेटा बंद है, जो उत्पादन के लिए सिफारिश है, तो तत्व ()। स्कोप () काम नहीं करेगा। क्या यह इस परिदृश्य में बेकार नहीं है? यह केवल परीक्षण / डिबगिंग के लिए होगा।
। नॉर्बर्ट

4
आप एंगुलर 1.3 में ऐसा नहीं करना चाहेंगे। कोणीय टीम ने हमें उत्पादन कोड में तत्वों पर ".scope ()" कहने का इरादा नहीं किया। यह डिबग टूल होने का मतलब था। तो, कोणीय 1.3 में शुरू करके, आप इसे बंद कर सकते हैं। कोणीय jQuery के .data फ़ंक्शन का उपयोग करते हुए तत्व को संलग्न करना बंद कर देगा। यह आपके ऐप को गति देगा। इसके अतिरिक्त, अपने स्कूप्स को jquery की कैशिंग विशेषताओं में सौंपने से मेमोरी लीक हो जाएगी। इसलिए, आपको अपने ऐप को गति देने के लिए इसे बंद करना चाहिए। कोणीय की साइट में एक उत्पादन मार्गदर्शिका है जिसे आपको अधिक जानने के लिए उपयोग करना चाहिए।
ठंढी

86

मिसको ने सही उत्तर (स्पष्ट रूप से) दिया, लेकिन हममें से कुछ लोगों को इसे सरल बनाने की आवश्यकता हो सकती है।

यदि आपको विरासत ऐप्स के भीतर से AngularJS कोड कॉल करने की बात आती है, तो AngularJS कोड को एक "माइक्रो ऐप" के रूप में देखें जो आपके लीगेसी एप्लिकेशन में संरक्षित कंटेनर के भीतर मौजूद है। आप इसे सीधे (बहुत अच्छे कारण से) कॉल नहीं कर सकते, लेकिन आप $ स्कोप ऑब्जेक्ट के माध्यम से दूरस्थ कॉल कर सकते हैं।

$ स्कोप ऑब्जेक्ट का उपयोग करने के लिए, आपको $ स्कोप का हैंडल प्राप्त करना होगा। सौभाग्य से यह करना बहुत आसान है।

आप AngularJS ऐप के $ स्कोप को संभालने के लिए अपने AngularJS "माइक्रो-ऐप" HTML के भीतर किसी भी HTML तत्व की आईडी का उपयोग कर सकते हैं।

एक उदाहरण के रूप में, मान लें कि हम अपने AngularJS नियंत्रक जैसे sayHi () और sayBye () के भीतर कुछ फ़ंक्शन कॉल करना चाहते हैं। AngularJS HTML (दृश्य) में हमारा आईडी "MySuperAwesomeApp" के साथ एक div है। आप $ गुंजाइश की संभाल पाने के लिए jQuery के साथ संयुक्त निम्न कोड का उपयोग कर सकते हैं:

var microappscope = angular.element($("#MySuperAwesomeApp")).scope();

अब आप स्कोप हैंडल के माध्यम से अपने AngularJS कोड फ़ंक्शन को कॉल कर सकते हैं:

// we are in legacy code land here...

microappscope.sayHi();

microappscope.sayBye();

चीजों को अधिक सुविधाजनक बनाने के लिए, आप किसी भी कार्य को तब तक स्कोप हैंडल को पकड़ने के लिए उपयोग कर सकते हैं जब आप इसे एक्सेस करना चाहते हैं:

function microappscope(){

    return angular.element($("#MySuperAwesomeApp")).scope();

}

आपकी कॉल तब इस तरह दिखाई देगी:

microappscope().sayHi();

microappscope().sayBye();

आप यहां एक कार्यशील उदाहरण देख सकते हैं:

http://jsfiddle.net/peterdrinnan/2nPnB/16/

मैंने इसे ओटावा एंगुलरजेएस समूह के लिए एक स्लाइड शो में भी दिखाया (बस अंतिम 2 स्लाइड्स पर जाएं)

http://www.slideshare.net/peterdrinnan/angular-for-legacyapps


4
ध्यान दें कि लिंक-केवल उत्तर हतोत्साहित किए जाते हैं, एसओ उत्तर एक समाधान के लिए खोज का अंतिम बिंदु होना चाहिए (बनाम संदर्भों का एक और ठहराव, जो समय के साथ बासी हो जाते हैं)। लिंक को संदर्भ के रूप में रखते हुए कृपया यहां एक स्टैंड-अलोन सिनोप्सिस जोड़ने पर विचार करें।
क्लेओपेट्रा

अच्छा अतिरिक्त स्पष्टीकरण। धन्यवाद।
जो

1
सुंदर व्याख्या! मुझे ऐसा करने से एक फॉर्म मान्यता को दरकिनार करने की अनुमति दी गई:<input type="button" onclick="angular.element(this).scope().edit.delete();" value="delete">
प्योरफैन

24

मुझे मिली अवधारणा का सबसे बड़ा विवरण यहाँ स्थित है: https://groups.google.com/forum/# ​​-msg / angular / kqFrwiysgpA / eB9mNbQzcHwJ

आपको क्लिक करने से बचाने के लिए:

// get Angular scope from the known DOM element
e = document.getElementById('myAngularApp');
scope = angular.element(e).scope();
// update the model with a wrap in $apply(fn) which will refresh the view for us
scope.$apply(function() {
    scope.controllerMethod(val);
}); 

14
जब एप और कंट्रोलर एक ही तत्व में सह-मौजूद होते हैं तो उपरोक्त कार्य करता है। टेम्पलेट के लिए एनजी-व्यू निर्देश का उपयोग करने वाले अधिक जटिल एप्लिकेशन के लिए, आपको दृश्य के भीतर पहला तत्व प्राप्त करना होगा, न कि संपूर्ण एप्लिकेशन का DOM तत्व। मुझे एक दस्तावेज के साथ तत्वों के चारों ओर प्रहार करना पड़ा ।getElementsByClassName ('एनजी-स्कोप'); नोड सूची हड़पने के लिए सही गुंजाइश डोम तत्व का पता लगाने के लिए।
goosemanjack

मुझे पता है कि यह वास्तव में पुराना धागा है, लेकिन मुझे लगता है कि मैं इस मुद्दे पर चल रहा हूं। क्या किसी के पास कोई कोड है जो दिखाता है कि DOM तत्व को हथियाने के लिए सूची को कैसे चलना है?
जेरीकेर

मेरे प्रश्न पर ध्यान न दें। मैं केवल डॉक्यूमेंट .getElementById ('any-Control-That-Has-An-NG-Directive') का उपयोग करके यह काम पाने में सक्षम था।
जैरीकुर

यदि आप एनजी-व्यू का उपयोग करते हैं और अपने विचारों को अपनी फाइलों में विभाजित करते हैं। आप idशीर्ष HTML तत्व में रख सकते हैं और फिर document.getElementById()उस आईडी को कर सकते हैं। यह आपको उस नियंत्रक के दायरे तक पहुंच प्रदान करता है। तरीके / गुण आदि ... बस goosemanjack की टिप्पणी पर एक ठीक बिंदु डाल।
फुटवियर्स

13

अन्य उत्तर के लिए आगे। यदि आप किसी कंट्रोलर में किसी विधि का उपयोग नहीं करना चाहते हैं, लेकिन सीधे सेवा का उपयोग करना चाहते हैं, तो आप कुछ ऐसा कर सकते हैं:

// Angular code* :
var myService = function(){
    this.my_number = 9;
}
angular.module('myApp').service('myService', myService);


// External Legacy Code:
var external_access_to_my_service = angular.element('body').injector().get('myService');
var my_number = external_access_to_my_service.my_number 

13

पिछली पोस्ट के लिए धन्यवाद, मैं एक अतुल्यकालिक घटना के साथ अपने मॉडल को अपडेट कर सकता हूं।

<div id="control-panel" ng-controller="Filters">
    <ul>
        <li ng-repeat="filter in filters">
        <button type="submit" value="" class="filter_btn">{{filter.name}}</button>
        </li>
    </ul>
</div>

मैं अपना मॉडल घोषित करता हूं

function Filters($scope) {
    $scope.filters = [];
}

और मैं अपने दायरे के बाहर से अपना मॉडल अपडेट करता हूं

ws.onmessage = function (evt) {
    dictt = JSON.parse(evt.data);
    angular.element(document.getElementById('control-panel')).scope().$apply(function(scope){
        scope.filters = dictt.filters;
    });
};

6

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

var sharedVar = {}
myModule.constant('mySharedVar', sharedVar)
mymodule.controller('MyCtrl', [ '$scope','mySharedVar', function( $scope, mySharedVar) {

var scopeToReturn = $scope;

$scope.$on('$destroy', function() {
        scopeToReturn = null;
    });

mySharedVar.accessScope = function() {
    return scopeToReturn;
}
}]);

पुन: प्रयोज्य निर्देश के रूप में सामान्यीकृत:

मैंने एक 'एक्सपोज़स्कोप' निर्देश बनाया, जो समान शैली में काम करता है लेकिन उपयोग सरल है:

<div ng-controller="myController" expose-scope="aVariableNameForThisScope">
   <span expose-scope='anotherVariableNameForTheSameScope" />
</div>

यह वैश्विक स्कोप्स ऑब्जेक्ट में वर्तमान स्कोप (जो निर्देश के लिंक फंक्शन को दिया गया है) को स्टोर करता है जो सभी स्कोप के लिए होल्डर है। निर्देश विशेषता को प्रदान किया गया मान इस वैश्विक ऑब्जेक्ट में स्कोप के गुण नाम के रूप में उपयोग किया जाता है।

डेमो यहाँ देखें । जैसा कि मैंने डेमो में दिखाया, आप jQuery इवेंट्स को ट्रिगर कर सकते हैं जब स्कोप को स्टोर किया जाता है और वैश्विक 'स्कोप्स' ऑब्जेक्ट से हटा दिया जाता है।

<script type="text/javascript" >
    $('div').on('scopeLinked', function(e, scopeName, scope, allScopes) {
      // access the scope variable or the given name or the global scopes object
    }.on('scopeDestroyed', function(e, scopeName, scope, allScopes) {
      // access the scope variable or the given name or the global scopes object
    }

</script>

ध्यान दें कि, जब वास्तविक तत्व को DOM से हटा दिया गया है, तो मैंने ('गुंजाइश पर आधारित) का परीक्षण नहीं किया है। यदि यह काम नहीं करता है, तो तत्व के बजाय दस्तावेज़ पर घटना को ट्रिगर करना मदद कर सकता है। (डेमो देखें app.js) डेमो प्लंकर में स्क्रिप्ट।


3

मुझे पता है कि यह एक पुराना सवाल है, लेकिन मैं हाल ही में ऐसा करने के विकल्पों पर विचार कर रहा था, इसलिए मैंने सोचा कि मैं अपने निष्कर्षों को यहां रखूं क्योंकि यह किसी के लिए भी उपयोगी है।

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

जो मैंने अपने मामले में उपयोग किया था, वह ब्राउज़र सुलभ ग्लोबल्स (यानी विंडो) और इवेंट हैंडलिंग का एक संयोजन है। मेरे कोड में एक स्मार्ट फॉर्म जनरेशन इंजन है जिसके लिए CMS से JSON आउटपुट की आवश्यकता होती है जो फॉर्म को initiliase करता है। यहाँ मैंने क्या किया है:

function FormSchemaService(DOM) {
    var conf = DOM.conf;

    // This event is the point of integration from Legacy Code 
    DOM.addEventListener('register-schema', function (e) {

       registerSchema(DOM.conf); 
    }, false);

    // service logic continues ....

अपेक्षित रूप से कोणीय इंजेक्टर का उपयोग करके फॉर्म स्कीमा सेवा बनाई जाती है:

angular.module('myApp.services').
service('FormSchemaService', ['$window' , FormSchemaService ])

और मेरे नियंत्रकों में: फ़ंक्शन () {'उपयोग सख्त';

angular.module('myApp').controller('MyController', MyController);

MyEncapsulatorController.$inject = ['$scope', 'FormSchemaService'];

function MyController($scope, formSchemaService) {
    // using the already configured formSchemaService
    formSchemaService.buildForm(); 

अब तक यह शुद्ध कोणीय और जावास्क्रिप्ट सेवा उन्मुख प्रोग्रामिंग है। लेकिन विरासत एकीकरण यहाँ आता है:

<script type="text/javascript">

   (function(app){
        var conf = app.conf = {
       'fields': {
          'field1: { // field configuration }
        }
     } ; 

     app.dispatchEvent(new Event('register-schema'));

 })(window);
</script>

जाहिर है कि हर दृष्टिकोण में यह गुण और कमियां हैं। इस दृष्टिकोण का लाभ और उपयोग आपके UI पर निर्भर करता है। पहले से सुझाए गए दृष्टिकोण मेरे मामले में काम नहीं करते हैं क्योंकि मेरे फॉर्म स्कीमा और विरासत कोड में कोणीय scopes का कोई नियंत्रण और ज्ञान नहीं है। इसलिए angular.element('element-X').scope(); यदि हम आसपास के स्कोप को बदलते हैं, तो संभवत: मेरे ऐप को कॉन्फ़िगर करने के आधार पर ऐप को तोड़ सकता है। लेकिन अगर आपको ऐप के बारे में पता चल गया है और वह इस पर भरोसा नहीं कर सकता है कि यह अक्सर नहीं बदल रहा है, तो जो पहले सुझाया गया है वह व्यवहार्य दृष्टिकोण है।

उम्मीद है की यह मदद करेगा। किसी भी प्रतिक्रिया का भी स्वागत है।

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