Açısal şablonda bir değişken nasıl bildirilir


202

Aşağıdaki şablon var:

<div>
  <span>{{aVariable}}</span>
</div>

ve sonuç olarak:

<div "let a = aVariable">
  <span>{{a}}</span>
</div>

Yapmanın bir yolu var mı?


Bu örnek gibi bir bağlanma parametresinin adını değiştirmek için gereksinim / kullanım durumunun ne olduğunu bilmek isterim?
LDJ

31
Sadece tab [element] .val gibi bir şeyin tekrarlanmasını önlemek. Bileşendeki sorunu çözebileceğimi biliyorum, ancak sadece şablonda nasıl yapılacağına bakıyordum (bu çözümle bitmeyebilirim bile).
Scipion

2
@LDJ bir örnek kullanım örneği: verimlilik. Örneklemini kullanarak stackblitz.com/angular/... {{düğüm <mat onay kutusu = "descendantsAllSelected (düğüm)" [belirsiz] = "descendantsPartiallySelected (düğüm)" (değişiklik) = "todoItemSelectionToggle (düğüm)" [kontrol]>. item}} </mat-checkbox> aslında descendantsPartiallySelected (), descendantsAllSelected () öğesini çağırır. Zaman zaman torunlarAllSelected iki kez çağrılır. Yerel bir değişken varsa, bu önlenebilir.
Steven.Xi

3
<div *ngIf="{name:'john'} as user1; let user"> <i>{{user1|json}}</i> <i>{{user|json}}</i> </div>
dasfdsa

@dasfdsa inanıyorum user1 === userböylece birini yapın *ngIf="{name:'john'} as user1ya *ngIf="{name:'john'};let userolduğu gibi yurzui cevabı .
CPHPython

Yanıtlar:


175

Güncelleme

Sadece direktifler oluşturabilir *ngIfve buna*ngVar

ng-var.directive.ts

@Directive({
    selector: '[ngVar]',
})
export class VarDirective {
  @Input()
  set ngVar(context: any) {
    this.context.$implicit = this.context.ngVar = context;
    this.updateView();
  }

  context: any = {};

  constructor(private vcRef: ViewContainerRef, private templateRef: TemplateRef<any>) {}

  updateView() {
    this.vcRef.clear();
    this.vcRef.createEmbeddedView(this.templateRef, this.context);
  }
}

bu *ngVardirektifle aşağıdakileri kullanabiliriz

<div *ngVar="false as variable">
      <span>{{variable | json}}</span>
</div>

veya

<div *ngVar="false; let variable">
    <span>{{variable | json}}</span>
</div>

veya

<div *ngVar="45 as variable">
    <span>{{variable | json}}</span>
</div>

veya

<div *ngVar="{ x: 4 } as variable">
    <span>{{variable | json}}</span>
</div>

Plunker Örneği Açısal4 ngVar

Ayrıca bakınız

Orijinal cevap

Açısal v4

1) div+ ngIf+let

<div *ngIf="{ a: 1, b: 2 }; let variable">
  <span>{{variable.a}}</span>
  <span>{{variable.b}}</span>
</div>

2) div+ ngIf+as

görünüm

<div *ngIf="{ a: 1, b: 2, c: 3 + x } as variable">
  <span>{{variable.a}}</span>
  <span>{{variable.b}}</span>
  <span>{{variable.c}}</span>
</div>

component.ts

export class AppComponent {
  x = 5;
}

3) divKullanabileceğiniz gibi sarıcı oluşturmak istemiyorsanızng-container

görünüm

<ng-container *ngIf="{ a: 1, b: 2, c: 3 + x } as variable">
  <span>{{variable.a}}</span>
  <span>{{variable.b}}</span>
  <span>{{variable.c}}</span>
</ng-container>

@Keith yorumlarda belirtildiği gibi

bu çoğu durumda işe yarayacaktır, ancak değişken bir doğruluk olduğu için genel bir çözüm değildir.

Başka bir yaklaşım için güncellemeye bakın.


