AngularJS: AngularJS द्वारा टेम्प्लेट किए जाने के बाद अतिरिक्त कोड कैसे चलाया जाए?


182

मेरे पास DOM में कोणीय टेम्प्लेट है। जब मेरे नियंत्रक को किसी सेवा से नया डेटा मिलता है, तो वह $ स्कोप में मॉडल को अपडेट करता है, और टेम्पलेट को फिर से प्रस्तुत करता है। अभी तक सभी अच्छे हैं।

मुद्दा यह है कि मुझे टेम्पलेट को फिर से प्रस्तुत करने और DOM (इस मामले में jQuery प्लगइन) के बाद कुछ अतिरिक्त काम करने की भी आवश्यकता है।

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

यहाँ एक jsFiddle मेरी समस्या है: Fiddle-AngularIssue

== अद्यतन ==

सहायक टिप्पणियों के आधार पर, मैंने तदनुसार डोम हेरफेर को संभालने के लिए एक निर्देश पर स्विच किया है, और निर्देश के अंदर एक मॉडल $ घड़ी लागू की है। हालाँकि, मैं अभी भी एक ही आधार जारी कर रहा हूँ; टेम्प्लेट को संकलित करने और DOM में डालने से पहले $ घड़ी घटना की आग के अंदर का कोड इसलिए, jquery प्लगइन हमेशा एक खाली तालिका का मूल्यांकन कर रहा है।

दिलचस्प बात यह है कि अगर मैं एसिंक्स कॉल को हटाता हूं तो पूरी चीज ठीक काम करती है, इसलिए यह सही दिशा में एक कदम है।

इन परिवर्तनों को दर्शाने के लिए यहां मेरी अपडेटेड फिडेल है: http://jsfiddle.net/uNREn/12/


यह मेरे लिए एक प्रश्न के समान लगता है। stackoverflow.com/questions/11444494/… । शायद वहाँ कुछ मदद कर सकता है।
dnc253

जवाबों:


39

यह पोस्ट पुरानी है, लेकिन मैं आपका कोड इसमें बदल देता हूं:

scope.$watch("assignments", function (value) {//I change here
  var val = value || null;            
  if (val)
    element.dataTable({"bDestroy": true});
  });
}

jsfiddle देखें ।

मुझे उम्मीद है इससे आपको मदद मिली होगी


धन्यवाद, यह बहुत उपयोगी है। यह मेरे लिए सबसे अच्छा समाधान है क्योंकि इसमें नियंत्रक से डोम हेरफेर की आवश्यकता नहीं है, और तब भी काम करेगा जब डेटा को वास्तव में अतुल्यकालिक सेवा प्रतिक्रिया से अद्यतन किया जाता है (और मुझे अपने नियंत्रक में $ evalAsync का उपयोग करने की आवश्यकता नहीं है)।
गोरबश

9
क्या इसे पदावनत किया गया है? जब मैं यह कोशिश करता हूं तो यह वास्तव में DOM के रेंडर होने से पहले कहता है। यह एक छाया डोम या कुछ पर निर्भर है?
Shayne

मैं कोणीय के लिए अपेक्षाकृत नया हूं और मैं यह नहीं देख सकता कि इस उत्तर को अपने विशिष्ट मामले के साथ कैसे लागू किया जाए। मैं विभिन्न उत्तरों को देख रहा हूं और अनुमान लगा रहा हूं, लेकिन यह काम नहीं कर रहा है। मुझे यकीन नहीं है कि 'वॉच' फंक्शन क्या देखना चाहिए। हमारे कोणीय ऐप में विभिन्न अलग-अलग निर्देश हैं, जो पृष्ठ-दर-पृष्ठ अलग-अलग होंगे, इसलिए मुझे कैसे पता चलेगा कि 'देखना' क्या है? जब पृष्ठ समाप्त हो रहा हो तो निश्चित रूप से कुछ कोड को बंद करने का एक सरल तरीका है?
मौसफेटचर

63

सबसे पहले, प्रतिपादन के साथ गड़बड़ करने का सही स्थान निर्देश हैं। मेरी सलाह यह होगी कि इस तरह के निर्देशों के द्वारा jQuery प्लगइन्स को डोम मैनिप्युलेट करना है।

