Mam formularz, który używa znaczników z Bootstrap, na przykład:
<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>
Jest tam dużo gotowego kodu, który chciałbym zredukować do nowej dyrektywy - form-input, na przykład:
<form-input label="Name" form-id="nameInput"></form-input>
generuje:
<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>
Tyle pracuję dzięki prostemu szablonowi.
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>'
}
})
Jednak kiedy dodam bardziej zaawansowaną funkcjonalność, utknęłam.
Jak mogę obsługiwać wartości domyślne w szablonie?
Chciałbym ujawnić parametr „type” jako opcjonalny atrybut w mojej dyrektywie, np .:
<form-input label="Password" form-id="password" type="password"/></form-input>
<form-input label="Email address" form-id="emailAddress" type="email" /></form-input>
Jeśli jednak nic nie zostanie określone, chcę domyślnie "text"
. Jak mogę to wesprzeć?
Jak mogę dostosować szablon na podstawie obecności / braku atrybutów?
Chciałbym również móc obsługiwać atrybut „wymagany”, jeśli jest obecny. Na przykład:
<form-input label="Email address" form-id="emailAddress" type="email" required/></form-input>
Jeśli required
jest obecny w dyrektywie, chciałbym dodać go do wygenerowanego <input />
wyniku i zignorować w przeciwnym razie. Nie jestem pewien, jak to osiągnąć.
Podejrzewam, że te wymagania mogły wyjść poza prosty szablon i muszę zacząć korzystać z faz prekompilacji, ale nie wiem, od czego zacząć.
źródło
type
jest ustawiane dynamicznie poprzez wiązanie np.type="{{ $ctrl.myForm.myField.type}}"
? Sprawdziłem wszystkie poniższe metody i nie mogłem znaleźć żadnego rozwiązania, które zadziała w tym scenariuszu. Wygląda na to, że funkcja szablonu zobaczy dosłowne wartości atrybutów, np.tAttr['type'] == '{{ $ctrl.myForm.myField.type }}'
zamiasttAttr['type'] == 'password'
. Jestem zdziwiony.Odpowiedzi:
źródło
htmlText
ty dodaje sięng-click
gdzieś, to jedyna modyfikacja być zastąpienieelement.replaceWith(htmlText)
zeelement.replaceWith($compile(htmlText))
?htmlText
zawiera dyrektywę ng-transclude$error
flagi na wstawionym wejściu nigdy nie są ustawiane. Musiałem to zrobić w ramach właściwości łącza dyrektywy:$compile(htmlText)(scope,function(_el){ element.replaceWith(_el); });
aby kontroler formularza mógł rozpoznać jego nowo utworzone istnienie i uwzględnić go w walidacji. Nie mogłem zmusić go do działania we właściwości kompilacji dyrektywy.Próbowałem skorzystać z rozwiązania zaproponowanego przez Misko, ale w mojej sytuacji niektóre atrybuty, które musiały zostać włączone do mojego szablonu html, same były dyrektywami.
Niestety, nie wszystkie dyrektywy, do których odwołuje się wynikowy szablon, działały poprawnie. Nie miałem wystarczająco dużo czasu, aby zagłębić się w kod kątowy i znaleźć główną przyczynę, ale znalazłem obejście, które może być potencjalnie pomocne.
Rozwiązaniem było przeniesienie kodu, który tworzy szablon html, z kompilacji do funkcji szablonu. Przykład na podstawie kodu z góry:
źródło
Powyższe odpowiedzi niestety nie do końca działają. W szczególności etap kompilacji nie ma dostępu do zakresu, więc nie można dostosowywać pola na podstawie atrybutów dynamicznych. Wydaje się, że użycie etapu linkowania zapewnia największą elastyczność (pod względem asynchronicznego tworzenia domeny itp.) Poniższe podejście rozwiązuje następujące kwestie:
Utworzyłem GIST z bardziej kompletny kod i writeup podejścia.
źródło
Error: [ngTransclude:orphan] Illegal use of ngTransclude directive in the template! No parent directive that requires a transclusion found.
Oto, czego ostatecznie użyłem.
Jestem bardzo nowy w AngularJS, więc chciałbym zobaczyć lepsze / alternatywne rozwiązania.
Przykładowe użycie:
źródło
<form-input ng-model="appName" label="Application Name" form-id="appName" required/></form-input>
)compile
fazę, która zajmuje się transformacją szablonu, orazlink
fazę, która zajmuje się modyfikowaniem danych w widoku. Zgodnie z tymi liniami podstawowa różnica międzycompile
ilink
funkcje w dyrektywach polega na tym, żecompile
funkcje zajmują się przekształcaniem samego szablonu, alink
funkcje zajmują się tworzeniem dynamicznego połączenia między modelem a widokiem. W tej drugiej fazie zakresy są dołączane do skompilowanychlink
funkcji, a dyrektywa staje się aktywna dzięki powiązaniu danych "