0

The following is a template that works to the point that webix-ui directive points to childscope because it is inside of an ng-if...

I need ng-if to wait for the $scope.init() to finish getting data before I intitalize the ui component configuration objects.

How do I point to scope, not childscope in my webix-ui directive?

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

This points to scope properly as it is not nested in ng-if

angular.module('Risk').directive('getRisk', getRisk); 

function getRisk(){
     return {
            restrict: 'A',
            controller: function ($scope, $http, $sce){

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

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

                $scope.initDone = false;

                $scope.init = function(){
                      angular.element(document.querySelector('link[href="/app/tool/risk/CreateRisk.css"]')).remove();
                      angular.element(document.querySelector('head')).append('<link type="text/css" rel="stylesheet" href="/app/tool/risk/CreateRisk.css"/>'); 

                      return $http.get('/api/riskconfig').then(function(response){
                           if (response.data.Succeeded){
                                $scope.risklevels.riskmaximum = response.data.Result.Levels[0].riskmaximum;
                                $scope.risklevels.riskhigh = response.data.Result.Levels[0].riskhigh;
                                $scope.risklevels.riskmedium = response.data.Result.Levels[0].riskmedium;
                                $scope.risklevels.riskminimum = response.data.Result.Levels[0].riskminimum; 


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

                                return response.data.Result;
                           }
                           else{
                                $scope.msg = $sce.trustAsHtml(response.data);
                           }
                      });
                } 

                $scope.init().then(function(){
                    $scope.initDone = true;
                    return $scope.initDone;
                });
            } 
     }  
}

Currently This Points to ChildScope (should point to Scope Instead) because it is nested inside ng-if in template

angular.module('Risk').directive('webixUi', WebixElement);

function WebixElement(DOMops, ValidationService){                   
      var directive = {
            restrict: 'A',
            link: linkFn,
            controller: webixUiController,
            bindToController: true
      }

      function linkFn(scope, element, attrs) {                       
      }

      return directive;            
}


function webixUiController($scope, $attrs, DOMops, ValidationService){
    var attr = $attrs.name;
    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: $scope.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};
    $scope.config[$attrs.name] = config; 
} 
georgeawg
  • 48,608
  • 13
  • 72
  • 95
Vahe
  • 1,699
  • 3
  • 25
  • 76
  • I am trying to make all directives part of `scope` and not `childscope` on the entire template. – Vahe May 29 '19 at 22:41

1 Answers1

0

One approach to setting values from an attribute component is to use scope.$eval to manually evaluate an expression attribute:

$scope.$eval($attrs.onConfig, {$config: config}); 

Usage:

<div webix-ui="config.risktitle" width="500" 
     height="30" type="text" id="risktitle"
     name="risktitle" on-config="config.risktitle = $config">
</div>

When the directive initializes, it evaluates the expression in the on-config attribute with $config as a local.

Scope inheritance is normally straightfoward... until you need 2-way data binding (i.e., form elements, ng-model) in the child scope. Ng-repeat, ng-switch, and ng-include can trip you up if you try to bind to a primitive (e.g., number, string, boolean) in the parent scope from inside the child scope. It doesn't work the way most people expect it should work. The child scope gets its own property that hides/shadows the parent property of the same name.

The way to make it work is to define objects in the parent for your model, then reference a property of that object in the child.

So in the parent controller define the object:

 $scope.config = {};

This follows the best practice of "always have a '.' in your models".

For more information, see

georgeawg
  • 48,608
  • 13
  • 72
  • 95
  • $scope.config = {} is actually already present in my module controller as I read up on using dot method for my model. The only question is, are both the eval and the scope.config needed together? – Vahe May 30 '19 at 01:59
  • Also `$scope.init().then(function(){ $scope.initDone = true })` already exists in my code so how do I use `$scope.initDone` in a more proper way than `ng-if` method I am using in my question? Basically I want to wait for a scope variable to be true then evaluate a statement i.e. $scope.someConfig = config object; – Vahe May 30 '19 at 02:01
  • https://stackoverflow.com/questions/28388452/load-directive-after-ajax-call is what I am trying to do but doing so is causing this isolated scope. – Vahe May 30 '19 at 20:29