5

Desidero creare una direttiva con vista dinamica con controller dinamico. il controller e la vista del modello provengono dal server.Direttiva AngularJs con controller dinamico e modello

La direttiva

var DirectivesModule = angular.module('BPM.Directives', []); 
(function() { 
    'use strict'; 

    angular 
     .module('BPM.Directives') 
     .directive('bpmCompletedTask', bpmCompletedTask); 

    bpmCompletedTask.$inject = ['$window']; 

    function bpmCompletedTask ($window) { 
     // Usage: 
     //  <bpmCompletedTask></bpmCompletedTask> 
     // Creates: 
     // 
     var directive = { 
      link: link, 
      restrict: 'E', 
      scope: { 
       type: '=', 
       taskdata: '=', 
       controllername:'@' 
      }, 
      template: '<div ng-include="getContentUrl()"></div>', 
      controller: '@', 
      name: 'controllername' 
      }; 
     return directive; 

     function link(scope, element, attrs) { 
      scope.getContentUrl = function() { 
       return '/app/views/TasksViews/' + scope.type + '.html'; 
      } 
      scope.getControllerName = function() 
      { 
       console.warn("Controller Name is " + scope.type); 
       return scope.type; 
      } 
     } 
    } 

})(); 

Ecco come sto cercando di utilizzare la direttiva

<div ng-controller="WorkflowHistoryController as vm"> 
    <h2>Workflow History</h2> 
    <h3>{{Id}}</h3> 
    <div ng-repeat="workflowStep in CompletedWorkflowSteps"> 
     <bpm-completed-task controllername="workflowStep.WorkflowTaskType.DataMessageViewViewName" taskdata="workflowStep.WorkflowTaskOutcome.TaskOutcome" type="workflowStep.WorkflowTaskType.DataMessageViewViewName"> 
     </bpm-completed-task> 
    </div>  
</div> 

Il problema ora è quando la direttiva prende il nome del controller lo ottengono stringa letterale non come parametro

È fattibile? se non è fattibile, qual è la soluzione migliore per creare viste dinamiche con i suoi controller e visualizzarle dinamicamente all'interno di ng-repeat?

Grazie,

Aggiornamento 20 gennaio Ho appena aggiornato il mio codice nel caso in cui se qualcuno interessato in esso. Tutto il credito va a @Meligy.

La prima direttiva:

(function() { 
    'use strict'; 

    angular 
     .module('BPM.Directives') 
     .directive('bpmCompletedTask', bpmCompletedTask); 

    bpmCompletedTask.$inject = ['$compile', '$parse']; 

    function bpmCompletedTask ($compile, $parse) { 
     var directive = { 
      link: function (scope, elem, attrs) { 
       console.warn('in the first directive - before if'); 
       if (!elem.attr('bpm-completed-task-inner')) 
       { 
        console.warn('in the first directive'); 
        var name = $parse(elem.attr('controllername'))(scope); 
        console.warn('Controller Name : ' + name); 
        elem = elem.removeAttr('bpm-completed-task'); 
        elem.attr('controllernameinner', name); 
        elem.attr('bpm-completed-task-inner', ''); 
        $compile(elem)(scope); 
       } 
      }, 
      restrict: 'A', 
      }; 
     return directive;   
    } 

})(); 

La seconda direttiva

angular 
.module('BPM.Directives') 
.directive('bpmCompletedTaskInner',['$compile', '$parse', 
function ($window, $compile, $parse) { 
    console.warn('in the second directive'); 
    return { 
     link: function (scope, elem, attrs) { 
      console.warn('in the second directive'); 
      scope.getContentUrl = function() { 
       return '/app/views/TasksViews/' + scope.type + '.html'; 
      } 
     }, 
     restrict: 'A', 
     scope: { 
      type: '=', 
      taskdata: '=', 
      controllernameinner: '@' 
     }, 
     template: '<div ng-include="getContentUrl()"></div>', 
     controller: '@', 
     name: 'controllernameinner' 
    }; 

}]); 

Il Html

