Jaki jest najlepszy sposób warunkowego zastosowania atrybutów w AngularJS?

296

Muszę być w stanie dodać na przykład „contentediable” do elementów, w oparciu o zmienną boolowską w zakresie.

Przykładowe zastosowanie:

<h1 attrs="{'contenteditable=\"true\"': editMode}">{{content.title}}</h1>

Spowodowałoby to dodanie contenteditable = true do elementu, gdyby $scope.editModebył ustawiony na true. Czy jest jakiś prosty sposób na implementację takiego zachowania atrybutu klasy ng? Rozważam napisanie dyrektywy i podzielenie się, jeśli nie.

Edycja: Widzę, że istnieją pewne podobieństwa między moją proponowaną dyrektywą attrs a ng-bind-attrs, ale została ona usunięta w wersji 1.0.0.rc3 , dlaczego tak jest?

Kenneth Lynne
źródło
2
Nie spotkałem czegoś takiego. Głosuję, zrób to! : D Może prześlij to do projektu kątowego. Przydałaby się składnia, która lepiej pasuje do klasy ng. ng-attr="expression".
Xesued
Zdecydowanie biorę pod uwagę, że tak!
Kenneth Lynne
3
To naprawdę nie jest to samo, co ngClass lub ngStyle, ponieważ kontrolują pojedynczy atrybut, a ty chcesz kontrolować dowolny atrybut. Myślę, że lepiej byłoby stworzyć contentEditabledyrektywę.
Josh David Miller
@JoshDavidMiller +1 w tej sprawie. Myślę, że jest niewielka korzyść z kontrolowania dowolnego atrybutu, szczególnie biorąc pod uwagę złożoność. Możesz mieć dyrektywy warunkowo działające na zmiennej.
Umur Kontacı
<h1 ng-attr-contenteditable="{{editMode && true : false}}">{{content.title}}</h1>
mia

Odpowiedzi:

272

Korzystam z następujących opcji, aby warunkowo ustawić klasę attr, gdy nie można użyć klasy ng (na przykład podczas stylowania SVG):

ng-attr-class="{{someBoolean && 'class-when-true' || 'class-when-false' }}"

To samo podejście powinno działać w przypadku innych typów atrybutów.

(Myślę, że musisz używać najnowszego niestabilnego Angulara, aby używać ng-attr-, aktualnie jestem na wersji 1.1.4)

Ashley Davis
źródło
97
Żeby wyjaśnić tę odpowiedź: jeśli użyjesz prefiksu dowolnego atrybutu ng-attr-, kompilator usunie prefiks i doda atrybut z jego wartością związaną z wynikiem wyrażenia kątowego z oryginalnej wartości atrybutu.
Matthias,
12
Moim zdaniem łatwiej jest przeczytać, jeśli używasz operatora trójskładnikowego, dla którego dodano obsługę w 1.1.5. To by wyglądało tak: {{someConditionalExpression? „class-when-true”: „class-when-false”}}
dshap
129
problem z tym podejściem polega na tym, że atrybut jest tworzony niezależnie od wyniku. Idealnie chcielibyśmy kontrolować, czy nie atrybut w ogóle zostanie utworzony.
airtonix
24
Zauważ, że ng-attr-stuff został usunięty z Angular 1.2. Ta odpowiedź nie jest już ważna.
Judah Gabriel Himango,
2
Mylisz się. Ten projekt github.com/codecapers/AngularJS-FlowChart używa Angular 1.2 i ng-attr-. Również najnowsze dokumenty (Angular 1.4) nadal obejmują ng-attr-
Ashley Davis
120

Możesz poprzedzać atrybuty, ng-attraby ewaluować wyrażenie kątowe. Gdy wynik wyrażeń jest niezdefiniowany, usuwa to wartość z atrybutu.

<a ng-attr-href="{{value || undefined}}">Hello World</a>

Produkuje (gdy wartość jest fałszywa)

<a ng-attr-href="{{value || undefined}}" href>Hello World</a>

Nie używaj, falseponieważ spowoduje to wygenerowanie słowa „fałsz” jako wartości.

<a ng-attr-href="{{value || false}}" href="false">Hello World</a>

Podczas korzystania z tej sztuczki w dyrektywie. Atrybuty tej dyrektywy będą fałszywe, jeśli nie będą mieć wartości.

Na przykład powyższe byłoby fałszywe.

