वहाँ एक पोस्ट कोणीय जेएस निर्देश के लिए कॉलबैक सौंपनेवाला है?


139

मैंने अपने निर्देश को इस तरह अपने तत्व में जोड़ने के लिए एक टेम्पलेट में खींचने के लिए अपना निर्देश दिया है:

# CoffeeScript
.directive 'dashboardTable', ->
  controller: lineItemIndexCtrl
  templateUrl: "<%= asset_path('angular/templates/line_items/dashboard_rows.html') %>"
  (scope, element, attrs) ->
    element.parent('table#line_items').dataTable()
    console.log 'Just to make sure this is run'

# HTML
<table id="line_items">
    <tbody dashboard-table>
    </tbody>
</table>

मैं डेटाटेबल्स नामक एक jQuery प्लगइन का भी उपयोग कर रहा हूं। इसका सामान्य उपयोग इस प्रकार है: $ ('तालिका # some_id')। डेटाटेबल ()। आप JSON डेटा को डेटाटेबल में पास कर सकते हैं () टेबल डेटा की आपूर्ति करने के लिए कॉल करें या आपके पास पृष्ठ पर पहले से ही डेटा हो सकता है और यह बाकी काम करेगा .. मैं बाद में कर रहा हूं, HTML पृष्ठ पर पहले से पंक्तियाँ हैं ।

लेकिन समस्या यह है कि मुझे टेबल पर #T_items AFTER DOM के लिए डेटाटेबल () कॉल करना होगा। ऊपर मेरा निर्देश डेटाटेबल कहता है () विधि के तत्व से पहले टेम्पलेट को जोड़ा जाता है। क्या कोई ऐसा तरीका है जिसे मैं एपेंड के बाद फ़ंक्शन कह सकता हूं?

आपके सहयोग के लिए धन्यवाद!

एंडी के जवाब के बाद अपडेट 1:

मैं यह सुनिश्चित करना चाहता हूं कि लिंक पद्धति केवल AFTER कहलाती है सब कुछ पेज पर है इसलिए मैंने थोड़ा सा निर्देश के लिए निर्देश बदल दिया:

# CoffeeScript
#angular.module(...)
.directive 'dashboardTable', ->
    {
      link: (scope,element,attrs) -> 
        console.log 'Just to make sure this gets run'
        element.find('#sayboo').html('boo')

      controller: lineItemIndexCtrl
      template: "<div id='sayboo'></div>"

    }

और मैं वास्तव में div # sayboo में "बू" देखता हूं।

फिर मैं अपने jquery डेटा को कॉल करने का प्रयास करता हूं

.directive 'dashboardTable',  ->
    {
      link: (scope,element,attrs) -> 
        console.log 'Just to make sure this gets run'
        element.parent('table').dataTable() # NEW LINE

      controller: lineItemIndexCtrl
      templateUrl: "<%= asset_path('angular/templates/line_items/dashboard_rows.html') %>"
    }

वहां कोई किस्मत नहीं

फिर मैं एक समय जोड़ने की कोशिश करता हूं:

.directive 'dashboardTable', ($timeout) ->
    {
      link: (scope,element,attrs) -> 
        console.log 'Just to make sure this gets run'
        $timeout -> # NEW LINE
          element.parent('table').dataTable()
        ,5000
      controller: lineItemIndexCtrl
      templateUrl: "<%= asset_path('angular/templates/line_items/dashboard_rows.html') %>"
    }

और वह काम करता है। तो मुझे आश्चर्य है कि कोड के गैर-टाइमर संस्करण में क्या गलत है?


1
@adardesign नहीं मैंने कभी नहीं किया, मुझे एक टाइमर का उपयोग करना पड़ा। किसी कारण से, कॉलबैक वास्तव में यहाँ कॉलबैक नहीं है। मेरे पास 11 कॉलम और 100 पंक्तियों के साथ एक तालिका है, इसलिए स्वाभाविक रूप से कोणीय डेटा बाइंडिंग के लिए उपयोग करने के लिए एक अच्छा शर्त जैसा दिखता है; लेकिन मुझे jquery डेटाटैबल्स प्लगइन का भी उपयोग करने की आवश्यकता है जो $ ('तालिका') के समान सरल है। निर्देशन का उपयोग करना या बस सभी पंक्तियों के साथ एक डंबल जोंस ऑब्जेक्ट का उपयोग करना और एनजीआर को दोहराने के लिए पुनरावृत्ति का उपयोग करना, मुझे $ $ () नहीं मिल सकता है। html HTML तत्व को प्रस्तुत करने के लिए चलाने के लिए। यह जाँचने के लिए कि क्या $ ('tr') लंबाई> 3 (हेडर / फुटर का b / c)
निक

