অ্যাঙ্গুলারজেএস-এ নির্দেশিকা থেকে নির্দেশিকা যুক্ত করুন


197

আমি এমন একটি নির্দেশিকা তৈরির চেষ্টা করছি যা এটি ঘোষিত উপাদানটিতে আরও নির্দেশিকা যুক্ত করার ক্ষেত্রে যত্নশীল । উদাহরণস্বরূপ, আমি যে একটি নির্দেশ যোগ করার যত্ন নেয় গড়তে চাই datepicker, datepicker-languageএবং ng-required="true"

যদি আমি এই বৈশিষ্ট্যগুলি যুক্ত করার চেষ্টা করি এবং তারপরে $compileআমি স্পষ্টতই একটি অসীম লুপ তৈরি করি, তাই আমি ইতিমধ্যে প্রয়োজনীয় বৈশিষ্ট্যগুলি যুক্ত করেছি কিনা তা আমি যাচাই করছি:

angular.module('app')
  .directive('superDirective', function ($compile, $injector) {
    return {
      restrict: 'A',
      replace: true,
      link: function compile(scope, element, attrs) {
        if (element.attr('datepicker')) { // check
          return;
        }
        element.attr('datepicker', 'someValue');
        element.attr('datepicker-language', 'en');
        // some more
        $compile(element)(scope);
      }
    };
  });

অবশ্যই, আমি যদি $compileউপাদানটি না রাখি তবে বৈশিষ্ট্যগুলি সেট করা হবে তবে নির্দেশিকা বুটস্ট্র্যাপ করা হবে না।

এই পদ্ধতির সঠিক বা আমি এটি ভুল করছি? একই আচরণ অর্জনের আরও ভাল উপায় আছে কি?

UDPATE : এটি $compileঅর্জনের একমাত্র উপায় হ'ল সত্যটি প্রদত্ত , প্রথম সংকলন পাসটি এড়িয়ে যাওয়ার কোনও উপায় আছে (উপাদানটিতে বেশ কয়েকটি শিশু থাকতে পারে)? সেট করে terminal:trueকি?

আপডেট 2 : আমি নির্দেশটিকে একটি selectউপাদানটিতে রাখার চেষ্টা করেছি এবং যেমনটি প্রত্যাশা করা হয়েছিল, সংকলনটি দু'বার চলে, যার অর্থ প্রত্যাশিত সংখ্যার দ্বিগুণ option

উত্তর:


260

একক ডিওএম উপাদান নিয়ে আপনার একাধিক নির্দেশনা রয়েছে এবং যেখানে তারা যে ক্রম প্রয়োগ করেছে সে ক্ষেত্রে আপনি priorityতাদের প্রয়োগের আদেশ দেওয়ার জন্য সম্পত্তিটি ব্যবহার করতে পারেন । উচ্চতর সংখ্যা প্রথমে চলে। ডিফল্ট অগ্রাধিকার 0 হয় যদি আপনি কোনও নির্দিষ্ট না করেন।

সম্পাদনা : আলোচনার পরে, এখানে সম্পূর্ণ কার্যক্ষম সমাধান। কীটি ছিল বৈশিষ্ট্যটি মুছে ফেলা : element.removeAttr("common-things");এবং এটিও element.removeAttr("data-common-things");(ব্যবহারকারীরা data-common-thingsএইচটিএমএল-তে নির্দিষ্ট করেছেন)

angular.module('app')
  .directive('commonThings', function ($compile) {
    return {
      restrict: 'A',
      replace: false, 
      terminal: true, //this setting is important, see explanation below
      priority: 1000, //this setting is important, see explanation below
      compile: function compile(element, attrs) {
        element.attr('tooltip', '{{dt()}}');
        element.attr('tooltip-placement', 'bottom');
        element.removeAttr("common-things"); //remove the attribute to avoid indefinite loop
        element.removeAttr("data-common-things"); //also remove the same attribute with data- prefix in case users specify data-common-things in the html

        return {
          pre: function preLink(scope, iElement, iAttrs, controller) {  },
          post: function postLink(scope, iElement, iAttrs, controller) {  
            $compile(iElement)(scope);
          }
        };
      }
    };
  });