मुझे भी यही समस्या थी और इस स्निपेट के साथ आया। इसका उपयोग करता है $watchऔर यह $evalAsyncसुनिश्चित करने के लिए कि आपके कोड ng-repeatको हल किया गया है जैसे कि हल किया गया है और जैसे टेम्पलेट {{ value }}प्रदान किए गए हैं।

app.directive('name', function() {
    return {
        link: function($scope, element, attrs) {
            // Trigger when number of children changes,
            // including by directives like ng-repeat
            var watch = $scope.$watch(function() {
                return element.children().length;
            }, function() {
                // Wait for templates to render
                $scope.$evalAsync(function() {
                    // Finally, directives are evaluated
                    // and templates are renderer here
                    var children = element.children();
                    console.log(children);
                });
            });
        },
    };
});

आशा है कि यह आपको कुछ संघर्ष को रोकने में मदद कर सकता है।


यह स्पष्ट हो सकता है, लेकिन अगर यह आपके लिए काम नहीं करता है, तो अपने लिंक फ़ंक्शंस / कंट्रोलर्स में एसिंक्रोनस ऑपरेशंस की जाँच करें। मुझे नहीं लगता कि $ evalAsync उन लोगों को ध्यान में रख सकता है।
LOAS

ध्यान देने योग्य बात यह है कि आप किसी linkफ़ंक्शन को a के साथ भी जोड़ सकते हैं templateUrl
विटावर

35

Misko की सलाह के बाद, यदि आप async ऑपरेशन चाहते हैं, तो $ timeout () के बजाय (जो काम नहीं करता है)

$timeout(function () { $scope.assignmentsLoaded(data); }, 1000);

$ evalAsync () का उपयोग करें (जो काम करता है)

$scope.$evalAsync(function() { $scope.assignmentsLoaded(data); } );

फील करना । मैंने एक "डेटा की पंक्ति हटाएं" लिंक भी जोड़ा, जो $ स्कोप को संशोधित करेगा। डेटा / मॉडल में परिवर्तन का अनुकरण करते हुए - यह दिखाने के लिए कि डेटा काम करता है।

वैचारिक अवलोकन पृष्ठ का रनटाइम अनुभाग बताता है कि evalAsync का उपयोग तब किया जाना चाहिए जब आपको वर्तमान स्टैक फ़्रेम के बाहर कुछ होने की आवश्यकता होती है, लेकिन ब्राउज़र रेंडर करने से पहले। (यहाँ अनुमान लगाते हुए ... "वर्तमान स्टैक फ़्रेम" में शायद कोणीय डोम अपडेट शामिल हैं।) यदि ब्राउज़र रेंडर करने के बाद आपको कुछ करने की आवश्यकता हो तो $ टाइमआउट का उपयोग करें।

हालाँकि, जैसा कि आपको पहले ही पता चला है, मुझे नहीं लगता कि यहाँ async ऑपरेशन की कोई आवश्यकता है।


4
$scope.$evalAsync($scope.assignmentsLoaded(data));कोई मतलब नहीं आईएमओ। इसके लिए तर्क $evalAsync()एक फ़ंक्शन होना चाहिए। आपके उदाहरण में आप उस फ़ंक्शन को कॉल कर रहे हैं जिस समय एक फ़ंक्शन को बाद के निष्पादन के लिए पंजीकृत होना चाहिए।
hgoebl

@ अहबेबल, $ evalAsync का तर्क एक फ़ंक्शन या एक अभिव्यक्ति हो सकता है। इस मामले में मैंने एक अभिव्यक्ति का उपयोग किया। लेकिन आप सही हैं, अभिव्यक्ति तुरंत निष्पादित हो जाती है। मैंने बाद के निष्पादन के लिए इसे एक फ़ंक्शन में लपेटने के लिए उत्तर को संशोधित किया। उस पकड़ने के लिए धन्यवाद।
मार्क राजकॉक

26

मैंने पाया है कि सबसे सरल (सस्ता और हंसमुख) समाधान केवल एनजी-शो = "someFunctionThatAlwaysReturnsZeroOrNothing ()" के साथ खाली अवधि जोड़कर अंतिम तत्व प्रदान किया गया है। स्पैन तत्व प्रदर्शित किया जाना चाहिए या नहीं यह जांचने के लिए यह फ़ंक्शन चलाया जाएगा। इस फ़ंक्शन में कोई अन्य कोड निष्पादित करें।

