В значительной степени название говорит само за себя, но в целом я хочу переместить приведенные ниже функции ссылки в общее место, чтобы при нескольких экземплярах директивы у меня не было одного и того же набора функций ссылки для каждой директивы, а скорее набор функция ссылки в общем месте?
Как мне заставить это работать?
Директива
angular.module('Risk').directive('webixUi', WebixElement);
function WebixElement(){
return {
restrict: 'A',
scope: {
elem: '@'
},
controller: function($scope, CommonService){
$scope.getTextValue = function(obj, model, type, field){
CommonService.getTextValue(obj, model, type, field);
}
},
link: function (scope, element, attrs) {
function clearLevel(){
leveldiv = document.querySelector("div[name='level']");
leveldiv.innerHTML = '';
leveldiv.setAttribute('class', '');
}
function assignRiskLevel(obj){
l = scope.$parent.risk.likelihood;
t = scope.$parent.risk.technical;
s = scope.$parent.risk.schedule;
c = scope.$parent.risk.cost;
if (validLevel(obj) && riskNotEmpty(l,t,s,c))
{
if (riskIsValid(l,t,s,c))
{
l = Number(l);
tech = Number(t);
schd = Number(s);
cost = Number(c);
c = Math.max(tech,schd,cost);
displayLevel(scope.$parent.riskMatrix[l][c],l,c);
clearDot();
drawDot(l,c);
}
}
else
{
clearLevel();
clearDot();
}
}
function isLevelField(id){
return (id == 'likelihood' || id == 'technical' || id == 'schedule' || id == 'cost');
}
function clearValidation(id){
(document.querySelector('#'+id+ ' > div.webix_control')).classList.remove("webix_invalid");
}
function makeInvalid(id){
(document.querySelector('#'+id+' > div.webix_control')).classList.add("webix_invalid");
}
function validLevel(obj){
return obj.getValue().charCodeAt(0) - '0'.charCodeAt(0) >= 1
&& obj.getValue().charCodeAt(0) - '0'.charCodeAt(0) <= 5;
}
function riskIsValid(l,t,s,c){
var lvl = [l,t,s,c];
valid = true;
for (var idx = 0; idx < lvl.length; idx++)
if ((lvl[idx].charCodeAt(0) - '0'.charCodeAt(0) < 1) || (lvl[idx].charCodeAt(0) - '0'.charCodeAt(0) > 5))
valid = false;
return valid;
}
function riskNotEmpty(l, t, s, c){
if (l != '' && t != '' && s != '' && c != '')
return true;
return false;
}
function clearDot(){
levelDiv = document.querySelector("div.level");
if (levelDiv)
levelDiv.parentNode.removeChild(levelDiv);
}
function fieldEmpty(elem){
return elem.getValue() == '' || elem.getValue().trim() == '';
}
function formValid(){
for (var idx = 0; idx < scope.$parent.fields.length; idx++){
field = scope.$parent.fields[idx];
if (isLevelField(field) && !validLevel(scope.$parent.risk[field]))
return false;
else if (scope.$parent.risk[field] == '')
return false;
}
return true;
}
function validate(elem, id){
if (isLevelField(id) && (!validLevel(elem) || fieldEmpty(elem))){
makeInvalid(id);
clearDot();
}
else if (typeof elem !== 'undefined' && (elem.getValue() == 0 || fieldEmpty(elem)))
makeInvalid(id);
if (formValid())
enableElement("#submit");
else
disableElement("#submit");
}
function enableElement(id){
(document.querySelector(id)).removeAttribute('disabled');
}
function disableElement(id){
(document.querySelector(id)).setAttribute('disabled', 'disabled');
}
function validCharacter(c){
return (c >= 32 && c <= 126);
}
function clearTextValue(code, obj, field){
if (!validCharacter(code) || obj.getValue().trim() == '')
{
scope.$parent.risk[field] = '';
return;
}
}
function handleKeyPress(obj, code, attr){
getTextValueAndValidate(code, obj, attr);
validate(obj, attr);
}
function updateAndValidate(code, obj, attr){
clearTextValue(code, obj, attr);
validate(obj, attr);
}
function getTextValueAndValidate(code, obj, field){
clearTextValue(code, obj, field);
clearValidation(field);
scope.getTextValue(obj, scope.$parent, 'risk', field);
validate(obj, field);
}
function drawDot(l, c){
document.querySelector("td[name='risk["+l+"]["+c+"]']").innerHTML
= "<div class='level' style='width:15px; height:15px; background-color: black'/>";
}
function displayLevel(level, l, c){
leveldiv = document.querySelector("div[name='level']");
if (level >= scope.$parent.risklevels.riskhigh)
{
leveldiv.innerHTML = 'H ' + l + '-' + c;
leveldiv.setAttribute('class', 'high');
}
else if (level < scope.$parent.risklevels.riskhigh && level >= scope.$parent.risklevels.riskmedium)
{
leveldiv.innerHTML = 'M ' + l + '-' + c;
leveldiv.setAttribute('class', 'med');
}
else if (level < scope.$parent.risklevels.riskmedium)
{
leveldiv.innerHTML = 'L ' + l + '-' + c;
leveldiv.setAttribute('class', 'low');
}
}
function getConfig(attr, type, width, height, maxlength)
{
var view;
if (type == "level")
view = "text";
else
view = type;
var config =
{
view: view,
value: scope.$parent.risk[attr],
on: {
"onTimedKeyPress": function(code){
var obj = this.eventSource || this;
handleKeyPress(obj, code, attr);
if (type == "level")
assignRiskLevel(obj);
},
"onBlur": function(code){
var obj = this.eventSource || this;
updateAndValidate(code, obj, attr);
}
},
responsive: true,
width: width,
height: height
};
if (maxlength)
config.attributes = {maxlength : maxlength};
return config;
};
scope.$parent[attrs.webixUi] = getConfig(attrs.webixUi, attrs.type, attrs.width, attrs.height, attrs.hasOwnProperty('maxlength')? attrs.maxlength: null);
}
}
}
Повторяющиеся директивы webix-ui для двух разных значений
<div ng-if = "$root.initDone">
<div webix-ui = "risktitle" width = "500" height = "30" type = "text"
id = "risktitle" name = "risktitle" />
</div>
<div ng-if = "$root.initDone">
<div webix-ui = "riskstatement" width = "500" height = "97" type = "textarea"
id = "riskstatement" name = "riskstatement" />
</div>
Кажется, в моем шаблоне использование таблиц для макета вызвало эту проблему. Замена на div была решением приведенного выше комментария.
Сервисы могут быть внедрены в функцию построения директивы:
angular.module('Risk').directive('webixUi', WebixElement);
̶f̶u̶n̶c̶t̶i̶o̶n̶ ̶W̶e̶b̶i̶x̶E̶l̶e̶m̶e̶n̶t̶(̶)̶{̶ ̶
function WebixElement(DOMops){
return {
restrict: 'A',
scope: {
elem: '@'
},
controller: function($scope, CommonService){
$scope.getTextValue = function(obj, model, type, field){
CommonService.getTextValue(obj, model, type, field);
}
},
link: function (scope, element, attrs) {
var clearLevel = DOMops.clearLevel;
/**
function clearLevel(){
leveldiv = document.querySelector("div[name='level']");
leveldiv.innerHTML = '';
leveldiv.setAttribute('class', '');
}
**/
Переместите общие функции в эту службу.
Похоже, именно то, что мне нужно, я реализую и отчитаюсь.
Как передать аргументы в clearLevel, если это требуется? Нужно ли мне обернуть его внутри анонимной функции? function(arg) { DOMops.clearLevel(arg); }
или (arg) => { DOMops.clearLevel(arg); }
Или есть более эффективный или правильный способ? Есть ли способ обойти определение таких функций в моей функции ссылки?
Если служба выполнена правильно, нет необходимости оборачивать функцию. Я также склонен пропустить создание var
. Просто вызовите функцию напрямую, как это можно сделать с любой службой, например. var config = DOMops.config(args)
Когда я вызываю функцию с аргументами, я получаю, что аргументы не определены, потому что я вызываю clearLevel с локальной переменной. Кажется, я понимаю, поскольку функции определены, я буду называть их просто. Спасибо!
$root
и$parent
— это Код пахнет, симптом более глубоких проблем. По крайней мере, они приводят к хрупкому коду с ошибками.