ওয়ার্কিং প্লঙ্কার এখানে উপলব্ধ: http://plnkr.co/edit/Q13bUt?p= পূর্বরূপ দেখুন

বা:

angular.module('app')
  .directive('commonThings', function ($compile) {
    return {
      restrict: 'A',
      replace: false,
      terminal: true,
      priority: 1000,
      link: function link(scope,element, attrs) {
        element.attr('tooltip', '{{dt()}}');
        element.attr('tooltip-placement', 'bottom');
        element.removeAttr("common-things"); //remove the attribute to avoid indefinite loop
        element.removeAttr("data-common-things"); //also remove the same attribute with data- prefix in case users specify data-common-things in the html

        $compile(element)(scope);
      }
    };
  });

ডেমো

কেন আমাদের সেট করতে হবে terminal: trueএবং priority: 1000(একটি উচ্চ সংখ্যা) ব্যাখ্যা:

যখন ডিওএম প্রস্তুত থাকে, কৌণিক সমস্ত নিবন্ধিত নির্দেশাবলী সনাক্ত করতে এবং priority এই নির্দেশাবলী একই উপাদানটিতে থাকে কিনা তার উপর ভিত্তি করে নির্দেশকে একের পর এক সংকলন করতে কৌতুক ডিওএম পদক্ষেপ গ্রহণ করে । আমরা আমাদের কাস্টম নির্দেশের অগ্রাধিকারটি একটি উচ্চ সংখ্যায় সেট করেছিলাম তা নিশ্চিত করার জন্য যে এটি প্রথমে সংকলন করা হবে এবং তার সাথে এই নির্দেশিকাটি সংকলিত হওয়ার পরে terminal: trueঅন্যান্য নির্দেশাবলী বাদ দেওয়া হবে ।

যখন আমাদের কাস্টম নির্দেশিকাটি সংকলিত হয়, তখন এটি নির্দেশকে যুক্ত করে এবং নিজেই মুছে ফেলার মাধ্যমে উপাদানটি সংশোধন করে এবং all সমস্ত নির্দেশাবলী (বাদ দেওয়া হয়নি এমনগুলি সহ) সংকলন করতে ile সংকলন পরিষেবা ব্যবহার করে ।

যদি আমরা সেট না করি terminal:trueএবং priority: 1000, আমাদের কাস্টম নির্দেশাবলীর আগে কিছু নির্দেশ সংকলিত হওয়ার সম্ভাবনা রয়েছে । এবং যখন আমাদের কাস্টম নির্দেশিকাটি <================================================================================================================================================================================================================ এটি অনির্দেশ্য আচরণের কারণ হবে বিশেষত যদি আমাদের কাস্টম নির্দেশাবলীর পূর্বে সংকলিত নির্দেশাবলী ইতিমধ্যে ডিওমে রূপান্তরিত হয়।

অগ্রাধিকার এবং টার্মিনাল সম্পর্কে আরও তথ্যের জন্য , নির্দেশের "টার্মিনাল" কীভাবে বুঝতে হবে তা পরীক্ষা করে দেখুন ?

টেমপ্লেটটিও সংশোধন করে এমন একটি নির্দেশিকার উদাহরণ হ'ল ng-repeat(অগ্রাধিকার = 1000), যখন ng-repeatসংকলন করা হয়, ng-repeat অন্যান্য নির্দেশাবলীর প্রয়োগ হওয়ার আগে টেমপ্লেট উপাদানটির অনুলিপি তৈরি করুন

@ ইজহাকির মন্তব্যে ধন্যবাদ, এখানে ngRepeatউত্স কোডের রেফারেন্স দেওয়া হয়েছে : https://github.com/angular/angular.js/blob/master/src/ng/directive/ngRepeat.js


5
এটি আমার কাছে একটি স্ট্যাক ওভারফ্লো ব্যতিক্রম ছুঁড়ে ফেলেছে: RangeError: Maximum call stack size exceededএটি চিরতরে সংকলন হিসাবে চলে।
ফ্রেপন্টিলো

