Tengo un formulario que usa marcado de Bootstrap, como el siguiente:
<form class="form-horizontal">
<fieldset>
<legend>Legend text</legend>
<div class="control-group">
<label class="control-label" for="nameInput">Name</label>
<div class="controls">
<input type="text" class="input-xlarge" id="nameInput">
<p class="help-block">Supporting help text</p>
</div>
</div>
</fieldset>
</form>
Hay una gran cantidad de código repetitivo allí, que me gustaría reducir a una nueva directiva: formulario de entrada, como sigue:
<form-input label="Name" form-id="nameInput"></form-input>
genera:
<div class="control-group">
<label class="control-label" for="nameInput">Name</label>
<div class="controls">
<input type="text" class="input-xlarge" id="nameInput">
</div>
</div>
Tengo tanto trabajo a través de una plantilla simple.
angular.module('formComponents', [])
.directive('formInput', function() {
return {
restrict: 'E',
scope: {
label: 'bind',
formId: 'bind'
},
template: '<div class="control-group">' +
'<label class="control-label" for="{{formId}}">{{label}}</label>' +
'<div class="controls">' +
'<input type="text" class="input-xlarge" id="{{formId}}" name="{{formId}}">' +
'</div>' +
'</div>'
}
})
Sin embargo, es cuando llego a agregar una funcionalidad más avanzada que me atasco.
¿Cómo puedo admitir valores predeterminados en la plantilla?
Me gustaría exponer el parámetro "tipo" como un atributo opcional en mi directiva, por ejemplo:
<form-input label="Password" form-id="password" type="password"/></form-input>
<form-input label="Email address" form-id="emailAddress" type="email" /></form-input>
Sin embargo, si no se especifica nada, me gustaría usar de forma predeterminada "text"
. ¿Cómo puedo apoyar esto?
¿Cómo puedo personalizar la plantilla en función de la presencia / ausencia de atributos?
También me gustaría poder admitir el atributo "obligatorio", si está presente. P.ej:
<form-input label="Email address" form-id="emailAddress" type="email" required/></form-input>
Si required
está presente en la directiva, me gustaría agregarlo al generado <input />
en la salida e ignorarlo de lo contrario. No estoy seguro de cómo lograrlo.
Sospecho que estos requisitos pueden haberse movido más allá de una simple plantilla y tienen que comenzar a usar las fases de precompilación, pero no tengo por dónde empezar.
fuente
type
se establece dinámicamente a través de un enlace, por ejemplo?type="{{ $ctrl.myForm.myField.type}}"
? Revisé todos los métodos a continuación y no pude encontrar ninguna solución que funcione en este escenario. Parece que la función de plantilla verá valores literales de los atributos, por ejemplo.tAttr['type'] == '{{ $ctrl.myForm.myField.type }}'
en lugar detAttr['type'] == 'password'
. Estoy confundido.Respuestas:
fuente
htmlText
agregaste unng-click
lugar, ¿la única modificación sería reemplazarelement.replaceWith(htmlText)
conelement.replaceWith($compile(htmlText))
?htmlText
contiene una directiva ng-transclude$error
banderas en la entrada insertada nunca se configuran. Tuve que hacer esto dentro de la propiedad de enlace de una directiva:$compile(htmlText)(scope,function(_el){ element.replaceWith(_el); });
para que el controlador del formulario reconozca su existencia recién formada y la incluya en la validación. No pude hacer que funcione en la propiedad de compilación de una directiva.Intenté utilizar la solución propuesta por Misko, pero en mi situación, algunos atributos, que debían fusionarse en mi plantilla html, eran en sí mismos directivas.
Desafortunadamente, no todas las directivas a las que hace referencia la plantilla resultante funcionaron correctamente. No tuve suficiente tiempo para sumergirme en el código angular y descubrir la causa raíz, pero encontré una solución que podría ser útil.
La solución fue mover el código, que crea la plantilla html, de compilar a una función de plantilla. Ejemplo basado en el código de arriba:
fuente
Desafortunadamente, las respuestas anteriores no funcionan del todo. En particular, la etapa de compilación no tiene acceso al alcance, por lo que no puede personalizar el campo en función de atributos dinámicos. El uso de la etapa de vinculación parece ofrecer la mayor flexibilidad (en términos de creación asincrónica de dom, etc.) El siguiente enfoque aborda eso:
He creado una esencia con un código más completo y una redacción del enfoque.
fuente
Error: [ngTransclude:orphan] Illegal use of ngTransclude directive in the template! No parent directive that requires a transclusion found.
Esto es lo que terminé usando.
Soy muy nuevo en AngularJS, así que me encantaría ver soluciones mejores / alternativas.
Uso de ejemplo:
fuente
<form-input ng-model="appName" label="Application Name" form-id="appName" required/></form-input>
)compile
fase, que se ocupa de transformar la plantilla, y lalink
fase, que se ocupa de modificar los datos en la vista. En este sentido, la principal diferencia entrecompile
y laslink
funciones en las directivas es que lascompile
funciones se ocupan de transformar la plantilla en sí, y laslink
funciones se ocupan de establecer una conexión dinámica entre el modelo y la vista. Es en esta segunda fase cuando los ámbitos se adjuntan a laslink
funciones compiladas y la directiva se activa mediante el enlace de datos "