function post($scope, $el, $attr) {
      var url = $attr['href'] || false;
      alert(url === false);
}
Reactgular
źródło
3
Podoba mi się ta odpowiedź. Jednak nie sądzę, że jeśli wartość jest niezdefiniowana, ukryje atrybut. Ale może coś mi umknęło. Tak więc pierwszym wynikiem byłoby <a ng-attr-href="{{value || undefined}}" href> Hello World </a>
Roman K
13
@RomanK cześć, instrukcja stanowi, że undefinedjest to szczególny przypadek. „Podczas korzystania z ngAttr używana jest flaga allOrNothing zmiennej $ interpolate, więc jeśli jakiekolwiek wyrażenie w interpolowanym ciągu powoduje niezdefiniowanie, atrybut jest usuwany i nie dodawany do elementu.”
Reactgular,
9
Notatka, która ma pomóc przyszłym czytelnikom, wydaje się, że „niezdefiniowane” zachowanie zostało dodane w Angular 1.3. Używam 1.2.27 i obecnie muszę IE8.
Adam Marshall
3
Aby potwierdzić, że więcej Angular 1.2.15 wyświetli href, nawet jeśli wartość jest niezdefiniowana, wygląda na to, że niezdefiniowane zachowanie zaczyna się w Angular 1.3, jak stwierdzono w powyższym komentarzu.
Brian Ogden
Ważne jest, aby pamiętać, że ng-attr-foonadal będzie zawsze powoływać się na foodyrektywę, jeśli istnieje, nawet ng-attr-fooocenia się undefined. dyskusja
obejmuje
97

Pracowałem nad tym, ciężko ustawiając atrybut. I kontrolowanie stosowalności atrybutu za pomocą wartości logicznej dla atrybutu.

Oto fragment kodu:

<div contenteditable="{{ condition ? 'true' : 'false'}}"></div>

Mam nadzieję, że to pomoże.

jsbisht
źródło
Ponieważ angular może analizować wyrażenie IIF, działa to doskonale do oceny stanu w bieżącym zakresie i przypisywania wartości na podstawie tego stanu.
mccainz
22

W najnowszej wersji Angulara (1.1.5) wprowadzono dyrektywę warunkową o nazwie ngIf. To różni się od ngShowi ngHidetym, że elementy nie są ukryte, ale nie ujęte w DOM w ogóle. Są bardzo przydatne w przypadku komponentów, których tworzenie jest kosztowne, ale nie są używane:

<h1 ng-if="editMode" contenteditable=true>{{content.title}}</h1>
Brian Genisio
źródło
32
Wierzę, że ng-jeśli działa tylko na poziomie elementu, to znaczy nie można określić warunku tylko jednego atrybutu elementu.
Max Strater,
3
Rzeczywiście, ale możesz to zrobić<h1 ng-if="editMode" contenteditable="true"><h1 ng-if="!editMode">
ByScripts,
5
jednak uważaj, to ng-iftworzy nowy zakres.
Shimon Rachlenko
1
@ShimonRachlenko zgoda! Może to być źródłem nieporozumień i błędów. ng-iftworzy nowy zakres, ale ng-showtego nie robi. Ta niekonsekwencja zawsze była dla mnie bolącym miejscem. Defensywna reakcja programowa na to brzmi: „zawsze wiąż coś z kropką w wyrażeniu” i nie będzie to problemem.
Brian Genisio
Jeśli chcesz dodać atrybut, który jest tak naprawdę dyrektywą, działa to świetnie. Wstyd z powodu duplikacji kodu
Adam Marshall
16

Aby uzyskać atrybut pokazujący określoną wartość opartą na czeku logicznym lub zostać całkowicie pominięty, jeśli sprawdzenie boolean się nie powiodło, zastosowałem:

ng-attr-example="{{params.type == 'test' ? 'itWasTest' : undefined }}"

Przykładowe użycie:

<div ng-attr-class="{{params.type == 'test' ? 'itWasTest' : undefined }}">

Wyprowadziłby <div class="itWasTest">lub <div>na podstawie wartościparams.type

Dolina górska
źródło
9

<h1 ng-attr-contenteditable="{{isTrue || undefined }}">{{content.title}}</h1>

wygeneruje, gdy isTrue = true: <h1 contenteditable="true">{{content.title}}</h1>

a kiedy isTrue = false: <h1>{{content.title}}</h1>

Garfi
źródło
5
co jeśli chcę coś takiego jak <h1 contenteditable = "row">
SuperUberDuper
<h1 ng-attr-contenteditable="{{isTrue ? 'row' : undefined}}">{{content.title}} </h1>
PhatBuck,
To powinna być zaakceptowana odpowiedź. Mój scenariusz to<video ng-attr-autoplay="{{vm.autoplay || undefined}}" />
LucasM,
6

W odniesieniu do przyjętego rozwiązania, opublikowanego przez Ashleya Davisa, opisana metoda nadal drukuje atrybut w DOM, niezależnie od tego, że przypisana mu wartość jest niezdefiniowana.

Na przykład w konfiguracji pola wejściowego z zarówno modelem ng, jak i atrybutem wartości:

<input type="text" name="myInput" data-ng-attr-value="{{myValue}}" data-ng-model="myModel" />

Niezależnie od tego, co kryje się za myValue, wartość atrybut nadal jest drukowany w DOM, a zatem interpretowany. Model Ng zostaje wtedy zastąpiony.