3
@ ফ্রেপন্টিলো: আপনার ক্ষেত্রে element.removeAttr("common-datepicker");অনির্দিষ্ট লুপ এড়াতে যোগ করার চেষ্টা করুন ।
খান ২ TO

4
ঠিক আছে, আমি এটা বাছা করতে পারব, আপনি সেট আছে replace: false, terminal: true, priority: 1000; তারপরে compileফাংশনে পছন্দসই বৈশিষ্ট্যগুলি সেট করুন এবং আমাদের নির্দেশিক বৈশিষ্ট্যটি সরিয়ে দিন। পরিশেষে, postফাংশনে ফিরে compile, কল করুন $compile(element)(scope)। উপাদানটি নিয়মিত কাস্টম নির্দেশ ছাড়াই সংযোজন করা হবে তবে যুক্ত বৈশিষ্ট্য সহ। আমি যেটি অর্জনের চেষ্টা করছিলাম তা হ'ল কাস্টম নির্দেশনা সরিয়ে না দেওয়া এবং এই সমস্ত কিছুকে একটি প্রক্রিয়াতে পরিচালনা করা: এটি করা যায় না বলে মনে হয়। দয়া করে আপডেট করা plnkr: plnkr.co/edit/Q13bUt?p= পূর্বরূপ দেখুন
ফ্রেপন্টিলো

2
নোট করুন যে আপনি যদি সংকলন বা লিঙ্ক ফাংশনগুলির অ্যাট্রিবিউট অবজেক্ট প্যারামিটারটি ব্যবহার করতে চান, তবে জেনে রাখুন যে গুণাবলীর মানগুলিকে ইন্টারপোলটিং করার জন্য দায়ী নির্দেশকের অগ্রাধিকার 100 রয়েছে, এবং আপনার নির্দেশিকার চেয়ে এর চেয়ে কম অগ্রাধিকার থাকা দরকার, অন্যথায় আপনি কেবলমাত্র এটিকে পাবেন ডিরেক্টরিটি টার্মিনাল হওয়ার কারণে বৈশিষ্ট্যের স্ট্রিং মানগুলি। দেখুন ( এই গিথাব টানার অনুরোধ এবং এই সম্পর্কিত সমস্যাটি দেখুন )
সিমেন এছল্ট

2
common-thingsবৈশিষ্ট্যগুলি অপসারণের বিকল্প হিসাবে আপনি কমপাইল কমান্ডটিতে একটি সর্বাধিক জনপ্রিয় পরামিতিটি পাস করতে পারেন:$compile(element, null, 1000)(scope);
আন্দ্রেয়াস

10

আপনি কেবলমাত্র একটি সাধারণ টেম্পলেট ট্যাগ দিয়ে এগুলি সব হ্যান্ডেল করতে পারেন। উদাহরণের জন্য http://jsfiddle.net/m4ve9/ দেখুন । মনে রাখবেন যে সুপার-ডিরেক্টরেক্টিভ সংজ্ঞা অনুসারে আমার কোনও সংকলন বা সংযোগের সম্পত্তিটির দরকার নেই।

সংকলন প্রক্রিয়া চলাকালীন, কৌণিক সংকলনের আগে টেম্পলেট মানগুলিতে টান দেয়, যাতে আপনি সেখানে আরও কোনও নির্দেশিকা সংযুক্ত করতে পারেন এবং কৌণিক এটি আপনার জন্য যত্ন নেবে।

যদি এটি একটি দুর্দান্ত নির্দেশিকা যা মূল অভ্যন্তরীণ সামগ্রী সংরক্ষণ করার প্রয়োজন হয় তবে আপনি অভ্যন্তরটি ব্যবহার করে transclude : trueএটি প্রতিস্থাপন করতে পারেন<ng-transclude></ng-transclude>

আশা করি এটি সাহায্য করে, কিছু অস্পষ্ট কিনা তা আমাকে জানান

অ্যালেক্স