<div ng-repeat="workflowStep in CompletedWorkflowSteps"> 
     <div bpm-completed-task controllername="workflowStep.WorkflowTaskType.DataMessageViewViewName" taskdata="workflowStep.WorkflowTaskOutcome.TaskOutcome" 
          type="workflowStep.WorkflowTaskType.DataMessageViewViewName"> 
     </div> 
    </div> 

risposta

3

Aggiornamento:

Ho funzionato, ma è davvero brutto. Controllare:

http://jsfiddle.net/p6Hb4/13/

Il vostro esempio ha un sacco di pezzi in movimento, quindi questo è semplice, ma fa quello che vuoi.

Fondamentalmente è necessaria una direttiva wrapper che prenda l'oggetto JS e la converta in una proprietà stringa, quindi è possibile utilizzare هى la propria direttiva per tutto il resto (modello, ambito, ecc.).

.

Aggiornamento 2:

codice inline:

var app = angular.module('myApp', []). 
 
directive('communicatorInner', ["$parse", "$compile", 
 
    function($parse, $compile) { 
 
    return { 
 
     restrict: 'A', 
 
     template: "<input type='text' ng-model='message'/><input type='button' value='Send Message' ng-click='sendMsg()'><br/>", 
 
     scope: { 
 
     message: '=' 
 
     }, 
 
     controller: '@' 
 
    }; 
 
    } 
 
]). 
 
directive('communicator', ['$compile', '$parse', 
 
    function($compile, $parse) { 
 
    return { 
 
     restrict: 'E', 
 
     link: function(scope, elem) { 
 
     if (!elem.attr('communicator-inner')) { 
 
      var name = $parse(elem.attr('controller-name'))(scope); 
 
      elem = elem.removeAttr('controller-name') 
 
      elem.attr('communicator-inner', name); 
 
      $compile(elem)(scope); 
 
     } 
 
     } 
 
    }; 
 
    } 
 
]). 
 
controller("PhoneCtrl", function($scope) { 
 
    $scope.sendMsg = function() { 
 
    alert($scope.message + " : sending message via Phone Ctrl"); 
 
    } 
 
}). 
 
controller("LandlineCtrl", function($scope) { 
 
    $scope.sendMsg = function() { 
 
    alert($scope.message + " : sending message via Land Line Ctrl "); 
 
    } 
 
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular.min.js"></script> 
 

 
<div ng-app="myApp"> 
 

 
<div ng-init="test = {p: 'PhoneCtrl', l: 'LandlineCtrl' }"> 
 
    <communicator controller-name="test.p" message="'test1'"></communicator> 
 
    <communicator controller-name="test.l"></communicator> 
 

 
</div> 
 
    
 
    
 
</div>

.

originale (irrilevante ora, ma può aiutare altre questioni connesse)

Sì, dovrebbe funzionare.

Un test con angolare 1.3:

http://jsfiddle.net/p6Hb4/9/

cose da controllare:

  • è il controller definito e ha aggiunto al modulo? Non funzionerà

    Se il controller è solo una funzione globale, non funzionerà. Deve essere aggiunto tramite l'API <myModule>.controller("<controllerName>", <functiion>)

  • ng-controller funziona? Aggiungilo al modello

    Allo stesso modo, l'utilizzo di ng-controller direttamente al di fuori della direttiva funziona?

+0

Grazie per la risposta Meligy. Il mio problema inizia quando il nome del controller è un valore oggetto non un testo semplice. Nell'esempio che hai condiviso pensi ai nomi dei controller che arrivano dal server e li sto passando alla direttiva come parametri. – Hammad

+0

Penso di aver trovato il problema. Controlla l'aggiornamento nella mia risposta – Meligy

+0

No, fermo. Vedi, la direttiva riceve correttamente il valore e inizia a cercare un controller chiamato "workflowStep.WorkflowTaskType.DataMessageViewViewName", tuttavia questo non è il mio controller e lui a cercare un controller dopo aver valutato il valore di questo oggetto. Ho provato il seguente ' ' e inoltre non funziona – Hammad

Problemi correlati