Estensione della direttiva angolare


114

Vorrei apportare una piccola modifica a una direttiva di terze parti (in particolare Angular UI Bootstrap ). Voglio semplicemente aggiungere al campo di applicazione della panedirettiva:

angular.module('ui.bootstrap.tabs', [])
.controller('TabsController', ['$scope', '$element', function($scope, $element) {
  // various methods
}])
.directive('tabs', function() {
  return {
    // etc...
  };
})
.directive('pane', ['$parse', function($parse) {
  return {
    require: '^tabs',
    restrict: 'EA',
    transclude: true,
    scope:{
      heading:'@',
      disabled:'@' // <- ADDED SCOPE PROPERTY HERE
    },
    link: function(scope, element, attrs, tabsCtrl) {
      // link function
    },
    templateUrl: 'template/tabs/pane.html',
    replace: true
  };
}]);

Ma voglio anche tenere aggiornato Angular-Bootstrap con Bower. Non appena corro bower update, sovrascriverò le mie modifiche.

Allora come posso estendere questa direttiva separatamente da questa componente pergola?


2
Il modo più pulito sarebbe quello di utilizzare $provide.decorator(), vedere la mia risposta di seguito.
Eliran Malka

Risposte:


96

Probabilmente il modo più semplice per risolvere questo problema è creare una direttiva sulla tua app con lo stesso nome della direttiva di terze parti. Entrambe le direttive verranno eseguite ed è possibile specificare il loro ordine di esecuzione utilizzando la priorityproprietà (viene eseguita prima la priorità più alta).

Le due direttive condivideranno l'ambito e tu potrai accedere e modificare l'ambito della direttiva di terze parti tramite il linkmetodo della tua direttiva .

Opzione 2: puoi anche accedere all'ambito di una direttiva di terze parti semplicemente inserendo la tua direttiva con nome arbitrario sullo stesso elemento con essa (supponendo che nessuna delle due direttive utilizzi l'ambito isolato). Tutte le direttive di ambito non isolato su un elemento condivideranno l'ambito.

Ulteriori letture: https://github.com/angular/angular.js/wiki/Dev-Guide%3A-Understanding-Directives

Nota: la mia risposta precedente era per modificare un servizio di terze parti, non una direttiva.


3
grazie @ sh0ber, questo è esattamente quello di cui avevo bisogno. E anche la tua risposta precedente mi ha aiutato, riguardo ai servizi di terze parti.
Kyle

Ehi, questa risposta è davvero buona, ma non riesco a trovare alcuna documentazione sulla proprietà "priority" per le direttive. Tutto quello che ho trovato è stato un blurb che dice "puoi usarlo", ma non riesco a trovare alcun esempio reale di esso.
Ciel

2
@Ciel Le informazioni sull'API della direttiva sono state apparentemente spostate nel $compiledocumento qui
Dan

60

TL; DR - dammi la demo!


     Big Demo Button     
 


Usa $provide's decorator(), beh, decorare direttiva del terzo.

Nel nostro caso, possiamo estendere l'ambito della direttiva in questo modo:

app.config(function($provide) {
    $provide.decorator('paneDirective', function($delegate) {
        var directive = $delegate[0];
        angular.extend(directive.scope, {
            disabled:'@'
        });
        return $delegate;
    });
});

Per prima cosa, chiediamo di decorare la panedirettiva passando il suo nome, concatenato con Directivecome primo argomento, quindi lo recuperiamo dal parametro callback (che è un array di direttive che corrispondono a quel nome).

Una volta ottenuto, possiamo ottenere il suo oggetto ambito ed estenderlo secondo necessità. Notare che tutto questo deve essere fatto nel configblocco.

Alcune note

  • È stato suggerito di aggiungere semplicemente una direttiva con lo stesso nome, quindi impostarne il livello di priorità. Oltre ad essere antisemantico (che non è nemmeno una parola , lo so ...), pone problemi, ad esempio, cosa succede se il livello di priorità della direttiva di terze parti cambia?

  • JeetendraChauhan ha affermato (non l'ho testato però) che questa soluzione non funzionerà nella versione 1.13.


1
ti suggerisco di dare la risposta di @ sh0ber (crea un'altra direttiva solo per l'emissione di eventi).
Eliran Malka

2
Una breve nota su questa risposta (che funziona alla grande), la 'direttiva' in 'paneDirective' ha uno scopo ;-) Mi c'è voluto un po 'prima per capire che fuori: stackoverflow.com/questions/19409017/... , vedere la accettato risposta.
Roy Milder

2
ciao @EliranMalka controlla il mio plunker plnkr.co/edit/0mvQjHYjQCFS6joYJdwK spero che questo aiuterà qualcuno
Jeetendra Chauhan

1
Il collegamento decorator()è interrotto (aggiornato a docs.angularjs.org/api/auto/service/$provide#decorator )
Chris Brown,

1
@EliranMalka sì, è bindToControllerstato introdotto nella v1.3. Ma si noti che questa non è da considerarsi una soluzione alternativa, questo è solo per un caso specifico in cui la direttiva originale è stata impostata con la bindToControllerproprietà. Buona idea,
posterò

8

Sebbene questa non sia la risposta diretta alla tua domanda, potresti voler sapere che l'ultima versione (in master) di http://angular-ui.github.io/bootstrap/ ha aggiunto il supporto per la disabilitazione delle schede. Questa funzione è stata aggiunta tramite: https://github.com/angular-ui/bootstrap/commit/2b78dd16abd7e09846fa484331b5c35ece6619a2


+1 per l'avviso. buono a sapersi. Immagino che il bootstrap angolare di bower e il componente bootstrap di angular-ui non siano sincronizzati.
Kyle

6

Un'altra soluzione in cui si crea una nuova direttiva che la estende senza modificare la direttiva originale

La soluzione è simile alla soluzione del decoratore:

Crea una nuova direttiva e inserisci come dipendenza la direttiva che desideri estendere

app.directive('extendedPane', function (paneDirective) {

  // to inject a directive as a service append "Directive" to the directive name
  // you will receive an array of directive configurations that match this 
  // directive (usually only one) ordered by priority

  var configExtension = {
     scope: {
       disabled: '@'
     }
  }

  return angular.merge({}, paneDirective[0], configExtension)
});

In questo modo puoi utilizzare la direttiva originale e la versione estesa nella stessa app


2
Questo è fantastico, proprio quello di cui avevo bisogno per estendere una direttiva di ambito isolato con le mie variabili !! Ho scoperto che angular.extend non copia in profondità gli oggetti, quindi questo sostituisce l'oggetto scope di paneDirective con questo. Un'alternativa è angular.merge che manterrà l'ambito originale di PaneDirective e aggiungerà / unirà le variabili definite qui.
Mathewguest

1
sì, angular.mergeavrebbe dovuto essere usato, aggiornerò l'esempio
kidroca

1

Ecco un'altra soluzione per uno scenario diverso di estensione dei binding a una direttiva che ha la bindToControllerproprietà.

Nota: questa non è un'alternativa ad altre soluzioni che sono state offerte qui. Risolve solo un caso specifico (non trattato in altre risposte) con cui è stata istituita la direttiva originale bindToController.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.