3
\$\begingroup\$

I have here a simple webapp for displaying different D3 demonstrations:

enter image description here enter image description here

The idea is - the user can select one of many modules in the control bar at the top, and the corresponding controls for that module will be displayed.

The image generated by each module will be displayed in the main area below the control bar.

Essentially - I want to be able to create each module independently, each with their own set of controls and drawing function.

To achieve this, I've created a ng-template script for each module's controller, and a corresponding controller and service for each module.

I then dynamically compile the template when the module is selected - using the technique outlined here.

HTML and Templates

<body ng-app="myapp" ng-controller="myctrl">


    <div id="header" class = "flex-right" >

        <div class="flex-down" >
            <input type="button" class="btn btn-info" ng-repeat="m in modules"
                ng-click="switchModule(m)" value="{{m.name}}"></input>
        </div>

        <div class ="flex-right" >      
            <dynamic-template template = "currentModule.template"/> 
        </div>


    </div>
    <div id="main">

    </div>

        <script type="text/ng-template" id="SpaceInvaders.html">
            <div ng-controller = "SpaceInvadersCtrl" class ="flex-right"> 
                <div class = "slider-container"> 
                                  <slider
                        ng-model = "speed"
                        min = "1"
                        max = "10"
                        value = "5"
                        on-stop-slide = "update()"
                        orientation ="vertical"/>
                </div>
            </div>
        </script>

        <script type="text/ng-template" id="Waves.html">            
            <button class = "btn">foo</button> 
            <button class ="btn"> bar</button>
            waves (more controls here).
            <!--more controller stuff here-->
        </script>

</body>

Main Controller

(function(){
    "use strict"
    var app = angular.module("myapp",['ui.bootstrap', 'ui.bootstrap-slider']);
    app.controller("myctrl", function($scope){

        $scope.modules = [{
                name: "Space Invaders", template: 'SpaceInvaders.html'
            },
            {
                name: "Waves", template: 'Waves.html'
            }

        ];

        $scope.switchModule = function(m){
            $scope.$broadcast("dj:moduleswitch");
            $scope.currentModule = m;
        }

        $scope.currentModule = $scope.modules[0];
        });     
}()); 

Dynamic Template directive

(function() {
    "use strict"

    angular.module("myapp").directive('dynamicTemplate', function($compile, $templateCache, $timeout) {

        var linker = function(scope, element, attrs) {

            scope.$on("dj:moduleswitch", function(){
                            //timeout to make the template compile
                            //after variables have updated
                $timeout(function(){
                    element.html($templateCache.get(scope.template));

                    $compile(element.contents())(scope);
                });
            });

            element.html($templateCache.get(scope.template));
            $compile(element.contents())(scope);
        };

        return {
            restrict : "E",
            link : linker,
            scope : {
                template : '='
            }
        };

    })
}());

Example module service and controller

(function() {
    "use strict"
    angular.module("myapp").service("SpaceInvaders", function() {

        this.execute = function(speed) {
                     d3.select("#main").selectAll("*").remove();
                     //snip for brevity - 
                     //but all logic pertaining to actually drawing the thing
                });



    })
    .controller("SpaceInvadersCtrl", function($scope, SpaceInvaders){
        $scope.speed = 5; 

        $scope.update =function(){
            SpaceInvaders.execute($scope.speed);
        };
    });
    ;

}());

My Questions

  1. The main thing I'm concerned about is the technique I've used for the solution - declaring a template, passing and passing it to the directive for runtime compile.

  2. The implementation of the directive seems a little messy - with that $broadcast required from the main controller, and the $timeout required to get the compilation to occur after selected module has changed.

  3. How do I name broadcasts?

  4. In my main controller, I need to know the names of corresponding templates for each module.

  5. In each of my d3 modules, they'll all need to know the id of the drawing area - #main.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.