2
@ प्रारूप और हां, मैंने सभी संकलन विधि की कोशिश की, संकलन विधि किसी वस्तु को लौटाने की विधि पोस्टलिंक / प्रीलिंक, संकलन विधि सिर्फ एक फ़ंक्शन (जैसे लिंकिंग फ़ंक्शन), लिंकिंग विधि (संकलन विधि के बिना) क्योंकि मैं बता सकता हूं, यदि आपके पास एक संकलन विधि है जो एक लिंकिंग विधि लौटाती है, तो लिंकिंग फ़ंक्शन को अनदेखा किया जाता है) .. किसी ने भी काम नहीं किया है इसलिए अच्छे पुराने $ समय पर भरोसा करना होगा। इस पोस्ट को अपडेट करूंगा अगर मुझे कुछ भी मिलता है जो बेहतर काम करता है या बस जब मुझे पता चलता है कि कॉलबैक वास्तव में कॉलबैक की तरह काम करता है
निक तो

जवाबों:


215

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

$timeout(function () {
    //DOM has finished rendering
});

8
इसे डॉक्स में क्यों नहीं समझाया गया है ?
गौई

23
आप सही हैं, मेरा जवाब थोड़ा भ्रामक है क्योंकि मैंने इसे सरल बनाने की कोशिश की थी। पूर्ण उत्तर यह है कि यह प्रभाव कोणीय का नहीं बल्कि ब्राउज़र का परिणाम है। $timeout(fn)आखिरकार कॉल setTimeout(fn, 0)होता है जिसका प्रभाव जावास्क्रिप्ट निष्पादन में बाधा होता है और ब्राउज़र को उस जावास्क्रिप्ट का निष्पादन जारी रखने से पहले सामग्री को प्रस्तुत करने की अनुमति देता है।
पार्लियामेंट

7
ब्राउज़र के बारे में सोचें कि कतार के कुछ कार्य जैसे "जावास्क्रिप्ट निष्पादन" और "DOM रेंडरिंग" अलग-अलग हैं, और क्या setTimeout (fn, 0) यह वर्तमान में चल रहे "जावास्क्रिप्ट निष्पादन" को कतार के पीछे धकेलता है। ।
पार्लियामेंट

2
@GabLeRoux yup, कि $ टाइमआउट को छोड़कर एक ही प्रभाव होगा, $ स्कोप को कॉल करने का अतिरिक्त लाभ है। इसके चलने के बाद $ apply () लागू होता है। _.Defer () के साथ यदि myFunction के दायरे में परिवर्तन होते हैं, तो आपको इसे मैन्युअल रूप से कॉल करना होगा।
संसद

2
मेरे पास एक ऐसा परिदृश्य है जहां यह मदद नहीं करता है जहां पेज 1 एनजी-रिपीट तत्वों के रेंडर गुच्छा पर होता है, फिर मैं पेज 2 पर जाता हूं और फिर मैं पेज 1 पर वापस जाता हूं और मैं एनजी-रिपीट एलिमेंट्स के उच्च पाने की कोशिश करता हूं ... यह गलत ऊंचाई देता है। अगर मैं 1000 मी की तरह टाइमआउट करता हूं, तो यह काम करता है।
योडाल्र

14

मुझे भी यही समस्या थी और मुझे विश्वास है कि उत्तर वास्तव में नहीं है। मिश्को की टिप्पणी और समूह में कुछ चर्चा देखें ।

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

जैसा कि आपने किया था, हमने इसे एक सेटटाइमआउट के साथ हल किया।

(कृपया ध्यान रखें कि हर कोई मेरे साथ सहमत नहीं है - आपको उपरोक्त लिंक पर टिप्पणियों को पढ़ना चाहिए और देखना चाहिए कि आप क्या सोचते हैं)।


