I have a form made with AngularJS Material elements in which elements can be added and deleted dynamically. Each of these elements is formed by a md-autocomplete and an input. Both fields are required. I have two problems, the first is that the input is not validated correctly, the second problem is that when a field is deleted, the form is not revalidated, so the form will be considered invalid even if the elements that are in that moment are correctly filled. I don’t know why the input isn’t validated or how to revaluate the form every time an element is added or deleted. This is how the form looks:
The elements that are added dynamically are like this:
<div id="campoExtra${$scope.nCampoExtra}" style="max-height: 95px;">
<md-input-container flex="50"> +
<md-autocomplete required="required" md-no-cache="noCache" md-input-name="atributoExtra${$scope.nCampoExtra}" md-input-id="searchinput" md-selected-item="selectedItem[${$scope.nCampoExtra}]" md-search-text-change="searchTextChange(searchText[${$scope.nCampoExtra}])" md-search-text="searchText[${$scope.nCampoExtra}]" md-selected-item-change="selectedItemChange(item)" md-items="item in querySearch(searchText[${$scope.nCampoExtra}])" md-item-text="item.display" md-min-length="0" md-floating-label="Atributo extra ${$scope.nCampoExtra}">
<md-item-template style="color: #9ea1a4;">
<span md-highlight-text="searchText[${$scope.nCampoExtra}]" md-highlight-flags="^i">{{item.display}}</span>
</md-item-template>
<md-not-found ng-hide="extraCreado">
<md-button ng-hide="extraCreado" ng-click="crearCampoExtra(searchText[${$scope.nCampoExtra}], ${$scope.nCampoExtra})" style="width: 100%; text-align: center;">Crear!</md-button></md-not-found>
<div ng-messages="formAtributosExtra.atributoExtra${$scope.nCampoExtra}.$error" ng-if="formAtributosExtra.atributoExtra${$scope.nCampoExtra}.$touched">
<div ng-message="required">Campo requerido</div>
</div>
</md-autocomplete>
</md-input-container>
<md-input-container flex="50">
<label>Valor atributo extra ${$scope.nCampoExtra}</label>
<input name="atributosExtraValor${$scope.nCampoExtra}" ng-model="atributosExtraValor[${$scope.nCampoExtra}]" required>
<div ng-messages="formAtributosExtra.atributosExtraValor${$scope.nCampoExtra}.$error">
<div ng-message="required">This field is required.</div>
</div>
</md-input-container>
The form where the elements are inserted is the following:
<form name="formAtributosExtra" ng-submit="actualizarAtributos()" >
<div layout="row">
<md-button class="md-fab md-mini" aria-label="Añadir campo" ng-click="crearCampo()" >
<md-icon md-svg-src="img/icons/add.svg"></md-icon>
</md-button>
<md-button class="md-fab md-mini" aria-label="Quitar campo" ng-click="quitarCampo()" >
<md-icon md-svg-src="img/icons/remove.svg"></md-icon>
</md-button>
</div>
<div layout="column" id="camposExtra"></div>
And the functions to add and delete fields are:
//Add field
$scope.crearCampo = function () {
let template = `<div id="campoExtra${$scope.nCampoExtra}" style="max-height: 95px;">`+
`<md-input-container flex="50">` +
`<md-autocomplete required="required" md-no-cache="noCache" md-input-name="atributoExtra${$scope.nCampoExtra}" md-input-id="searchinput" md-selected-item="selectedItem[${$scope.nCampoExtra}]" md-search-text-change="searchTextChange(searchText[${$scope.nCampoExtra}])" md-search-text="searchText[${$scope.nCampoExtra}]" md-selected-item-change="selectedItemChange(item)" md-items="item in querySearch(searchText[${$scope.nCampoExtra}])" md-item-text="item.display" md-min-length="0" md-floating-label="Atributo extra ${$scope.nCampoExtra}">`+
`<md-item-template style="color: #9ea1a4;">`+
`<span md-highlight-text="searchText[${$scope.nCampoExtra}]" md-highlight-flags="^i">{{item.display}}</span>`+
`</md-item-template>`+
`<md-not-found ng-hide="extraCreado">`+
`<md-button ng-hide="extraCreado" ng-click="crearCampoExtra(searchText[${$scope.nCampoExtra}], ${$scope.nCampoExtra})" style="width: 100%; text-align: center;">Crear!</md-button></md-not-found>`+
`<div ng-messages="formAtributosExtra.atributoExtra${$scope.nCampoExtra}.$error" ng-if="formAtributosExtra.atributoExtra${$scope.nCampoExtra}.$touched">`+
`<div ng-message="required">Campo requerido</div>`+
`</div>`+
`</md-autocomplete>`+
`</md-input-container>`+
`<md-input-container flex="50">`+
`<label>Valor atributo extra ${$scope.nCampoExtra}</label>`+
`<input name="atributosExtraValor${$scope.nCampoExtra}" ng-model="atributosExtraValor[${$scope.nCampoExtra}]" required>`+
`<div ng-messages="formAtributosExtra.atributosExtraValor${$scope.nCampoExtra}.$error">`+
`<div ng-message="required">This field is required.</div>`+
`</div>`+
`</md-input-container>`+
`</div>`;
let html = $compile(template)($scope);
angular.element(document.getElementById("camposExtra")).append(html);
$scope.nCampoExtra++;
};
//Delete last field
$scope.quitarCampo = function () {
if ($scope.nCampoExtra > 1) {
let nCampoExtra = $scope.nCampoExtra - 1;
angular.element(document.getElementById("campoExtra" + nCampoExtra)).remove();
$scope.nCampoExtra--;
$scope.atributosExtraNombre[nCampoExtra] = '';
$scope.atributosExtraValor[nCampoExtra] = '';
}
};
Thank you in advance.
Updates:
Following the advice of @georgeawg, I created the form dynamically using ng-repeat. Currently it works correctly except that the ng-messages of the md-autocomplete are not displayed. Next is the HTML code, it's a template since the form is displayed in a Dialog.
'<md-dialog aria-label="List dialog" >' +
'<md-toolbar>' +
' <div class="md-toolbar-tools">' +
' <h2>Atributos extra</h2>' +
' <span flex></span>' +
' <md-button class="md-icon-button" ng-click="closeDialog(false)">' +
' <md-icon md-svg-src="img/icons/ic_close_24px.svg" aria-label="Close dialog"></md-icon>' +
' </md-button>' +
' </div>' +
'</md-toolbar>' +
'<md-dialog-content style="max-width:80%; max-height:80%; min-width: 425px; min-height: 400px;" layout-align="center center">' +
'<div class="md-dialog-content">'+
'<form name="formAtributosExtra" ng-submit="actualizarAtributos()" >'+
'<div layout="row">'+
'<md-button class="md-fab md-mini" aria-label="Añadir campo" ng-click="crearCampo()" >'+
'<md-icon md-svg-src="img/icons/add.svg"></md-icon>'+
'</md-button>'+
'<md-button class="md-fab md-mini" aria-label="Quitar campo" ng-click="quitarCampo()" >'+
'<md-icon md-svg-src="img/icons/remove.svg"></md-icon>'+
'</md-button>'+
'</div>'+
'<div ng-repeat="atributo in numeroAtributos" style="max-height: 95px;">'+
'<md-input-container flex="50">' +
'<md-autocomplete required="required" md-no-cache="noCache" md-input-name="atributoExtraNombre{{$index}}" md-input-id="searchinput{{$index}}" md-selected-item="selectedItem[$index]" md-search-text-change="searchTextChange(searchText[$index])" md-search-text="searchText[$index]" md-selected-item-change="selectedItemChange(item)" md-items="item in querySearch(searchText[$index])" md-item-text="item.display" md-min-length="0" md-floating-label="Atributo extra {{$index + 1 }}">'+
'<md-item-template style="color: #9ea1a4;">'+
'<span md-highlight-text="searchText[$index]" md-highlight-flags="^i">{{item.display}}</span>'+
'</md-item-template>'+
'<md-not-found ng-hide="extraCreado">'+
'<md-button ng-hide="extraCreado" ng-click="crearCampoExtra(searchText[$index], $index)" style="width: 100%; text-align: center;">Crear!</md-button></md-not-found>'+
'<div ng-messages="formAtributosExtra[\'atributoExtraNombre\' + $index].$error">'+
'<div ng-message="required">Required</div>'+
'</div>'+
'</md-autocomplete>'+
'</md-input-container>'+
'<md-input-container flex="50">'+
'<label>Valor atributo extra {{$index + 1}}</label>'+
'<input name="atributosExtraValor{{$index}}" ng-model="atributosExtraValor[$index]" required>'+
'<div ng-messages="formAtributosExtra[\'atributosExtraValor\'+$index].$error" ng-show="formAtributosExtra[\'atributosExtraValor\'+$index].$touched">'+
'<div ng-message="required">Campo requerido</div>'+
'</div>'+
'</md-input-container>'+
'</div>'+
'</form>'+
'</div>'+
' </md-dialog-content>' +
' <md-dialog-actions>' +
' <md-button ng-click="closeDialog(false)" class="md-primary">' +
' Cerrar' +
' </md-button>' +
'<md-button type="submit" class="md-raised md-primary" ng-disabled="formAtributosExtra.$invalid" ng-click="actualizarAtributos()" class="md-primary">' +
' Guardar' +
' </md-button>' +
' </md-dialog-actions>' +
'</md-dialog>',
