Атрибут динамического имени формы <input type = "text" name= "{{variable-name}}" /"> в Angularjs
Как кто-то будет использовать formName.inputName. $valid, когда "inputName" было динамически создано?
<form name="formName">
<input ng-repeat="(variable) in variables"
type="text" name="variable.name"
ng-model="variable.name" required />
</form>
Результатом входного атрибута HTML "name" будет строка "variablename", которая будет применяться ко всем повторным входам.
Если мы попробуем этот
<form name="formName">
<input ng-repeat="(variable) in variables"
type="text" name="{{ variable.name }}"
ng-model="variable.name" required />
</form>
Результатом входного атрибута HTML "name" будет строка "{{variable.name}}", которая будет применяться ко всем повторным входам.
В любом из этих двух условий атрибут имени для каждого из повторяющихся элементов ввода не будет создан динамически; Все входы будут иметь одно и то же имя ввода. Не очень хорошо, если вы хотите вызвать конкретный вход на основе определенного имени.
- необходимо использовать динамические значения имен
- нужно иметь возможность вызывать $scope.formName.dynamicName. $valid
- должен быть способен вызвать $scope.formName. $valid
- нужны динамические поля ввода имени для добавления в вложенную форму или основную форму
Ответы
Ответ 1
Я не мог найти ответ, который удовлетворил некоторые или все эти потребности. Это то, что я придумал.
Там может быть лучший способ, поэтому, пожалуйста, поделитесь своими мыслями.
Я использую Angularjs 1.3.0-beta.8
У меня есть форма с многопользовательскими директивами, в которой все содержат входные данные, select (s) и т.д....
Все эти элементы заключены в ng-повторах и динамических строковых значениях.
Вот как использовать директиву:
<form name="myFormName">
<nested directives of many levels>
ex: <input ng-repeat=(index, variable) in variables" type="text"
my-name="{{ variable.name + '/' + 'myFormName' }}"
ng-model="variable.name" required />
ex: <select ng-model="variable.name" ng-options="label in label in {{ variable.options }}"
my-name="{{ variable.name + '/' + 'myFormName' }}"
</select>
</form>
Примечание: вы можете добавлять и индексировать конкатенацию строк, если вам нужно сериализовать, возможно, таблицу входов; что я и сделал. Однако динамические входы имен означают, что вы не можете знать имя ввода формы, так как бы вы назвали $scope.formName.??????. Вы можете выполнить итерацию объекта $scope.formName, чтобы получить ключи, соответствующие определенному значению. Это означает, что конкатенация строк выглядит следующим образом:
my-name="{{ dynamicString + hello + '/' + 'myFormName' }}"
Затем в $scope.myFormName вы найдете любое имя ввода формы, просто перейдя по объекту и собирая любые ключи, которые включали "привет".
app.directive('myName', function(){
var myNameError = "myName directive error: "
return {
restrict:'A', // Declares an Attributes Directive.
require: 'ngModel', // ngModelController.
link: function( scope, elem, attrs, ngModel ){
if( !ngModel ){ return } // no ngModel exists for this element
// check myName input for proper formatting ex. something/something
checkInputFormat(attrs);
var inputName = attrs.myName.match('^\\w+').pop(); // match upto '/'
assignInputNameToInputModel(inputName, ngModel);
var formName = attrs.myName.match('\\w+$').pop(); // match after '/'
findForm(formName, ngModel, scope);
} // end link
} // end return
function checkInputFormat(attrs){
if( !/\w\/\w/.test(attrs.rsName )){
throw myNameError + "Formatting should be \"inputName/formName\" but is " + attrs.rsName
}
}
function assignInputNameToInputModel(inputName, ngModel){
ngModel.$name = inputName
}
function addInputNameToForm(formName, ngModel, scope){
scope[formName][ngModel.$name] = ngModel; return
}
function findForm(formName, ngModel, scope){
if( !scope ){ // ran out of scope before finding scope[formName]
throw myNameError + "<Form> element named " + formName + " could not be found."
}
if( formName in scope){ // found scope[formName]
addInputNameToForm(formName, ngModel, scope)
return
}
findForm(formName, ngModel, scope.$parent) // recursively search through $parent scopes
}
});
Это должно обрабатывать многие ситуации, когда вы просто не знаете, где будет форма. Или, возможно, у вас есть вложенные формы, но по какой-то причине вы хотите прикрепить это имя ввода к двум формам? Ну, просто введите имя формы, к которой вы хотите прикрепить имя ввода.
То, что я хотел, было способом присвоить динамические значения входам, которые я никогда не узнаю, а затем просто вызовет $scope.myFormName. $valid.
Это может быть чрезмерным, и в 1.3+ существует лучшее решение. Я не мог найти его в то время, которое у меня было. Теперь это работает для меня.
Удачи! Надеюсь, это поможет кому-то!!!!
Ответ 2
Похож, что Angular 1.3 исправил это (fooobar.com/questions/39594/...)
Теперь это возможно с помощью Angular 1.3 +:
<form name="vm.myForm" novalidate>
<div ng-repeat="p in vm.persons">
<input type="text" name="person_{{$index}}" ng-model="p" required>
<span ng-show="vm.myForm['person_' + $index].$invalid">Enter a name</span>
</div>
</form>
Демо
В некоторых случаях внутренняя форма является хорошим решением, если вы можете просто передать информацию: (https://stackoverflow.com/posts/12044600/)
Чтобы решить проблему "динамического имени" , вам нужно создать внутреннюю форму (см. ng-form):
<div ng-repeat="social in formData.socials">
<ng-form name="urlForm">
<input type="url" name="socialUrl" ng-model="social.url">
<span class="alert error" ng-show="urlForm.socialUrl.$error.url">URL error</span>
<button ng-click="doSomething(urlForm.socialUrl.$valid)">Test</button>
</ng-form>
</div>
Другой альтернативой было бы написать пользовательскую директиву для этого.
Вот jsFiddle, показывающий использование ngForm: http://jsfiddle.net/pkozlowski_opensource/XK2ZT/2/
Ответ 3
работайте со мной с angular 1.2.7
директива:
var DynamicName = function() {
return {
restrict: 'A',
priority: -1,
require: ['ngModel'],
link: function (scope, element, attr, ngModel) {
ngModel[0].$name = attr.name;
}
};
};
app.directive('dynamicName', DynamicName);
howtouse:
<div ng-repeat="phone in hrModel.phones">
<input type="text"
name="phones[{{$index}}]"
ng-model="phones[$index]"
dynamic-name
/>
</div>
Ответ 4
Компиляция имени ввода
- Как заметил кто-то другой, современные версии Angular исправили это...
- Это должно установить атрибут имени на вашем входе и добавить контроллер модели в форму:
angular.module('MOD')
.directive('compiledName', compiledNameDirective);
function compiledNameDirective() {
return {
restrict: 'A',
require: ['ngModel', '?^form'],
scope: {
name: '@compiledName'
},
link: function checkboxIndeterminateLink(scope, element, attributes, required) {
var ngModelController = required[0], ngFormController = required[1];
ngModelController.$name = scope.name;
element.attr('name', scope.name);
if (ngFormController) ngFormController.$addControl(ngModelController);
}
};
}
Ответ 5
Не забывайте, что вы можете обращаться к объектам javascript, используя нотацию массива со строковыми индексами. Учитывая следующий произвольный объект определения формы:
$scope.form_def = {
form_name : 'BallForm',
variables : [
height : { name : 'Height', type : 'text' },
width : { name : 'Width', type : 'text' },
color : { name : 'Color', type : 'multi', options : ['red', 'green', 'blue'] }
]
};
$scope.form_values = {};
... и html-фрагмент...
<form name="{{ form_def.form_name }}">
<div ng-repeat="variable in form_def.variables">
<input ng-if="variable.type==='text'" type="text" name="{{ variable.name }}" ng-model="form_values[variable.name]">
<select ng-if="variable.type==='multi'" name="{{ variable.name }}" ng-model="form_values[variable.name]">
<option ng-repeat="opt in variable.options" value="{{ opt }}">{{ opt }}</option>
</select>
</div>
</form>
Внутри контроллера у вас будет хороший объект form_values для каждого поля, к которому вы можете получить доступ, итерации по ключам в хэш-форме form_def.variables.
Когда вы приступите к написанию таких родовых сценариев обработки форм, вы получите гораздо больше информации, и, на мой взгляд, у вас получится адский код спагетти, и вы, вероятно, лучше пойдете с менее общим решение, но это еще один вопрос SO.