7

आप 'लिंक' फ़ंक्शन का उपयोग कर सकते हैं, जिसे पोस्टलिंक के रूप में भी जाना जाता है, जो टेम्पलेट में डालने के बाद चलता है।

app.directive('myDirective', function() {
  return {
    link: function(scope, elm, attrs) { /*I run after template is put in */ },
    template: '<b>Hello</b>'
  }
});

यह एक अगर तुम निर्देशों बनाने पर योजना को पढ़ने दो, यह एक बड़ा मदद है: http://docs.angularjs.org/guide/directive


हाय एंडी, जवाब देने के लिए बहुत बहुत धन्यवाद; मैंने लिंक फंक्शन की कोशिश की थी, लेकिन मैं इसे दोबारा कोड करने की कोशिश में बुरा नहीं मानूंगा; मैंने पिछले 1.5 दिन उस निर्देश पृष्ठ पर पढ़े; और कोणीय साइट पर भी उदाहरण देख रहे हैं। अब आपके कोड की कोशिश करेंगे।
निक सो

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

हाय एंडी, मेरे परिणाम वापस मिल गए; मैंने अपनी पवित्रता लगभग खो दी है, क्योंकि मैंने वास्तव में मूल रूप से वही किया है जो आपका उत्तर है। कृपया मेरा अपडेट देखें
निक सो

हमम, कुछ इस तरह का प्रयास करें: <table id = "bob"> <tbody डैशबोर्ड-तालिका = "# बॉब"> </ tbody> </ table> फिर अपने लिंक में, $ (attrs.dashboardTable) .dataTable () को करें। सुनिश्चित करें कि यह सही चुना जा रहा है। या मुझे लगता है कि आप पहले से ही कोशिश कर चुके हैं .. अगर लिंक काम नहीं कर रहा है तो मुझे यकीन नहीं है।
एंड्रयू जोसलिन

यह मेरे लिए काम करता है, मैं अपनी आवश्यकता के लिए टेम्प्लेट के डोम पोस्ट प्रतिपादन के भीतर तत्वों को स्थानांतरित करना चाहता था, लिंक फ़ंक्शन में किया था।
abhi

7

यद्यपि मेरा उत्तर डेटाटेबल्स से संबंधित नहीं है, यह डोम हेरफेर के मुद्दे को संबोधित करता है और उदाहरण के लिए तत्वों पर उपयोग किए जाने वाले निर्देशों के लिए jQuery प्लगइन आरंभीकरण जो उनकी सामग्री को async तरीके से अपडेट किया गया है।

टाइमआउट लागू करने के बजाय, केवल एक घड़ी को जोड़ा जा सकता है जो सामग्री परिवर्तनों (या यहां तक ​​कि अतिरिक्त बाहरी ट्रिगर) को सुनेगा।

मेरे मामले में मैंने इस वर्कअराउंड का उपयोग एक jQuery प्लगइन को इनिशियलाइज़ करने के लिए किया था एक बार एनजी-रिपीट होने के बाद जिसने मेरे इनर डोम को बनाया था - एक अन्य मामले में मैंने इसका इस्तेमाल सिर्फ डोम के हेरफेर के लिए किया था क्योंकि स्कोप प्रॉपर्टी में कंट्रोलर को बदल दिया गया था। यहाँ है कि मैं कैसे किया ...

HTML:

<div my-directive my-directive-watch="!!myContent">{{myContent}}</div>

जे एस:

app.directive('myDirective', [ function(){
    return {
        restrict : 'A',
        scope : {
            myDirectiveWatch : '='
        },
        compile : function(){
            return {
                post : function(scope, element, attributes){

                    scope.$watch('myDirectiveWatch', function(newVal, oldVal){
                        if (newVal !== oldVal) {
                            // Do stuff ...
                        }
                    });

                }
            }
        }
    }
}]);

ध्यान दें: मेरे निर्देशात्मक-वॉच विशेषता पर बूल के लिए माइकोन्टेंट चर कास्ट करने के बजाय, कोई भी मनमाना अभिव्यक्ति की कल्पना कर सकता है।

