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>
<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>
</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>
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};
}