angularjsangularjs-controlleras

Unable to use controller as syntax to set up directive (scope mismatch)


I am pulling my hair out trying to get a directive called webix-ui to assume the same scope level as parent scope. This code is the closest to making webix-ui work, but the element still sees childscope.

What am I doing wrong and why is my controller as not being picked up globally?

I am nearing the point of giving up as I have tried nearly 10-15 variations of my code, this one being the most promising and hopefully in the right direction.

I can provide additional details as necessary.

Module Controller

angular.module('Risk').controller('CreateRiskController', ['$http', '$resource', '$scope', '$state', '$window', '$timeout', '$interval', '$sce', 'CommonService', function($http, $resource, $scope, $state, $window, $timeout, $interval, $sce, CommonService){
    refresh = false;
    var vm = this;
    vm.config = {}
    vm.initDone = false;
    vm.setup = {
        done: false
    }
    vm.model = { elem: true }

    vm.risk = {
        risktitle: '',
        riskstatement: '',
        context: '',
        closurecriteria: '',
        likelihood:'',
        technical:'',
        schedule:'',
        cost:''
     }; 

    vm.fields = [   
        'risktitle',
        'riskstatement',
        'context',
        'closurecriteria',
        'likelihood',
        'technical',
        'schedule',
        'cost'
    ]

    vm.risklevels = {
        riskmaximum: '',
        riskhigh: '',
        riskmedium: '',
        riskminimum: ''
    }

    vm.flags = {
        disabled: true
    }

    vm.riskMatrix = [];
    for(var l = 1; l <= 5; l++)
    {
        vm.riskMatrix[l] = [];
        for (var c = 0; c <= 5; c++)
        {
            vm.riskMatrix[l][c] = '';  
        }
    }

    vm.riskLevel = function(l, c){
        elem = document.querySelector("div[name='risk["+l+"]["+c+"]']");
        risk = vm.riskMatrix[l][c];
        if (risk == '')
            return (elem && elem.hasAttribute('class'))?
                    elem.getAttribute('class') : ''; 

        if (risk >= vm.risklevels.riskhigh) 
            return 'cell high';
        else if (risk >= vm.risklevels.riskmedium && risk < vm.risklevels.riskhigh)
            return 'cell med';
        else if (risk < vm.risklevels.riskmedium)
            return 'cell low';
    }


    vm.valid = function(){          
        return CommonService.riskFormValid(vm.fields, vm);
    }

    vm.invalidLevel = function(lvl){
        return CommonService.invalidLevel(lvl);
    }

    $scope.$on("$destroy", function(){
         formcheck = 0;
         angular.element(document.querySelector('link[href="/app/tool/risk/CreateRisk.css"]')).remove();   
    });

    vm.initRisk = function(data){
        vm.risklevels.riskmaximum = data.Levels[0].riskmaximum;
        vm.risklevels.riskhigh = data.Levels[0].riskhigh;
        vm.risklevels.riskmedium = data.Levels[0].riskmedium;
        vm.risklevels.riskminimum = data.Levels[0].riskminimum; 


        for (var idx = 0; idx < data.Thresholds.length; idx++)
        {
            var l = data.Thresholds[idx].likelihood;
            var c = data.Thresholds[idx].consequence;
            v = data.Thresholds[idx].level;
            vm.riskMatrix[l][c] = v;
        }
    }

    vm.init = function(){      
          return $http.get('/api/riskconfig').then(function(response){
               if (response.data.Succeeded){
                    vm.initRisk(response.data.Result);
                    return response.data.Result;
               }
               else{
                    vm.msg = $sce.trustAsHtml(response.data);
               }
          });
    } 

    vm.submit = function(){
        if (!vm.valid())
             vm.msg = "Please complete form and resubmit";
        else{ 
            //vm.actionitem.duedate = vm.split(vm.actionitem.duedate,'T')[0];
            //vm.actionitem.ecd = vm.split(vm.actionitem.ecd, 'T')[0];
            $http.post('/api/risks', vm.risk).then(function(response){
                if (response.data.Succeeded){
                    vm.msg = response.data.Result;
                }
                else{
                    vm.msg = $sce.trustAsHtml(response.data);
                }
            });
        } 
    }
}]);

Directive

angular.module('Risk').directive('config', ConfigElement);

function ConfigElement(){
      var directive = {
            restrict: 'A',
            compile: function (){
                return {
                    pre: function (scope, elem, attrs){
                        var vm = scope.vm;
                        vm.config[attrs.config] = {done: false} 
                    },
                    post: ConfigController
                }
            },
            controller: 'CreateRiskController',
            controllerAs: 'vm',
            bindToController: true,
            scope: false
      }
      return directive;     
}                    