नोट: उपर्युक्त उदाहरण की तरह गुंजाइश को अलग करना केवल एक बार तत्व के अनुसार किया जा सकता है - एक ही तत्व पर कई निर्देशों के साथ ऐसा करने का प्रयास $ संकलन में होगा: multidir त्रुटि - देखें: https://docs.angularjs.org / त्रुटि / $ संकलन / multidir


7

इस प्रश्न का उत्तर देने में देर हो सकती है। लेकिन फिर भी किसी को मेरे उत्तर से लाभ मिल सकता है।

मेरे पास समान मुद्दा था और मेरे मामले में मैं निर्देश को नहीं बदल सकता, यह एक पुस्तकालय है और पुस्तकालय का एक कोड बदलना अच्छा अभ्यास नहीं है। तो मैंने जो किया वह एक चर का उपयोग करने के लिए पृष्ठ लोड करने के लिए प्रतीक्षा करने और एनजी-अगर मेरे HTML के अंदर का उपयोग करने के लिए विशेष तत्व को प्रस्तुत करने के लिए प्रतीक्षा करने के लिए किया गया था।

मेरे नियंत्रक में:

$scope.render=false;

//this will fire after load the the page

angular.element(document).ready(function() {
    $scope.render=true;
});

मेरे HTML में (मेरे मामले में html घटक एक कैनवास है)

<canvas ng-if="render"> </canvas>

3

मैं एक ही मुद्दा था, लेकिन एक साथ कोणीय + DataTable का उपयोग कर fnDrawCallback+ पंक्ति समूहीकरण + $ संकलित नेस्टेड निर्देशों। मैंने fnDrawCallbackपेजिंग प्रतिपादन को ठीक करने के लिए अपने कार्य में $ टाइमआउट रखा ।

उदाहरण से पहले, row_grouping स्रोत पर आधारित:

var myDrawCallback = function myDrawCallbackFn(oSettings){
  var nTrs = $('table#result>tbody>tr');
  for(var i=0; i<nTrs.length; i++){
     //1. group rows per row_grouping example
     //2. $compile html templates to hook datatable into Angular lifecycle
  }
}

उदाहरण के बाद:

var myDrawCallback = function myDrawCallbackFn(oSettings){
  var nTrs = $('table#result>tbody>tr');
  $timeout(function requiredRenderTimeoutDelay(){
    for(var i=0; i<nTrs.length; i++){
       //1. group rows per row_grouping example
       //2. $compile html templates to hook datatable into Angular lifecycle
    }
  ,50); //end $timeout
}

यहां तक ​​कि थोड़े समय की देरी के लिए पर्याप्त था कि कोणीय मेरे संकलित कोणीय निर्देशों को प्रस्तुत कर सके।


बस जिज्ञासु, क्या आपके पास कई स्तंभों के साथ एक बड़ी मेज है? क्योंकि मैंने पाया कि मुझे बहुत सी मिलीसेकंड (> 100) की आवश्यकता है ताकि डेटाटेबल () को ठोकने के लिए न बुलाया जाए
निक तो

मैंने पाया कि 150 पंक्तियों से अधिक 2 पंक्तियों के परिणाम सेट के लिए डेटाटेबल पेज नेविगेशन पर समस्या हुई । तो, नहीं - मुझे नहीं लगता कि तालिका का आकार मुद्दा था, लेकिन शायद DataTable ने उन कुछ मिलीसेकेंड को दूर करने के लिए पर्याप्त रेंडरिंग ओवरहेड को जोड़ा। मेरा ध्यान न्यूनतम AngularJS एकीकरण के साथ DataTable में काम करने के लिए पंक्ति-समूहन पर केंद्रित था।
जेजे ज़ाबकर

2

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

ध्यान दें, हालांकि, '0' का एक टाइमआउट हो सकता है क्योंकि टाइमआउट फ़ंक्शन को ब्राउज़र की कतार में बुलाया जा रहा है जो कोणीय रेंडरिंग इंजन के बाद होगा क्योंकि यह पहले से ही कतार में है।

इसका संदर्भ लें: http://blog.brunoscopelliti.com/run-a-directive-after-the-dom-has-finished-rendering


0

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

define(['angular'], function (angular) {
  'use strict';
  return angular.module('app.common.after-render', [])
    .directive('afterRender', [ '$timeout', function($timeout) {
    var def = {
        restrict : 'A', 
        terminal : true,
        transclude : false,
        link : function(scope, element, attrs) {
            if (attrs) { scope.$eval(attrs.afterRender) }
            scope.$emit('onAfterRender')
        }
    };
    return def;
    }]);
});

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

<div after-render></div>

या किसी भी उपयोगी अभिव्यक्ति के साथ जैसे:

<div after-render="$emit='onAfterThisConcreteThingRendered'"></div>


यह वास्तव में सामग्री प्रदान करने के बाद नहीं है। अगर मैं तत्व के अंदर एक अभिव्यक्ति था <div after-render> {{blah}} </ div> इस बिंदु पर अभी तक अभिव्यक्ति का मूल्यांकन नहीं किया गया है। लिंक फ़ंक्शन के अंदर div की सामग्री अभी भी {{blah}} है। तो तकनीकी रूप से आप सामग्री को प्रस्तुत करने से पहले घटना को निकाल रहे हैं।
एडवर्ड ओलिमिसन

रेंडर एक्शन के बाद यह उथला है, मैंने कभी दावा नहीं किया है कि यह गहरा है
सेबस्टियन सस्त्रे

0

मुझे निम्नलिखित निर्देश के साथ यह काम मिला है:

app.directive('datatableSetup', function () {
    return { link: function (scope, elm, attrs) { elm.dataTable(); } }
});

और HTML में:

<table class="table table-hover dataTable dataTable-columnfilter " datatable-setup="">

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

1) ध्यान दें कि 'datatableSetup' 'datatable-setup' के बराबर है। कोणीय मामले को ऊँट के मामले में बदल देता है।

