AngularJS'ye dinamik olarak nasıl direktif ekleyebilirim?


212

Yaptığım şeyin çok kaygılı bir versiyonu var, bu da sorunu çözüyor.

Basit bir tane var directive. Bir öğeyi her tıkladığınızda, başka bir öğeyi ekler. Ancak, doğru bir şekilde oluşturulması için önce derlenmesi gerekir.

Araştırmam beni yönlendirdi $compile. Ancak tüm örnekler burada nasıl uygulanacağını bilmediğim karmaşık bir yapı kullanıyor.

Kemanlar burada: http://jsfiddle.net/paulocoelho/fBjbP/1/

Ve JS burada:

var module = angular.module('testApp', [])
    .directive('test', function () {
    return {
        restrict: 'E',
        template: '<p>{{text}}</p>',
        scope: {
            text: '@text'
        },
        link:function(scope,element){
            $( element ).click(function(){
                // TODO: This does not do what it's supposed to :(
                $(this).parent().append("<test text='n'></test>");
            });
        }
    };
});

Josh David Miller'ın çözümü: http://jsfiddle.net/paulocoelho/fBjbP/2/

Yanıtlar:


259

Orada çok anlamsız jQuery var, ama $ compile hizmeti bu durumda aslında süper basit :

.directive( 'test', function ( $compile ) {
  return {
    restrict: 'E',
    scope: { text: '@' },
    template: '<p ng-click="add()">{{text}}</p>',
    controller: function ( $scope, $element ) {
      $scope.add = function () {
        var el = $compile( "<test text='n'></test>" )( $scope );
        $element.parent().append( el );
      };
    }
  };
});

Bazı en iyi uygulamaları takip etmek için direktifinizi de yeniden düzenlediğimi fark edeceksiniz. Bunlardan herhangi biri hakkında sorularınız varsa bize bildirin.


34
Muhteşem. İşe yarıyor. Bakın, bu basit ve temel örnekler, açısal belgelerinde gösterilmesi gereken örneklerdir. Karmaşık örneklerle başlarlar.
PCoelho

1
Teşekkürler Josh, bu gerçekten işe yaradı. Plnkr'de, çocukların kodlamayı öğrenmelerine yardımcı olmak için yeni bir CoderDojo'da kullandığımız bir araç yaptım ve şimdi datepicker, alert, sekmeler vb.Gibi Açısal Bootstrap yönergelerini kullanabilmem için genişlettim. ve şu anda yalnızca Chrome'da çalışıyor: embed.plnkr.co/WI16H7Rsa5adejXSmyNj/preview
JoshGough

3
Josh - bunu kullanmadan yapmanın daha kolay yolu $compilenedir? Bu arada cevabınız için teşekkürler!
14'te 0:25

3
@doubleswirve Bu durumda, sadece ngRepeat kullanmak çok daha kolay olurdu. :-) Ancak, sayfaya dinamik olarak yeni yönergeler eklemek istediğinizi varsayalım, bu durumda cevap hayırdır - daha basit bir yol yoktur çünkü $compilehizmet direktifleri yukarı çeker ve olay döngüsüne bağlar. Böyle $compilebir durumda ing etrafında bir yol yoktur , ancak çoğu durumda ngRepeat gibi başka bir yönerge aynı işi başarabilir (böylece ngRepeat derlemeyi bizim için yapıyor). Belirli bir kullanım vakanız var mı?
Josh David Miller

2
Derleme prelink aşamasında olmamalı mı? Denetleyicinin yalnızca DOM olmayan, birim olarak test edilebilir kod içermesi gerektiğini düşünüyorum, ancak bağlantı / denetleyici kavramında yeniyim, bu yüzden kendimden emin değilim. Ayrıca, temel bir alternatif mi-include + kısmi + ng-denetleyicidir, çünkü miras kapsamı olan bir yönerge görevi görecektir .
Marcus Rådell

77

Mükemmel Riceball LEE'nin yeni bir element-yönergesi ekleme örneğine ek olarak

newElement = $compile("<div my-directive='n'></div>")($scope)
$element.parent().append(newElement)

Var olan öğeye yeni bir öznitelik yönergesi eklemek şu şekilde yapılabilir:

Let Diyelim ki on-the-fly eklemek istediğiniz demek my-directiveiçin spaneleman.

template: '<div>Hello <span>World</span></div>'

link: ($scope, $element, $attrs) ->

  span = $element.find('span').clone()
  span.attr('my-directive', 'my-directive')
  span = $compile(span)($scope)
  $element.find('span').replaceWith span

Umarım yardımcı olur.


3
Maksimum çağrı yığını boyutunun aşılmasını önlemek için orijinal yönergeyi kaldırmayı unutmayın.
SRachamim

Merhaba, programlı olarak ekleme direktiflerini daha basit bir işlem haline getirmek için yeni önerilen API'm hakkında fikir verir misiniz? github.com/angular/angular.js/issues/6950 Teşekkürler!
trusktr

