Вот проблема, которую я пытаюсь решить: создание формы из переменного набора виджетов, где точные виджеты и их порядок определяются данными, а именно схемой. Первый подход, который я использовал, выглядит так (опуская ненужные детали):
контроллер.js:
angular.module('app').controller(function($scope) {
$scope.data = {
actions: [{
name: 'Action1',
base: 'nova.create_server',
baseInput: {
flavorId: {
title: 'Flavor Id',
type: 'string'
},
imageId: {
title: 'Image Id',
type: 'string'
}
},
input: [''],
output: [{
type: 'string',
value: ''
}, {
type: 'dictionary',
value: {
key1: '',
key2: ''
}
}, {
type: 'list',
value: ['', '']
}]
}]
};
$scope.schema = {
action: [{
name: 'name',
type: 'string',
}, {
name: 'base',
type: 'string',
}, {
name: 'baseInput',
type: 'frozendict',
}, {
name: 'input',
type: 'list',
}, {
name: 'output',
type: 'varlist',
}
]
};
})
шаблон.html
<div ng-controller="actionCtrl" ng-repeat="item in data.actions">
<div ng-repeat="spec in schema.action" ng-class="{'right-column': $even && isAtomic(spec.type), 'left-column': $odd && isAtomic(spec.type)}">
<typed-field></typed-field>
<div class="clearfix" ng-show="$even"></div>
</div>
</collapsible-panel>
директивы.js
.directive('typedField', function($http, $templateCache, $compile) {
return {
restrict: 'E',
scope: true,
link: function(scope, element, attrs) {
$http.get(
'/static/mistral/js/angular-templates/fields/' + scope.spec.type + '.html',
{cache: $templateCache}).success(function(templateContent) {
element.replaceWith($compile(templateContent)(scope));
});
}
}
})
Среди шаблонов, расположенных внутри '/fields/', простейшим шаблоном для поля строкового типа является
<div class="form-group">
<label>{$ spec.title || makeTitle(spec.name) $}</label>
<input type="text" class="form-control" ng-model="item[spec.name]">
</div>
Этот подход работает для - все виджеты визуализируются, привязки моделей работают, но как только я набираю одну букву внутри этих виджетов, область видимости изменяется, и виджеты перерисовываются, что приводит к: * потере фокуса * некоторой задержке по времени, что означает низкую производительность .
Пытаясь преодолеть этот недостаток, я переписал свое приложение следующим образом:
шаблон.html
<div ng-controller="actionCtrl" ng-repeat="item in data.actions">
<action></action>
</div>
директивы.js
.directive('typedField', function($http, $templateCache, idGenerator, $compile) {
return {
restrict: 'E',
scope: true,
compile: function ($element, $attrs) {
$http.get(
'/static/mistral/js/angular-templates/fields/' + $attrs.type + '.html',
{cache: $templateCache}).success(function (templateContent) {
$element.replaceWith(templateContent);
});
return function (scope, element, attrs) {
scope.title = $attrs.title;
scope.type = $attrs.type;
scope.name = $attrs.name;
}
}
}
})
.directive('action', function($compile, schema, isAtomic) {
return {
restrict: 'E',
compile: function(tElement, tAttrs) {
angular.forEach(
schema.action,
function(spec, index) {
var cls = '', elt;
if ( isAtomic(spec.type) ) {
cls = index % 2 ? 'class="right-column"' : 'class="left-column"';
}
elt = '<div ' + cls + '><typed-field type="' + spec.type + '" name="' + spec.name + '"></typed-field>';
if ( index % 2 ) {
elt += '<div class="clearfix"></div>';
}
elt += '</div>';
tElement.append(elt);
});
return function(scope, element, attrs) {
}
}
}
})
Вместо того, чтобы получать схему из области видимости, я предоставляю ее через внедрение зависимостей в фазу компиляции директивы (которая запускается только в первый раз — мне казалось, что это именно то, что мне нужно, чтобы избежать повторяющейся полной перерисовки виджетов). Но теперь вместо красиво выглядящих виджетов (как раньше) я получаю сырой html с привязками данных, которые вообще не оцениваются. Я предполагаю, что делаю что-то не так, но не понимаю, как мне правильно использовать функцию компиляции, чтобы избежать проблем с производительностью. Не могли бы вы дать совет, что следует исправить?