Tenho um formulário que usa marcação do Bootstrap, como o seguinte:
<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>
Há muito código clichê lá, que eu gostaria de reduzir a uma nova diretiva - form-input, como a seguir:
<form-input label="Name" form-id="nameInput"></form-input>
gera:
<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>
Tenho tudo isso trabalhando por meio de um modelo simples.
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>'
}
})
No entanto, é quando eu venho para adicionar funcionalidades mais avançadas que estou ficando preso.
Como posso oferecer suporte a valores padrão no modelo?
Gostaria de expor o parâmetro "type" como um atributo opcional na minha diretiva, por exemplo:
<form-input label="Password" form-id="password" type="password"/></form-input>
<form-input label="Email address" form-id="emailAddress" type="email" /></form-input>
No entanto, se nada for especificado, gostaria de usar como padrão "text"
. Como posso apoiar isso?
Como posso personalizar o modelo com base na presença / ausência de atributos?
Eu também gostaria de ser capaz de oferecer suporte ao atributo "required", se estiver presente. Por exemplo:
<form-input label="Email address" form-id="emailAddress" type="email" required/></form-input>
Se required
estiver presente na diretiva, gostaria de adicioná-lo ao gerado <input />
na saída e ignorá-lo caso contrário. Não tenho certeza de como fazer isso.
Suspeito que esses requisitos podem ter ido além de um simples modelo e precisam começar a usar as fases de pré-compilação, mas não sei por onde começar.
fonte
type
for definido dinamicamente por meio de ligação, por exemplo.type="{{ $ctrl.myForm.myField.type}}"
? Verifiquei todos os métodos abaixo e não encontrei nenhuma solução que funcione neste cenário. Parece que a função de modelo verá valores literais dos atributos, por exemplo.tAttr['type'] == '{{ $ctrl.myForm.myField.type }}'
em vez detAttr['type'] == 'password'
. Estou confuso.Respostas:
fonte
htmlText
você adicionar umng-click
algum lugar, a única modificação seria substituirelement.replaceWith(htmlText)
porelement.replaceWith($compile(htmlText))
?htmlText
contiver uma diretiva ng-transclude$error
sinalizadores na entrada inserida nunca são definidos. Tive que fazer isso dentro da propriedade de link de uma diretiva:$compile(htmlText)(scope,function(_el){ element.replaceWith(_el); });
para que o controlador do formulário reconhecesse sua existência recém-formada e incluísse na validação. Não consegui fazê-lo funcionar na propriedade de compilação de uma diretiva.Tentei usar a solução proposta por Misko, mas na minha situação, alguns atributos, que precisavam ser integrados ao meu template html, eram eles próprios diretivas.
Infelizmente, nem todas as diretivas referenciadas pelo modelo resultante funcionaram corretamente. Não tive tempo suficiente para mergulhar no código angular e descobrir a causa raiz, mas encontrei uma solução alternativa que poderia ser útil.
A solução foi mover o código, que cria o template html, de compilar para uma função de template. Exemplo baseado no código acima:
fonte
As respostas acima, infelizmente, não funcionam bem. Em particular, o estágio de compilação não tem acesso ao escopo, portanto, você não pode personalizar o campo com base em atributos dinâmicos. Usar o estágio de vinculação parece oferecer mais flexibilidade (em termos de criação de dom de forma assíncrona, etc.) A abordagem a seguir aborda o seguinte:
Eu criei uma essência com um código mais completo e uma descrição da abordagem.
fonte
Error: [ngTransclude:orphan] Illegal use of ngTransclude directive in the template! No parent directive that requires a transclusion found.
Aqui está o que acabei usando.
Eu sou muito novo no AngularJS, então adoraria ver soluções melhores / alternativas.
Exemplo de uso:
fonte
<form-input ng-model="appName" label="Application Name" form-id="appName" required/></form-input>
)compile
fase, que trata da transformação do modelo, e alink
fase, que trata da modificação dos dados na visualização. Ao longo dessas linhas, a principal diferença entrecompile
elink
funções em diretivas é que ascompile
funções lidam com a transformação do próprio modelo e aslink
funções lidam com a conexão dinâmica entre o modelo e a visualização. É nessa segunda fase que os escopos são anexados àslink
funções compiladas e a diretiva torna-se ativa por meio da vinculação de dados "