10
Bu çoğu durumda çalışacak ancak güvenir çünkü genel bir çözüm değildir variableolmanın truthy
Keith

6
@ Keith Bunu işaret ettiğiniz için teşekkürler. Güncel
cevabıma

3
Bu yeni yanıt olmalıdır, çünkü 1) diğer çözümden daha moderndir 2) mevcut cevapta bağlantılı çekme taleplerini özetler ve çok zaman kazandırır 3) harici bağlantıdan ziyade satır içi örnekleri içerir. Bunu gösterdiğin için teşekkürler. AFAIK, herhangi bir nesnenin {}gerçeğe uygunluğunu değerlendirecektir, bu nedenle bu çözüm oldukça sağlamdır.
kvanberendonck

4
Örneğin, genişletilebilir düğmeleri: *ngIf="{ expanded: false } as scope"ve ön yükleme alanı kullanıyorsanız o zaman sadece kullanabilirsiniz [ngClass]="{ 'in': scope.expanded }"ve (click)="scope.expanded = !scope.expanded"yerine bir şey ekleme js/ tsdosyalar.
kvanberendonck

1
ilgili github sorunu ( *ngIfözel ngvar şeyler yerine basit kullanarak dikkat çekiyor ): github.com/angular/angular/issues/14985
phil294 14:17

81

Çirkin, ama:

<div *ngFor="let a of [aVariable]">
  <span>{{a}}</span>
</div>

Zaman uyumsuz boru ile kullanıldığında:

<div *ngFor="let a of [aVariable | async]">
  <span>{{a.prop1}}</span>
  <span>{{a.prop2}}</span>
</div>

4
İçgüdüsel olarak bulduğum bu - *ngFor="let a of [(someStream$ | async).someA]aynı zamanda da çalışıyor . Sanırım bir ile kullanılan <ng-container>iş oldukça doğru hizmet vermektedir!
Angelos Pikoulas

2
Böyle bir durumda, tüm değerler için aynı kimliği döndüren *ngForbir trackByişlev belirleyene kadar, değişken değeri değişirse tüm iç içe içeriğin yeniden oluşturulacağını unutmayın .
Valeriy Katkov

76

templateAçısal 2 veya ng-templateAçısal 4+ içindeki bir öğeyi kullanarak html kodundaki değişkenleri bildirebilirsiniz .

Şablonlar, özellikleri letbağlayıcı sözdizimi kullanılarak değişkenlere atanabilen bir bağlam nesnesine sahiptir . Şablon için bir çıkış belirtmeniz gerektiğini unutmayın, ancak bunun kendisi için bir referans olabilir.

<ng-template let-a="aVariable" [ngTemplateOutletContext]="{ aVariable: 123 }" [ngTemplateOutlet]="selfie" #selfie>
  <div>
    <span>{{a}}</span>
  </div>
</ng-template>

<!-- Output
<div>
  <span>123</span>
</div>
-->

$implicitÖzel bir özellik yerine bağlam nesnesinin özelliğini kullanarak kod miktarını azaltabilirsiniz .

<ng-template let-a [ngTemplateOutletContext]="{ $implicit: 123 }" [ngTemplateOutlet]="t" #t>
  <div>
    <span>{{a}}</span>
  </div>
</ng-template>

Bağlam nesnesi, değişmez bir nesne veya başka bir bağlayıcı ifade olabilir. Borular bile parantezle çevrili gibi görünüyor.

Geçerli örnekler ngTemplateOutletContext:

  • [ngTemplateOutletContext]="{ aVariable: 123 }"
  • [ngTemplateOutletContext]="{ aVariable: (3.141592 | number:'3.1-5') }"
  • [ngTemplateOutletContext]="{ aVariable: anotherVariable }" La kullan let-a="aVariable"
  • [ngTemplateOutletContext]="{ $implicit: anotherVariable }" La kullan let-a
  • [ngTemplateOutletContext]="ctx"ctxkamu malı nerede

Çalışması için kodunuzu '<template ...' yerine '<ng-template ...' olarak değiştirmek zorunda kaldım.
Humppakäräjät