আপনাকে অ্যালেক্স ধন্যবাদ, এই পদ্ধতির সমস্যাটি হ'ল আমি ট্যাগটি কী হবে সে সম্পর্কে কোনও ধারণা নিতে পারি না। উদাহরণস্বরূপ এটি একটি ডেটপিকার ছিল, অর্থাত্ একটি inputট্যাগ, তবে আমি এটিকে divএস বা selectএস এর মতো কোনও উপাদানের জন্য কাজ করতে চাই ।
ফ্রেপন্টিলো

1
হ্যাঁ, আমি এটা মিস করেছি। সেক্ষেত্রে আমি একটি ডিভের সাথে লেগে থাকা এবং আপনার অন্যান্য নির্দেশিকা এতে কাজ করতে পারে তা নিশ্চিত করার পরামর্শ দেব। এটি উত্তরগুলির থেকে পরিষ্কার নয়, তবে কৌণিক পদ্ধতির মধ্যে সেরা ফিট করে। বুটস্ট্র্যাপ প্রক্রিয়াটি এইচটিএমএল নোড সংকলন শুরু করার সময়, এটি ইতিমধ্যে সংকলনের জন্য নোডের সমস্ত নির্দেশিকা সংগ্রহ করেছে, সুতরাং সেখানে একটি নতুন যুক্ত করে মূল বুটস্ট্র্যাপ প্রক্রিয়াটি লক্ষ্য করা যাবে না। আপনার প্রয়োজনের উপর নির্ভর করে আপনি সমস্ত কিছু ডিভের মধ্যে আবৃত করতে এবং এর মধ্যে কাজ করা আপনাকে আরও নমনীয়তা পেতে পারেন তবে এটি আপনাকে নিজের উপাদানটি কোথায় রাখতে পারে তাও সীমাবদ্ধ করে।
এমআরভিডট

3
@ ফ্রেপন্টিলো আপনি একটি ফাংশন হিসাবে টেমপ্লেট ব্যবহার করতে পারেন elementএবং এটি attrsপেরিয়ে যেতে পারেন me আমাকে এটি কাজ করতে যুগে যুগে নিয়ে গেছে এবং আমি এটি কোথাও ব্যবহার করতে দেখিনি - তবে এটি ঠিকঠাক
প্যাট্রিক

6

এখানে একটি সমাধান যা দিকনির্দেশনাগুলিকে গতিশীলভাবে যুক্ত করা দরকার সেই দৃষ্টিভঙ্গিতে সরিয়ে নিয়ে যায় এবং কিছু alচ্ছিক (বেসিক) শর্তসাপেক্ষ-যুক্তি যুক্ত করে। এটি কোনও হার্ড-কোডড যুক্তি দিয়ে নির্দেশকে পরিষ্কার রাখে।

নির্দেশটি বস্তুর একটি অ্যারে নেয়, প্রতিটি বস্তুতে যোগ করার নির্দেশকের নাম এবং এতে পাস করার মান (যদি থাকে) থাকে।

আমি এই জাতীয় নির্দেশের জন্য ইউজ-কেসটি ভাবতে লড়াই করে যাচ্ছিলাম যতক্ষণ না ভেবেছিলাম যে এটি কিছু শর্তাধীন যুক্তি যুক্ত করা দরকারী যা কেবলমাত্র কিছু শর্তের উপর ভিত্তি করে একটি নির্দেশ যুক্ত করে (যদিও নীচের উত্তরটি এখনও স্বীকৃত)। আমি ifএকটি alচ্ছিক সম্পত্তি যুক্ত করেছি যাতে একটি বুল মান, অভিব্যক্তি বা ফাংশন থাকতে হবে (যেমন আপনার নিয়ামক দ্বারা সংজ্ঞায়িত) যা নির্ধারণ করে যে নির্দেশটি যুক্ত করা উচিত কিনা।

আমিও ব্যবহার করছি attrs.$attr.dynamicDirectivesনির্দেশ (যেমন যোগ করতে ব্যবহার সঠিক অ্যাট্রিবিউট ঘোষণা পেতে data-dynamic-directive, dynamic-directiveজন্য চেক কঠিন-কোডিং স্ট্রিং মান ছাড়া)।

Plunker Demo