मुझे एहसास है कि यह चीजों को करने का सबसे सुरुचिपूर्ण तरीका नहीं है, हालांकि, यह मेरे लिए काम करता है ...

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


3
यह सुनिश्चित करने के लिए एक हैक है, लेकिन यह वास्तव में मैं क्या जरूरत है। मेरे कोड को रेंडर करने के बाद बिल्कुल चलाने के लिए मजबूर किया (या वास्तव में बहुत करीब से)। एक आदर्श दुनिया में मैं ऐसा नहीं करूंगा लेकिन हम यहाँ हैं ...
एंड्रयू

मुझे जरूरत थी कि इस $anchorScrollसेवा में निर्मित को DOM रेंडर के बाद बुलाया जाए और कुछ भी नहीं किया गया हो, लेकिन इस ट्रिक को करने के लिए कुछ नहीं किया गया। हैकिस लेकिन काम करता है।
पैट मिगलियाकियो

एनजी-इनिट एक बेहतर विकल्प है
फ्लाइंग गैम्बिट

1
एनजी-इनिट हमेशा काम नहीं कर सकता है। उदाहरण के लिए, मेरे पास एनजी-रिपीट है जो डोम में कई छवियों को जोड़ता है। यदि मैं एनजी-शो में प्रत्येक छवि के जुड़ने के बाद किसी फ़ंक्शन को कॉल करना चाहता हूं तो मुझे एनजी-शो का उपयोग करना होगा।
माइकल ब्रेमकैंप

7

मुझे लगता है कि आप $ evalAsync की तलाश कर रहे हैं http://docs.angularjs.org/api/ng.$rootScope.Scope#$evalAsync


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

4

अंत में मुझे समाधान मिल गया, मैं अपने संग्रह को अपडेट करने के लिए REST सेवा का उपयोग कर रहा था। आदेश में परिवर्तनशील jquery का अनुसरण करने के लिए निम्नलिखित कोड है:

$scope.$watchCollection( 'conferences', function( old, nuew ) {
        if( old === nuew ) return;
        $( '#dataTablex' ).dataTable().fnDestroy();
        $timeout(function () {
                $( '#dataTablex' ).dataTable();
        });
    });

3

मुझे यह अक्सर करना पड़ता है। मेरे पास एक निर्देश है और मॉडल के सामान को पूरी तरह से डोम में लोड करने के बाद कुछ jquery सामान करने की आवश्यकता है। इसलिए मैंने लिंक में अपना तर्क दिया: निर्देश का कार्य और कोड को एक सेटटाइमआउट (फ़ंक्शन () {.....}, 1) में लपेटें; DOM लोड होने के बाद setTimout फायर करेगा और कोड निष्पादित होने से पहले DOM के लोड होने के बाद 1 मील का समय कम से कम होगा। यह मेरे लिए काम करने लगता है, लेकिन मुझे इच्छा है कि एक बार टेम्प्लेट लोड करने के बाद कोणीय ने एक घटना को उठाया ताकि उस टेम्पलेट द्वारा उपयोग किए जाने वाले निर्देश jquery के सामान और DOM तत्वों तक पहुंच सकें। उम्मीद है की यह मदद करेगा।



2

न तो $ गुंजाइश। $ evalAsync () या $ टाइमआउट (fn, 0) ने मेरे लिए मज़बूती से काम किया।

मुझे दोनों को मिलाना था। मैंने एक निर्देश बनाया और अच्छे उपाय के लिए डिफ़ॉल्ट मूल्य से अधिक प्राथमिकता दी। इसके लिए एक निर्देश है (नोट मैं निर्भरता को इंजेक्ट करने के लिए ngInject का उपयोग करता हूं):

app.directive('postrenderAction', postrenderAction);

/* @ngInject */
function postrenderAction($timeout) {
    // ### Directive Interface
    // Defines base properties for the directive.
    var directive = {
        restrict: 'A',
        priority: 101,
        link: link
    };
    return directive;

    // ### Link Function
    // Provides functionality for the directive during the DOM building/data binding stage.
    function link(scope, element, attrs) {
        $timeout(function() {
            scope.$evalAsync(attrs.postrenderAction);
        }, 0);
    }
}