function ConfigController(scope, element, attrs, DOMops, ValidationService){
   //$scope.$watch('setup.done', function(dataReady,dataNotReady,scope){
   //    if (dataReady){
            var vm = scope.vm;

            var attr = attrs.config;
            var type = attrs.type;
            var width = attrs.width;
            var height = attrs.height;
            var maxlength = attrs.hasOwnProperty('maxlength')? attrs.maxlength: null;  

            var view;
            if (type == "level")
                view = "text";
            else
                view = type;

            var config = 
            {
                view: view,
                value: vm.risk[attr],      
                on: {
                    "onTimedKeyPress": function(code){  
                        var obj = this.eventSource || this; 
                        ValidationService.handleKeyPress(obj, code, attr);
                        if (type == "level")
                            DOMops.assignRiskLevel(scope, obj); 
                    },
                    "onBlur": function(code){  
                        var obj = this.eventSource || this;  
                        ValidationService.updateAndValidate(obj,code,attr); 
                    }
                },
                responsive: true,
                width: width,
                height: height
            };
            if (maxlength)
                config.attributes = {maxlength : maxlength};
            config.done = true;
            vm.config[attr] = config;
            //$scope.$eval($attrs.onConfig, {$config: $scope.config[$attrs.name]});                    
     // }
   //});  
}  

Template

   <div id="formcontainer" ng-app="Risk" ng-controller="CreateRiskController as vm" get-risk>
        <div id="mycreateform" class="container" type="space" layout-padding="" ng-cloak="">     
            <form id="form" name="CreateRisk" role="form" ng-submit="vm.valid() && vm.submit()" novalidate>
                <div id="details" class="layout" border="1">                               
                    <div class="tr">
                        <div class="td label">
                            Title
                        </div>
                        <div config="risktitle" class="td locked" width="500" height="30" type="text">
                            <div ng-if="vm.config.risktitle.done" ng-model="vm.config.risktitle" webix-ui="vm.config.risktitle" id="risktitle" name="risktitle"></div>
                        </div>
                    </div>
                    <div class="tr">    
                        <div class="td label">
                            Risk Statement
                        </div>
                        <div config="riskstatement" class="td locked" width="500" height="97" type="textarea">
                            <div ng-if="vm.config.riskstatement.done" ng-model="vm.config.riskstatement" webix-ui="vm.config.riskstatement"  id="riskstatement" name="riskstatement"></div>
                        </div>
                    </div>
                    <div class="tr">
                        <div class="td label">
                            Context
                        </div>
                        <div config="context" width="500" height="97" type="textarea" class="td locked">
                            <div ng-if="vm.conig.context.done"  ng-model="vm.config.context" webix-ui="vm.config.context" id="context" name="context"></div>
                        </div>
                    </div>
                    <div class="tr">
                        <div class="td label">
                            Closure Criteria
                        </div>
                        <div config="closurecriteria" width="500" height="97" type="textarea" class="td locked">
                            <div ng-if="vm.config.closurecriteria.done"  ng-model="vm.config.closurecriteria" webix-ui="vm.config.closurecriteria" id="closurecriteria" name="closurecriteria"></div>
                        </div>
                    </div>
                     <!--tr class="text">
                            <div class="td label">
                                Category
                            </div>
                            <div class="locked">
                                 <div id="category" name="category" />
                            </div>
                      </div-->
                </table>
                <h2>Initial Risk Assessment</h2>
                <div class="nested">
                    <div class="info">
                        <div id="details" class="table" border="1">
                            <div class="tr">
                                <div class="td label">
                                    Likelihood
                                </div>
                                <div config="likelihood" width="30" height="30" maxlength="1" type="level" class="td locked">                   
                                    {{config.likelihood}}<div ng-if="vm.config.likelihood.done" ng-model="vm.config.likelihood" webix-ui="vm.config.likelihood" id="likelihood" name="likelihood"></div>
                                </div>
                            </div>
                            <div class="tr">
                                <div class="td label" colspan="2">
                                    Consequence
                                </div>
                            </div>
                             <div class="tr">
                                <div class="td label margin-left">
                                    Technical
                                </div>
                                <div config="technical" width="30" height="30" type="level" maxlength="1" class="td locked">
                                    {{config.technical}}<div ng-if="vm.config.technical.done" ng-model="vm.config.technical" webix-ui="vm.config.technical" id="technical" name="technical"></div>
                                </div>                                                        
                            </div>
                             <div class="tr">
                                <div class="td label margin-left">
                                    Schedule
                                </div>
                                <div config="schedule" width="30" height="30" type="level" maxlength="1" class="td locked">
                                    {{config.schedule}}<div ng-if="vm.config.webix" ng-model="vm.config.schedule" webix-ui="vm.config.schedule"  id="schedule" name="schedule"></div>
                                </div>
                            </div>
                             <div class="tr">
                                <div class="td label margin-left">
                                    Cost
                                </div>
                                <div config="cost" width="30" height="30" type="level" maxlength="1" class="td locked">
                                    {{config.cost}}<div ng-if="vm.config.cost.done"  ng-model="vm.config.cost" webix-ui="vm.config.cost" id="cost" name="cost"></div>
                                </div>
                            </div>
                        </div>
                         <div name="level"></div>
                    </div> 
                    &nbsp;&nbsp;    
                    <div class="info" ng-if="vm.setup.done">
                        <table class="matrix" id="riskmatrix">
                        <tbody>
                        <tr ng-repeat="likelihood in [5,4,3,2,1]">
                                <td ng-if="likelihood == 2" class="vlabel">Likelihood</td>
                                <td ng-if="likelihood != 2"></td>
                                <td class="likelihood">{{likelihood}}</td>
                                <td ng-repeat="consequence in [1,2,3,4,5]" name="risk[{{likelihood}}][{{consequence}}]" ng-model="vm.riskMatrix[likelihood][consequence]" ng-class="[vm.riskLevel(likelihood,consequence)]"></td>
                        </tr>
                        <tr>
                                <td></td>
                                <td></td>
                                <td ng-repeat="consequence in [1,2,3,4,5]">{{consequence}}</td>
                        </tr>
                        <tr>
                            <td></td><td></td><td colspan="5">Consequence</td> 
                        </tr>  
                        </tbody></table>
                    </div>
                     &nbsp;&nbsp;   
                </div>
            <divider></divider>
            <div class="tr">
                <div class="tr">
                  <button id="submit" type="submit" disabled="disabled" class="raised primary">Create Risk</button>
                </div>
            </div>
            <div class="tr">
              <div class="msg" layout-align="center">
                <span ng-bind-html="msg">{{msg}}</span>
              </div>
            </div>
            </form>
        </div>
    </div>