angular.module('plunker', ['ui.bootstrap'])
    .controller('DatepickerDemoCtrl', ['$scope',
        function($scope) {
            $scope.dt = function() {
                return new Date();
            };
            $scope.selects = [1, 2, 3, 4];
            $scope.el = 2;

            // For use with our dynamic-directive
            $scope.selectIsRequired = true;
            $scope.addTooltip = function() {
                return true;
            };
        }
    ])
    .directive('dynamicDirectives', ['$compile',
        function($compile) {
            
             var addDirectiveToElement = function(scope, element, dir) {
                var propName;
                if (dir.if) {
                    propName = Object.keys(dir)[1];
                    var addDirective = scope.$eval(dir.if);
                    if (addDirective) {
                        element.attr(propName, dir[propName]);
                    }
                } else { // No condition, just add directive
                    propName = Object.keys(dir)[0];
                    element.attr(propName, dir[propName]);
                }
            };
            
            var linker = function(scope, element, attrs) {
                var directives = scope.$eval(attrs.dynamicDirectives);
        
                if (!directives || !angular.isArray(directives)) {
                    return $compile(element)(scope);
                }
               
                // Add all directives in the array
                angular.forEach(directives, function(dir){
                    addDirectiveToElement(scope, element, dir);
                });
                
                // Remove attribute used to add this directive
                element.removeAttr(attrs.$attr.dynamicDirectives);
                // Compile element to run other directives
                $compile(element)(scope);
            };
        
            return {
                priority: 1001, // Run before other directives e.g.  ng-repeat
                terminal: true, // Stop other directives running
                link: linker
            };
        }
    ]);
<!doctype html>
<html ng-app="plunker">

<head>
    <script src="//code.angularjs.org/1.2.20/angular.js"></script>
    <script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.6.0.js"></script>
    <script src="example.js"></script>
    <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet">
</head>

<body>

    <div data-ng-controller="DatepickerDemoCtrl">

        <select data-ng-options="s for s in selects" data-ng-model="el" 
            data-dynamic-directives="[
                { 'if' : 'selectIsRequired', 'ng-required' : '{{selectIsRequired}}' },
                { 'tooltip-placement' : 'bottom' },
                { 'if' : 'addTooltip()', 'tooltip' : '{{ dt() }}' }
            ]">
            <option value=""></option>
        </select>

    </div>
</body>

</html>


অন্য নির্দেশের টেম্পলেট ব্যবহৃত হয়। এটি ঠিক কাজ করে আমার সময় সাশ্রয় করে। শুধু ধন্যবাদ।
jcstritt

4

আমি আমার সমাধান যুক্ত করতে চেয়েছিলাম যেহেতু গৃহীত একজন আমার পক্ষে যথেষ্ট কাজ করে না।

আমার একটি নির্দেশিকা যুক্ত করার প্রয়োজন ছিল তবে উপাদানটিতে আমার নজর রাখা দরকার।

এই উদাহরণে আমি উপাদানটিতে একটি সাধারণ এনজি-স্টাইল নির্দেশিকা যুক্ত করছি। অসীম সংকলন লুপগুলি রোধ করতে এবং আমাকে আমার নির্দেশনা রাখার অনুমতি দেওয়ার জন্য আমি যুক্ত করেছিলাম যা উপাদানটি পুনরায় সংবিধানের আগে উপস্থিত ছিল কিনা তা পরীক্ষা করার জন্য।

angular.module('some.directive', [])
.directive('someDirective', ['$compile',function($compile){
    return {
        priority: 1001,
        controller: ['$scope', '$element', '$attrs', '$transclude' ,function($scope, $element, $attrs, $transclude) {

            // controller code here

        }],
        compile: function(element, attributes){
            var compile = false;

            //check to see if the target directive was already added
            if(!element.attr('ng-style')){
                //add the target directive
                element.attr('ng-style', "{'width':'200px'}");
                compile = true;
            }
            return {
                pre: function preLink(scope, iElement, iAttrs, controller) {  },
                post: function postLink(scope, iElement, iAttrs, controller) {
                    if(compile){
                        $compile(iElement)(scope);
                    }
                }
            };
        }
    };
}]);

