Angular (1.5.8) Dynamic Components

▼魔方 西西 提交于 2019-12-03 05:06:56

问题


I'm trying to build a sort of dynamic dashboard using Angular 1.5.8. I've made decent progress up until the final hurdle. Which is actually rendering the dynamic component.

I've tried 2 options, either adding a ui-view and programatically passing in the name of the widget, or, and this is the route I'm guessing is more correct, I need to figure out how to render a dynamic widget.

For Example: As I append and item to the dashItems collection, it should render a new widget (based on the name I've provided)

I have seen that I can swap out templates using ngInclude, but I'm still unclear as to how to get a template and controller to be injected dynamically. (EG all my templates wont be sharing a common controller).

JavaScript:

angular
    .module('myDashboard', [])
    .config(routesConfig)
    .component('dashboard', {
        templateUrl: 'dashboard/dashboard.tpl.html',
        controller: dashboardController
    })
    .component('widgetPie', {
        template: '<h3>Pie Graph</h3>',
        controller: function($log) {
            $log.info('widgetPie: loaded');
        }
    })
    .component('widgetLine', {
        template: '<h3>Line Graph</h3>',
        controller: function($log) {
            $log.info('WidgetLine: loaded');
        }
    });

function routesConfig($stateProvider) {
    // this is only needed if I go the ui-view route.. I assume
    $stateProvider
        .state('widgetPie', { component: 'widgetPie'})
        .state('widgetLine', { component: 'widgetLine'});
}

function dashboardController($log) {
    $log.info('in dashboard');
    this.dashItems = [
        { widget:'widgetPie' },
        { widget:'widgetLine' }
    ];
}

Markup (dashboard/dashboard.tpl.html):

<div>
    <ul>
        <li ng-repeat="item in dashItems">
            <!--somehow render dynamic-->
            <!--<widget-pie></widget-pie>-->
            <!--<div ui-view="item.widget"></div>-->
        </li>
    </ul>
</div>

Question(s):

1. I've looked into ngInclude, but to be perfectly honest, I'm not sure how to go about using it in this instance, and IF it is the right tool for this, or am I approaching this incorrectly?

2. Should I even be adding items to the state provider for this, EG i / could a widget be seen as a child state (thus I'm not sure what would be seen as best practice)


回答1:


I ended up changing the dashboard.tpl.html file to:

<div>
    <ul>
        <li ng-repeat="item in dashItems">
            <div ng-include="item.widget"></div>
        </li>
    </ul>
</div>

But I also needed to add a build task to run through my widgets folder and generate the following (or you can manually add, whatever floats your boat I guess).

angular
 .module('myDashboard')
 .run(function ($templateCache) {
    $templateCache.put('widgetPie', '<widget-pie></widget-pie>');
    $templateCache.put('widgetLine', '<widget-line></widget-line>');
 });

The above allows me to either use templateUrl, or inline templates.

.component('widgetPie', {
   templateUrl: 'dashboard/widgetPie.tpl.html',
   controller: function($log) {
      $log.info('widgetPie: loaded');
   }
})
.component('widgetLine', {
    template: '<h1>Some Content</h1>',
    controller: function($log) {
      $log.info('widgetLine: loaded');
    }
})



回答2:


You can do it. Firstly, you need to use wrapper component which helps you compile your dynamic component:

app.component('dynamicWrapper',
    {
        controller: function widgetClientCtrl($scope, $compile, $element) {
                    var self = this;
                    self.$onInit = function () {
                          renderWidget(self.name, self.payload);
                    };
                    function renderWidget(name, payload) {
                          var template = '<' + name;

                          if (payload) {
                             $scope.payload = payload;
                             template += ' payload="payload"';
                          }

                          template += '></' + name + '>';
                          $element.append($compile(template)($scope));
                    }
        },
        bindings: {
            name: '@',
            payload: '=?'
        }
    });

your dynamic component:

app.component('someDynamicComponent', {
    templateUrl: 'yourPath',
    controller: dynamicComponentCtrl,
    controllerAs: 'vm',
    bindings: {
        payload: '<'
    }
});

and then:

<li ng-repeat="(name, payload) in vm.dynamicComponents">
      <dynamic-wrapper name="{{name}}" payload="payload"></dynamic-wrapper>
</li>


来源:https://stackoverflow.com/questions/40633648/angular-1-5-8-dynamic-components

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!