निर्देश को कॉल करने के लिए, आप ऐसा करेंगे:

<div postrender-action="functionToRun()"></div>

अगर आप एनजी-रिपीट चलने के बाद इसे कॉल करना चाहते हैं, तो मैंने अपने एनजी-रिपीट और एनजी-इफ = "$ last" में एक खाली अवधि जोड़ी।

<li ng-repeat="item in list">
    <!-- Do stuff with list -->
    ...

    <!-- Fire function after the last element is rendered -->
    <span ng-if="$last" postrender-action="$ctrl.postRender()"></span>
</li>

1

कुछ परिदृश्यों में जहां आप किसी सेवा को अपडेट करते हैं और एक नए दृश्य (पेज) पर रीडायरेक्ट करते हैं और फिर आपकी सेवाओं के अपडेट होने से पहले आपका निर्देश लोड हो जाता है तो आप $ rootScope का उपयोग कर सकते हैं। यदि आपका $ वॉच या $ टाइमआउट विफल हो जाता है।

राय

<service-history log="log" data-ng-repeat="log in requiedData"></service-history>

नियंत्रक

app.controller("MyController",['$scope','$rootScope', function($scope, $rootScope) {

   $scope.$on('$viewContentLoaded', function () {
       SomeSerive.getHistory().then(function(data) {
           $scope.requiedData = data;
           $rootScope.$broadcast("history-updation");
       });
  });

}]);

आदेश

app.directive("serviceHistory", function() {
    return {
        restrict: 'E',
        replace: true,
        scope: {
           log: '='
        },
        link: function($scope, element, attrs) {
            function updateHistory() {
               if(log) {
                   //do something
               }
            }
            $rootScope.$on("history-updation", updateHistory);
        }
   };
});

1

मैं एक बहुत सरल समाधान के साथ आया था। मुझे यकीन नहीं है कि यह करने का सही तरीका है लेकिन यह व्यावहारिक अर्थों में काम करता है। आइए सीधे देखें कि हम क्या प्रदान करना चाहते हैं। उदाहरण के लिए एक निर्देश जिसमें कुछ ng-repeatएस शामिल हैं , मैं पैराग्राफ या पूरे HTML के पाठ की लंबाई (आप अन्य चीजें हो सकती हैं!) के लिए बाहर देखना होगा। निर्देश इस प्रकार होगा:

.directive('myDirective', [function () {
    'use strict';
    return {

        link: function (scope, element, attrs) {
            scope.$watch(function(){
               var whole_p_length = 0;
               var ps = element.find('p');
                for (var i=0;i<ps.length;i++){
                    if (ps[i].innerHTML == undefined){
                        continue
                    }
                    whole_p_length+= ps[i].innerHTML.length;
                }
                //it could be this too:  whole_p_length = element[0].innerHTML.length; but my test showed that the above method is a bit faster
                console.log(whole_p_length);
                return whole_p_length;
            }, function (value) {   
                //Code you want to be run after rendering changes
            });
        }
}]);

ध्यान दें कि कोड वास्तव में पूर्ण प्रतिपादन के बजाय परिवर्तनों को प्रस्तुत करने के बाद चलता है । लेकिन मुझे लगता है कि ज्यादातर मामलों में आप स्थितियों को संभाल सकते हैं जब भी परिवर्तन होता है। इसके अलावा आप इस pमॉडल की लंबाई (या किसी अन्य उपाय) की तुलना अपने मॉडल से करने की सोच सकते हैं यदि आप पूरा होने के बाद केवल एक बार अपना कोड चलाना चाहते हैं । मैं इस पर किसी भी विचार / टिप्पणी की सराहना करता हूं।


0

आप कोणीय-यूआई बर्तनों के 'jQuery Passthrough' मॉड्यूल का उपयोग कर सकते हैं । मैंने सफलतापूर्वक कुछ छवियों के लिए एक jQuery टच हिंडोला प्लगइन को बांध दिया है जो मैं एक वेब सेवा से async पुनः प्राप्त करता हूं और उन्हें एनजी-रिपीट के साथ प्रस्तुत करता हूं।

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