Solution

  • Initializing my div directive with an object whose property was initially false and then using "as ctrl" in my template solved the issue finally. I had to use this in my controller and scope.ctrl.<property> in. It seems to have worked similar to the syntax as many references places suggesting use of this pointer instead of $scope. The only thing that I changed was use of ng-show instead of ng-if. I have not used ng-if but I suspect it might still work too.

    <div id="formcontainer" ng-app="Risk" ng-controller="CreateRiskController as ctrl" ng-cloak>
        <get-risk></get-risk>
        <div id="mycreateform" class="container" type="space" layout-padding="">     
            <form id="form" name="CreateRisk" role="form" ng-submit="ctrl.valid() && ctrl.submit()" novalidate>
                <table id="details" class="layout" border="1">
                    <tr>
                        <td class="label">
                            Title
                        </td>
                        <td class="locked">
                            <div ng-show="ctrl.config.risktitle.done" config="risktitle" webix-ui="risktitle" width="500" height="30" type="text" id="risktitle" name="risktitle"></div>
                        </td>
                    </tr>
                 </table>
            </form>
        </div>
    </div>
    

    Directive

    angular.module('Risk').directive('config', ConfigElement);
    
    function ConfigElement(){
          var directive = {
                restrict: 'A',
                link: linkFn,
                controller: ConfigController
          }
    
          function linkFn(scope, elem, attrs){
                var attr = attrs.config;
                var type = attrs.type;
                var width = attrs.width;
                var height = attrs.height;
                var maxlength = attrs.hasOwnProperty('maxlength')? attrs.maxlength: null;  
    
                var view;
                if (type == "level")
                    view = "text";
                else
                    view = type;
    
                scope.ctrl.DOMops.setValidationServiceObj(scope.ctrl.ValidationService);
                scope.ctrl.DOMops.setValue('risk', scope.ctrl.risk);
                scope.ctrl.DOMops.setValue('riskMatrix', scope.ctrl.riskMatrix);   
                scope.ctrl.DOMops.setValue('risklevels', scope.ctrl.risklevels);
    
                scope.ctrl.ValidationService.setValue('risk', scope.ctrl.risk);
                scope.ctrl.ValidationService.setDOMobj(scope.ctrl.DOMops);
    
                var config = 
                {
                    view: view,
                    value: scope.ctrl.risk[attr],      
                    on: {
                        "onTimedKeyPress": function(){  
                            var obj = this.eventSource || this; 
                            code = this.getValue();
                            scope.ctrl.ValidationService.handleKeyPress(code, scope.ctrl, obj, attr);
                            if (type == "level")
                                scope.ctrl.DOMops.assignRiskLevel(obj); 
                        },
                        "onBlur": function(){  
                            var obj = this.eventSource || this;  
                            code = this.getValue();
                            scope.ctrl.ValidationService.getTextValueAndValidate(code, scope.ctrl, obj, attr); 
                        }
                    },
                    responsive: true,
                    width: width,
                    height: height
                };
                if (maxlength)
                    config.attributes = {maxlength : maxlength};
                config.done = true;
                scope.ctrl.config[attr] = config;
          }
    
          return directive;     
    }
    
    
    function ConfigController($scope, $element, $attrs){
        $scope.ctrl.config[$attrs.config] = {done: false};
    }