2) सुनिश्चित करें कि निर्देश से पहले ऐप को परिभाषित किया गया है। उदाहरण के लिए सरल ऐप परिभाषा और निर्देश।

var app = angular.module('app', []);
app.directive('datatableSetup', function () {
    return { link: function (scope, elm, attrs) { elm.dataTable(); } }
});

0

इस तथ्य के बाद कि लोड ऑर्डर का अनुमान नहीं लगाया जा सकता है, एक सरल समाधान का उपयोग किया जा सकता है।

आइए नजर डालते हैं डायरेक्शन-er डायरेक्टर ऑफ डायरेक्शन ’के रिश्ते पर। आमतौर पर निर्देश का उपयोगकर्ता निर्देश को कुछ डेटा की आपूर्ति करेगा या निर्देश की आपूर्ति में कुछ कार्यक्षमता (फ़ंक्शन) का उपयोग करेगा। दूसरी ओर निर्देश की उम्मीद है कि इसके दायरे में कुछ चरों को परिभाषित किया जाएगा।

यदि हम यह सुनिश्चित कर सकते हैं कि उन कार्यों को निष्पादित करने का प्रयास करने से पहले सभी खिलाड़ियों की सभी कार्रवाई की आवश्यकताएं पूरी हो जाएं - सब कुछ ठीक होना चाहिए।

और अब निर्देश:

app.directive('aDirective', function () {
    return {
        scope: {
            input: '=',
            control: '='
        },
        link: function (scope, element) {
            function functionThatNeedsInput(){
                //use scope.input here
            }
            if ( scope.input){ //We already have input 
                functionThatNeedsInput();
            } else {
                scope.control.init = functionThatNeedsInput;
            }
          }

        };
})

और अब निर्देशक html का उपयोगकर्ता

<a-directive control="control" input="input"></a-directive>

और कहीं न कहीं उस घटक के नियंत्रक में जो निर्देश का उपयोग करता है:

$scope.control = {};
...
$scope.input = 'some data could be async';
if ( $scope.control.functionThatNeedsInput){
    $scope.control.functionThatNeedsInput();
}

यह इसके बारे में। बहुत अधिक ओवरहेड है, लेकिन आप $ समय समाप्त कर सकते हैं। हम यह भी मानते हैं कि निर्देश का उपयोग करने वाले घटक को निर्देश से पहले त्वरित किया जाता है क्योंकि हम निर्देश चर पर निर्भर होते हैं जब निर्देश तत्काल होता है।

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