2
Evet, yalnızca <template>Açısal 2'de kullanabilirsiniz . Açısal 4'te birini <template>veya <ng-template>Açıyı kullanabilirsiniz , ancak yalnızca kullanmalısınız <ng-template>. Açısal 5 için destek düştü <template>.
Steven Liekens

Ne tiçin?
matttm

1
@matttm #tdepolayan bir şablon değişkendir ng-template. [ngTemplateOutlet]="t"Ng-şablonu referansını kendisi yapmak için kullanılır .
Steven Liekens

Bu tuhaf, ama işe yarıyor! Açısal, bunu yerleşik değişken yönergesi ile daha basit hale getirmelidir. Teşekkürler.
TetraDev

57

güncelleme 3

Sayı 2451, Açısal 4.0.0'da düzeltildi

Ayrıca bakınız

güncelleme 2

Bu desteklenmiyor.

Şablon değişkenleri var, ancak rastgele değerler ataması desteklenmiyor. Yalnızca uygulandıkları öğelere, direktiflerin veya bileşenlerin dışa aktarılan adlarına ve yapısal direktifler için kapsam değişkenlerine atıfta bulunmak için kullanılabilir ngFor,

Ayrıca bkz. Https://github.com/angular/angular/issues/2451

Güncelleme 1

@Directive({
  selector: '[var]',
  exportAs: 'var'
})
class VarDirective {
  @Input() var:any;
}

ve şu şekilde başlat

<div #aVariable="var" var="abc"></div>

veya

<div #aVariable="var" [var]="'abc'"></div>

ve değişkeni aşağıdaki gibi kullanın

<div>{{aVariable.var}}</div>

(test edilmedi)

  • #aVariableVarDirective( exportAs: 'var') öğesine bir başvuru oluşturur
  • var="abc"VarDirectivedize değerini başlatır ve dize değerini "abc"değer girdisine geçirir .
  • aVariable.varvaryönergeler vargirişine atanan değeri okur .

Bunu yapmak için yapısal bir yönerge oluşturmak mümkün olmaz mıydı?
Scipion

Buna tekrar tekrar ihtiyacınız varsa, bir yönerge istediğinizi yapabilir. Yapısal bir yönerge kendi görüşünü oluşturur, muhtemelen istediğiniz şey bu değildir.
Günter Zöchbauer

1
@ GünterZöchbauer, çok güzel şeyler. component.tsDosyada değişkenlerin hesaplanması / hazırlanması için muhtemelen daha iyi bir uygulama olduğunu biliyorum . Ancak, tüm uygulama boyunca uyguladığım bir senkronizasyon şeması nedeniyle bazı durumlarda onları görmem çok daha kolay. Farklı değişkenler aynı nesneye işaret ettiğinde javascript başvuru kurallarından yararlanıyorum.
AmmarCSE

Gibi bir hata alıyorum There is no directive with "exportAs" set to "var". Birisi bana ne hata yaptığımı söyleyebilir mi? Yukarıdaki yönergeyi kullandım.
Partha Sarathi Ghosh

Belki hiç yönergesini eklemek vermedi declarations: [...]ait @NgModule(). Sorun bu değilse, lütfen yeni bir soru oluşturun ve sorunun teşhis edilmesine izin veren kodu sağlayın.
Günter Zöchbauer


11

Burada, exportAs decorator parametresinin kullanımı üzerine genişleyen ve yerel bir değişken olarak bir sözlük kullanmanıza izin veren bir direktif var.

import { Directive, Input } from "@angular/core";
@Directive({
    selector:"[localVariables]",
    exportAs:"localVariables"
})
export class LocalVariables {
    @Input("localVariables") set localVariables( struct: any ) {
        if ( typeof struct === "object" ) {
            for( var variableName in struct ) {
                this[variableName] = struct[variableName];
            }
        }
    }
    constructor( ) {
    }
}

Bir şablonda aşağıdaki gibi kullanabilirsiniz:

<div #local="localVariables" [localVariables]="{a: 1, b: 2, c: 3+2}">
   <span>a = {{local.a}}</span>
   <span>b = {{local.b}}</span>
   <span>c = {{local.c}}</span>
