AngularJs directive with dynamic controller and template

I want to create a dynamic view directive with a dynamic controller. the controller and view of the template come from the server.

Directive

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; } } } })(); 

This is how I try to use the directive

 <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> 

Now the problem is when the directive gets the name of the controller, it gets it as a literal string, not as a parameter.

Is this doable? if this is not possible, What is the best solution for creating dynamic views using your controllers and dynamically display them inside ng-repeat?

Thanks,

Update January 20 I just updated my code in case someone is interested in it. All credits are sent by @Meligy.

First directive:

 (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; } })(); 

Second directive

 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' }; }]); 

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> 
+5
source share
1 answer

Update:

I earned it, but it's really ugly. Check:

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

Your example has a lot of moving parts, so this one is simple, but it does what you want.

Basically, you need a shell directive that takes a JS object and converts it to a string property, then you can use هى your directive for everything else (template, scope, etc.).

.

Update 2:

Inline Code:

 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> 

.

Original (now irrelevant, but may help other related issues)

Yes, it should work.

Test with Angular 1.3:

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

What you need to check:

  • Is a controller defined and added to the module? This will not work

    If the controller is just a global function, it will not work. It must be added via the <myModule>.controller("<controllerName>", <functiion>) API

  • Does ng-controller ? Just adding it to the template

    Similarly, does the ng controller use directly outside of the directive?

+3
source

Source: https://habr.com/ru/post/1211401/


All Articles