web-dev-qa-db-fra.com

Angular (1.5.8) Composants dynamiques

J'essaie de créer une sorte de tableau de bord dynamique en utilisant Angular 1.5.8. J'ai fait des progrès décents jusqu'au dernier obstacle. Ce qui rend réellement le composant dynamique. 

J'ai essayé 2 options, soit en ajoutant un ui-view et en transmettant par programme le nom du widget, ou , et c'est la route que je suppose est plus correct, je dois comprendre comment rendre un widget dynamique.

Par exemple: Lorsque j'ajoute un élément à la collection dashItems, il doit générer un nouveau widget (basé sur le nom que j'ai fourni).

J'ai vu que je pouvais échanger des modèles en utilisant ngInclude, mais je ne sais toujours pas comment obtenir un modèle et un contrôleur à injecter de manière dynamique. (Par exemple, tous mes modèles ne partageront pas un contrôleur commun).

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

Balisage (tableau de bord/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>

Des questions):

1 . J'ai examiné ngInclude, mais pour être parfaitement honnête, je ne suis pas sûr de savoir comment l'utiliser dans ce cas, et SI c'est le bon outil pour cela, ou est-ce que je l'aborde de manière incorrecte?

2 . Si je devais même ajouter des éléments au fournisseur d’État pour cela, par exemple, un i/un widget pourrait-il être considéré comme un état enfant (je ne suis donc pas sûr de ce qui serait considéré comme une pratique exemplaire)

16
Rohan Büchner

J'ai fini par changer le fichier dashboard.tpl.html en:

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

Mais je devais aussi ajouter une tâche de construction pour parcourir mon dossier de widgets et générer ce qui suit (ou vous pouvez ajouter manuellement tout ce qui flotte, je suppose).

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

Ce qui précède me permet d’utiliser soit templateUrl, soit des modèles en ligne.

.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');
    }
})
19
Rohan Büchner

Tu peux le faire. Tout d'abord, vous devez utiliser le composant wrapper qui vous aide à compiler votre composant dynamique:

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: '=?'
        }
    });

votre composante dynamique:

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

et alors:

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