</div>

Tabii ki #local geçerli herhangi bir yerel değişken adı olabilir.


'Üretim' derlemesini olduğu gibi geçirmez (IDE'ler tarafından da hata olarak gösterilir). Ekle [key: string]: any;için Classbu çevrede alır.
Charly

7

Bir işlevin yanıtını almak ve bir değişkene ayarlamak isterseniz, şablonda ng-containerdeğişiklik yapmaktan kaçınmak için bunu şablonda aşağıdaki gibi kullanabilirsiniz .

<ng-container *ngIf="methodName(parameters) as respObject">
  {{respObject.name}}
</ng-container>

Ve bileşendeki yöntem şöyle bir şey olabilir

methodName(parameters: any): any {
  return {name: 'Test name'};
}

5

Açısal Dil Hizmeti'ndeki şablonlarınızın içinden otomatik tamamlama desteğine ihtiyacınız varsa :

Senkron:

myVar = { hello: '' };

<ng-container *ngIf="myVar; let var;">
  {{var.hello}}
</ng-container>

Zaman uyumsuz boru kullanma:

myVar$ = of({ hello: '' });

<ng-container *ngIf="myVar$ | async; let var;">
  {{var.hello}}
</ng-container>

2

Açısal 6x kullanıyorum ve aşağıdaki snippet'i kullanarak bitirdim. Görev nesnesinden kullanıcı bulabileceğim bir senaryom var. kullanıcı dizisi içeriyor ancak atanmış kullanıcı seçmem gerekiyor.

<ng-container *ngTemplateOutlet="memberTemplate; context:{o: getAssignee(task) }">
</ng-container>
<ng-template #memberTemplate let-user="o">
  <ng-container *ngIf="user">
    <div class="d-flex flex-row-reverse">
      <span class="image-block">
        <ngx-avatar placement="left" ngbTooltip="{{user.firstName}} {{user.lastName}}" class="task-assigned" value="28%" [src]="user.googleId" size="32"></ngx-avatar>
      </span>
    </div>
  </ng-container>
</ng-template>

1

Çok daha basit, ek bir şeye gerek yok. Örneğimde "open" değişkenini bildiriyorum ve sonra kullanıyorum.

   <mat-accordion class="accord-align" #open>
      <mat-expansion-panel hideToggle="true" (opened)="open.value=true" (closed)="open.value=false">
        <mat-expansion-panel-header>
          <span class="accord-title">Review Policy Summary</span>
          <span class="spacer"></span>
          <a *ngIf="!open.value" class="f-accent">SHOW</a>
          <a *ngIf="open.value" class="f-accent">HIDE</a>
        </mat-expansion-panel-header>
        <mat-divider></mat-divider>
        <!-- Quote Details Component -->
        <quote-details [quote]="quote"></quote-details>
      </mat-expansion-panel>
    </mat-accordion>

Eğer bir etiket adlandırma, bu değişken ilan değil
Amirreza

1
@Amirreza, kesin olarak ben bir değeri depolamak için ElementRef kullanıyorum.
Jack Rus

Müthiş! "?""Tanımlayıcı 'değeri'" bu => "open? .Value" gibi tanımlanmadı iletisi vardı çünkü kullanmak zorunda kaldı ama çalışıyor!
A. Morel

1

Bunu yapmak için bir yönerge oluşturma yaklaşımını beğendim (iyi çağrı @yurzui).

Bu sorunu güzelce açıklayan ve asgari kod değişiklikleri ile kullanım durumum için harika bir sonuç veren özel bir izin yönergesi öneren bir Orta makale Açısal "let" Direktifi bulduk .

İşte değişikliklerimle birlikte (gönderme sırasında) öz:

import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core'

interface LetContext <T> {
  appLet: T | null
}

@Directive({
  selector: '[appLet]',
})
export class LetDirective <T> {
  private _context: LetContext <T> = { appLet: null }

  constructor(_viewContainer: ViewContainerRef, _templateRef: TemplateRef <LetContext <T> >) {
    _viewContainer.createEmbeddedView(_templateRef, this._context)
  }

  @Input()
  set appLet(value: T) {
    this._context.appLet = value
  }
}

Temel değişikliklerim:

  • öneki 'ng' yerine 'app' olarak değiştirme (uygulamanızın özel öneki ne olursa olsun kullanmalısınız)
  • değişen appLet: TiçinappLet: T | null

Açısal ekibin neden sadece resmi bir ngLet direktifi değil, aynı zamanda ne yaptığını da bilmiyoruz.

Orijinal kaynak kodu kredisi @AustinMatherne'a gidiyor


Bu benim en sevdiğim yaklaşımdı ve benim için çalıştı.
Skychan

1

Birine yardım eden kısa cevap

  • Şablon Referans değişkeni genellikle bir şablondaki DOM öğesine başvurur.
  • Ayrıca açısal veya web bileşeni ve yönergesine atıfta bulunun.
  • Bu, değişkenin bir şablonda herhangi bir yere kolayca erişebileceğiniz anlamına gelir

resim açıklamasını buraya girin

resim açıklamasını buraya girin

  • Kare sembolünü (#) kullanarak referans değişkeni bildirin
  • Bir değişkeni bir olaya parametre olarak iletebilir

resim açıklamasını buraya girin

  show(lastName: HTMLInputElement){
    this.fullName = this.nameInputRef.nativeElement.value + ' ' + lastName.value;
    this.ctx.fullName = this.fullName;
  }

* Bununla birlikte, bileşeninizde referans vermek için ViewChild dekoratörünü kullanabilirsiniz.

import {ViewChild, ElementRef} from '@angular/core';

Bileşen içindeki firstNameInput değişkeni başvurusu

@ViewChild('firstNameInput') nameInputRef: ElementRef;

Bundan sonra, bu.nameInputRef bileşenini Bileşeninizin içinde herhangi bir yerde kullanabilirsiniz.

Ng-template ile çalışma

Ng-şablonu söz konusu olduğunda, biraz farklıdır çünkü her şablonun kendi girdi değişkenleri seti vardır.

resim açıklamasını buraya girin

https://stackblitz.com/edit/angular-2-template-reference-variable


1

Bunun yerine yapısal bir yönerge kullanmaya karar verenler için *ngIf, yönerge içeriğinin varsayılan olarak tür işaretli olmadığını unutmayın. Tür oluşturmak için güvenli yönerge ngTemplateContextGuardözelliği eklenmelidir, bkz . Yönerge bağlamını yazma . Örneğin:

import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({
    // don't use 'ng' prefix since it's reserved for Angular
    selector: '[appVar]',
})
export class VarDirective<T = unknown> {
    // https://angular.io/guide/structural-directives#typing-the-directives-context
    static ngTemplateContextGuard<T>(dir: VarDirective<T>, ctx: any): ctx is Context<T> {
        return true;
    }

    private context?: Context<T>;

    constructor(
        private vcRef: ViewContainerRef,
        private templateRef: TemplateRef<Context<T>>
    ) {}

    @Input()
    set appVar(value: T) {
        if (this.context) {
            this.context.appVar = value;
        } else {
            this.context = { appVar: value };
            this.vcRef.createEmbeddedView(this.templateRef, this.context);
        }
    }
}

interface Context<T> {
    appVar: T;
}

Yönerge, yanlış değerleri *ngIfdepolaması dışında aynen kullanılabilir :

<ng-container *appVar="false as value">{{value}}</ng-container>

<!-- error: User doesn't have `nam` property-->
<ng-container *appVar="user as user">{{user.nam}}</ng-container>

<ng-container *appVar="user$ | async as user">{{user.name}}</ng-container>

Karşılaştırma yapılan tek dezavantaj *ngIf, Açısal Dil Hizmetinin değişken türünü anlayamamasıdır, bu nedenle şablonlarda kod tamamlama olmaz. Umarım yakında düzeltilecektir.


Bu işe yarıyor ama akıllı değil. Açısal 8 kullanıyorum
Tx_monster
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.