Keşke 2015 yılında çağrı yığını boyutunda sınırlarımız olmasaydı. :(
psycho brm

3
Maximum call stack size exceededHata nedeniyle her zaman sonsuz özyinelemeye olur. Yığın boyutunu artırmanın bunu çözeceği bir örneği hiç görmedim.
Gunchars

Karşılaştığım benzer sorun, Bana burada yardımcı olabilir misiniz stackoverflow.com/questions/38821980/…
pandu das

45

Angularjs'e dinamik olarak yönergeler eklemenin iki stili vardır:

Angularjs yönergesini başka bir yönerge içine ekleme

  • yeni bir eleman ekleme (yönerge)
  • öğeye yeni bir özellik (yönerge) ekleme

yeni bir eleman ekleme (yönerge)

basit. Ve u "link" veya "compile" kullanabilirsiniz.

var newElement = $compile( "<div my-diretive='n'></div>" )( $scope );
$element.parent().append( newElement );

öğeye yeni bir özellik ekleme

Zor ve iki gün içinde başım ağrıyor.

"$ Compile" kullanmak kritik özyinelemeli hatayı artıracaktır !! Belki eleman yeniden derlenirken mevcut yönergeyi göz ardı etmelidir.

$element.$set("myDirective", "expression");
var newElement = $compile( $element )( $scope ); // critical recursive error.
var newElement = angular.copy(element);          // the same error too.
$element.replaceWith( newElement );

Yani, direktif "link" fonksiyonunu çağırmanın bir yolunu bulmalıyım. Kapakların derinliklerine gizlenmiş yararlı yöntemleri elde etmek çok zordur.

compile: (tElement, tAttrs, transclude) ->
   links = []
   myDirectiveLink = $injector.get('myDirective'+'Directive')[0] #this is the way
   links.push myDirectiveLink
   myAnotherDirectiveLink = ($scope, $element, attrs) ->
       #....
   links.push myAnotherDirectiveLink
   return (scope, elm, attrs, ctrl) ->
       for link in links
           link(scope, elm, attrs, ctrl)       

Şimdi, iyi çalışıyor.


1
Mümkünse vanilya JS'de elemente yeni bir özellik ekleme demosunu görmek isterdim - Bir şey eksik ...
Patrick

öğeye yeni bir özellik eklemenin
LEE

1
Dürüst yardım etmiyor.
Patrick

Evet, bu durum bir öznitelik yönergesini başka bir yönerge içine eklemektir, şablondaki ekleme öğesini değil.
Riceball LEE

Bunu şablonun dışında yapmanın ardındaki neden nedir?
Patrick

9
function addAttr(scope, el, attrName, attrValue) {
  el.replaceWith($compile(el.clone().attr(attrName, attrValue))(scope));
}

5

Josh David Miller'ın kabul ettiği cevap, satır içi kullanan dinamik bir yönerge eklemeye çalışıyorsanız harika çalışıyor template. Ancak direktifiniz templateUrlcevabından yararlanırsa işe yaramaz. İşte benim için işe yarayan:

.directive('helperModal', [, "$compile", "$timeout", function ($compile, $timeout) {
    return {
        restrict: 'E',
        replace: true,
        scope: {}, 
        templateUrl: "app/views/modal.html",
        link: function (scope, element, attrs) {
            scope.modalTitle = attrs.modaltitle;
            scope.modalContentDirective = attrs.modalcontentdirective;
        },
        controller: function ($scope, $element, $attrs) {
            if ($attrs.modalcontentdirective != undefined && $attrs.modalcontentdirective != '') {
                var el = $compile($attrs.modalcontentdirective)($scope);
                $timeout(function () {
                    $scope.$digest();
                    $element.find('.modal-body').append(el);
                }, 0);
            }
        }
    }
}]);

5

Josh David Miller doğru.

PCoelho, $compileSahnelerin arkasında neler yaptığını ve direktiften HTML çıktısının nasıl oluşturulduğunu merak ediyorsanız , lütfen aşağıya bir göz atın

$compileHizmet HTML (fragmanını derler "< test text='n' >< / test >"direktifi (bir unsur olarak "test") içerir ve bir işlev üretir). Bu işlev daha sonra "bir yönergeden HTML çıktısı" almak için bir kapsamla yürütülebilir.

var compileFunction = $compile("< test text='n' > < / test >");
var HtmlOutputFromDirective = compileFunction($scope);

Tam kod örnekleri ile daha fazla ayrıntı burada: http://www.learn-angularjs-apps-projects.com/AngularJs/dynamically-add-directives-in-angularjs


4

Önceki cevapların birçoğundan esinlenerek, kendisini diğer direktiflerle değiştirecek aşağıdaki "stroman" direktifini buldum.

app.directive('stroman', function($compile) {
  return {
    link: function(scope, el, attrName) {
      var newElem = angular.element('<div></div>');
      // Copying all of the attributes
      for (let prop in attrName.$attr) {
        newElem.attr(prop, attrName[prop]);
      }
      el.replaceWith($compile(newElem)(scope)); // Replacing
    }
  };
});

Önemli: Kullanmak istediğiniz yönergeleri kaydedin restrict: 'C'. Bunun gibi:

app.directive('my-directive', function() {
  return {
    restrict: 'C',
    template: 'Hi there',
  };
});

Bunun gibi kullanabilirsiniz:

<stroman class="my-directive other-class" randomProperty="8"></stroman>

Bunu elde etmek için:

<div class="my-directive other-class" randomProperty="8">Hi there</div>

PROTIP. Sınıflara dayalı yönergeler kullanmak istemiyorsanız, istediğiniz gibi değiştirebilirsiniz '<div></div>'. Örneğin, yerine istenen direktifin adını içeren sabit bir öznitelik var class.


Karşılaştığım benzer sorun, Bana burada yardımcı olabilir misiniz stackoverflow.com/questions/38821980/…
pandu das

AMAN TANRIM. bu $ derlemek bulmak için 2 gün sürdü ... teşekkürler arkadaşlar .. en iyi çalışıyor ... AJS sen salla ....
Srinivasan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.