Trochę nieprzyjemne, ale użycie ng-if działa:

<input type="text" name="myInput" data-ng-if="value" data-ng-attr-value="{{myValue}}" data-ng-model="myModel" />
<input type="text" name="myInput" data-ng-if="!value" data-ng-model="myModel" />

Poleciłbym bardziej szczegółowe sprawdzenie w dyrektywach ng-if :)

alexc
źródło
Dzięki takiemu podejściu będziesz jednak powtarzał ten sam kod.
Kalyan
To prawda, ale zapewnia bezpieczeństwo deklaracji modelu. Mój problem z użyciem zaakceptowanego rozwiązania polegał na tym, że atrybut wartości znalazł się w DOM, mając pierwszeństwo przed deklaracją modelu. Jeśli więc atrybut wartości jest pusty, ale model nie, model zostanie zastąpiony, aby przyjąć pustą wartość.
alexc
6

Możesz także użyć takiego wyrażenia:

<h1 ng-attr-contenteditable="{{ editMode ? true : false }}"></h1>
Kamuran Sönecek
źródło
5

Kilka miesięcy temu napisałem łatkę, aby to zrobić (po tym, jak ktoś zapytał o to w #angularjs na freenode).

Prawdopodobnie nie zostanie scalony, ale jest bardzo podobny do ngClass: https://github.com/angular/angular.js/pull/4269

Niezależnie od tego, czy zostanie scalony, czy nie, istniejące elementy ng-attr- * są prawdopodobnie odpowiednie dla twoich potrzeb (jak wspomnieli inni), chociaż mogą być nieco bardziej skomplikowane niż sugerowana funkcjonalność w stylu ngClass.

chronicsalsa
źródło
2

Aby sprawdzić poprawność pola wejściowego, możesz:

<input ng-model="discount" type="number" ng-attr-max="{{discountType == '%' ? 100 : undefined}}">

Będzie to miało zastosowanie atrybut maxaby 100tylko jeśli discountTypejest zdefiniowana jako%

Nestor Britez
źródło
1

Edycja : Ta odpowiedź dotyczy Angular2 +! Przepraszam, brakowało mi tagu!

Oryginalna odpowiedź:

Jeśli chodzi o bardzo prosty przypadek, w którym chcesz zastosować (lub ustawić) atrybut tylko, jeśli ustawiono określoną wartość wejściową, jest to tak proste, jak

<my-element [conditionalAttr]="optionalValue || false">

To jest tak samo jak:

<my-element [conditionalAttr]="optionalValue ? optionalValue : false">

(Tak więc opcjonalneWartość jest stosowana, jeśli podano inaczej wyrażenie jest fałszywe i atrybut nie jest stosowany).

Przykład: miałem przypadek, w którym pozwalałem zastosować kolor, ale także dowolne style, w których atrybut koloru nie działał tak, jak został już ustawiony (nawet jeśli nie podano koloru @Input ()):

@Component({
  selector: "rb-icon",
  styleUrls: ["icon.component.scss"],
  template: "<span class="ic-{{icon}}" [style.color]="color==color" [ngStyle]="styleObj" ></span>",
})
export class IconComponent {
   @Input() icon: string;
   @Input() color: string;
   @Input() styles: string;

   private styleObj: object;
...
}

Zatem „style.color” został ustawiony tylko wtedy, gdy istniał atrybut color, w przeciwnym razie można użyć atrybutu color w ciągu „styles”.

Oczywiście można to również osiągnąć za pomocą

[style.color]="color" 

i

@Input color: (string | boolean) = false;
Zaphoid
źródło
Angular.JS to Angular 1, który bardzo różni się od Angular 2+. Twoje rozwiązanie odpowiada na Angular 2+, ale poproszono o AngularJS (1).
ssc-hrep3
@ ssc-hrep3: Masz rację. Przepraszam, że za tym tęskniłem! Dzięki. Zredagowałem odpowiedź, aby to podkreślić. :-)
Zaphoid,
is angularjs not angular, angularjs is angular 1
dgzornoza
0

Na wypadek, gdybyś potrzebował rozwiązania dla Angulara 2, skorzystaj z powiązania właściwości, jak poniżej, np. Jeśli chcesz, aby dane wejściowe były odczytywane tylko warunkowo, a następnie dodaj w nawiasach kwadratowych atrybut attrbute, a następnie znak = i wyrażenie.

<input [readonly]="mode=='VIEW'"> 
Sanjay Singh
źródło
jest angularjs (angular1) not angular (angular2)
dgzornoza
Angular 2+ i Angular JS nie są takie same, bardziej przypominają różne produkty.
Sanjay Singh
0

Udało mi się uruchomić to:

ng-attr-aria-current="{{::item.isSelected==true ? 'page' : undefined}}"

Zaletą jest to, że jeśli item.isSelected ma wartość false, wówczas atrybut po prostu nie jest renderowany.

Richard Strickland
źródło