এটি লক্ষণীয় যে আপনি এটি ট্রান্সক্লোকড বা কোনও টেম্পলেট দিয়ে ব্যবহার করতে পারবেন না, কারণ সংকলক দ্বিতীয় রাউন্ডে সেগুলি পুনরায় প্রয়োগ করার চেষ্টা করে।
spikyjt

1

উপাদানটিকে নিজেই কোনও বৈশিষ্ট্যে রাষ্ট্র সংরক্ষণের চেষ্টা করুন superDirectiveStatus="true"

উদাহরণ স্বরূপ:

angular.module('app')
  .directive('superDirective', function ($compile, $injector) {
    return {
      restrict: 'A',
      replace: true,
      link: function compile(scope, element, attrs) {
        if (element.attr('datepicker')) { // check
          return;
        }
        var status = element.attr('superDirectiveStatus');
        if( status !== "true" ){
             element.attr('datepicker', 'someValue');
             element.attr('datepicker-language', 'en');
             // some more
             element.attr('superDirectiveStatus','true');
             $compile(element)(scope);

        }

      }
    };
  });

আমি আশা করি এটা আপনাকে সাহায্য করবে।


ধন্যবাদ, প্রাথমিক ধারণাটি একই থাকে :)। আমি প্রথম সংকলন পাস এড়িয়ে যাওয়ার একটি উপায় বের করার চেষ্টা করছি। আমি মূল প্রশ্নটি আপডেট করেছি।
ফ্রেপন্টিলো

ডাবল সংকলনটি একটি ভয়াবহ উপায়ে জিনিসগুলি ভেঙে দেয়।
ফ্রেপন্টিলো

1

1.3.x থেকে 1.4.x এ পরিবর্তন হয়েছিল।

কৌণিক 1.3.x এ এটি কাজ করেছে:

var dir: ng.IDirective = {
    restrict: "A",
    require: ["select", "ngModel"],
    compile: compile,
};

function compile(tElement: ng.IAugmentedJQuery, tAttrs, transclude) {
    tElement.append("<option value=''>--- Kein ---</option>");

    return function postLink(scope: DirectiveScope, element: ng.IAugmentedJQuery, attributes: ng.IAttributes) {
        attributes["ngOptions"] = "a.ID as a.Bezeichnung for a in akademischetitel";
        scope.akademischetitel = AkademischerTitel.query();
    }
}

এখন কৌণিক 1.4.x এ আমাদের এটি করতে হবে:

var dir: ng.IDirective = {
    restrict: "A",
    compile: compile,
    terminal: true,
    priority: 10,
};

function compile(tElement: ng.IAugmentedJQuery, tAttrs, transclude) {
    tElement.append("<option value=''>--- Kein ---</option>");
    tElement.removeAttr("tq-akademischer-titel-select");
    tElement.attr("ng-options", "a.ID as a.Bezeichnung for a in akademischetitel");

    return function postLink(scope: DirectiveScope, element: ng.IAugmentedJQuery, attributes: ng.IAttributes) {

        $compile(element)(scope);
        scope.akademischetitel = AkademischerTitel.query();
    }
}

(গৃহীত উত্তর থেকে : https://stackoverflow.com/a/19228302/605586 থেকে খান টো)।


0

একটি সহজ সমাধান যা কিছু ক্ষেত্রে কাজ করতে পারে তা হ'ল একটি মোড়ক তৈরি করা এবং then তারপরে আপনার মূল উপাদানটি সংযোজন করা।

কিছুটা এইরকম...

link: function(scope, elem, attr){
    var wrapper = angular.element('<div tooltip></div>');
    elem.before(wrapper);
    $compile(wrapper)(scope);
    wrapper.append(elem);
}

এই সমাধানটির সুবিধা রয়েছে যে এটি আসল উপাদানটি পুনরায় সংশোধন না করে জিনিসগুলি সহজ রাখে।

যুক্ত নির্দেশাবলীর যদি কোনও requireআসল উপাদানটির দিকনির্দেশনা থাকে বা যদি মূল উপাদানটির পরম অবস্থান থাকে তবে এটি কাজ করবে না ।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.