Cara mendeklarasikan variabel dalam templat di Angular


203

Saya memiliki template berikut:

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

dan ingin berakhir dengan:

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

Apakah ada cara untuk melakukannya?


Saya tertarik untuk mengetahui apa persyaratan / kasus penggunaan untuk ingin mengubah nama parameter yang mengikat seperti contoh ini?
LDJ

31
Itu hanya untuk mencegah pengulangan sesuatu seperti tab [elemen] .val secara instan. Saya tahu saya bisa menyelesaikan masalah dalam komponen, tapi saya hanya melihat bagaimana melakukannya di template (walaupun saya mungkin tidak berakhir dengan solusi itu).
Scipion

2
@LDJ satu contoh penggunaan: efisiensi. Gunakan contoh stackblitz.com/angular/… <mat-checkbox [centang] = "descendantsAllSelected (node)" [indeterminate] = "descendantsPartiallySelected (node)" (ubah) = "todoItemSelectionToggle (node)"> {{node. item}} </mat-checkbox> sebenarnya descendantsPartiallySelected () memanggil descendantsAllSelected (). Ini berarti kadang-kadang keturunan AllSelected disebut dua kali. Jika ada variabel lokal, ini bisa dihindari.
Steven.Xi

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

@dasfdsa saya percaya user1 === user, dengan demikian Anda melakukannya *ngIf="{name:'john'} as user1atau *ngIf="{name:'john'};let userseperti dalam jawaban yurzui .
CPHPython

Jawaban:


175

Memperbarui

Kami hanya bisa membuat arahan suka *ngIfdan menyebutnya*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);
  }
}

dengan *ngVararahan ini kita bisa menggunakan yang berikut ini

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

atau

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

atau

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

atau

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

Contoh Plunker Angular4 ngVar

Lihat juga

Jawaban asli

V4 sudut

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

melihat

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

komponen.ts

export class AppComponent {
  x = 5;
}

3) Jika Anda tidak ingin membuat wrapper seperti divyang dapat Anda gunakanng-container

melihat

<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>

Seperti @Keith disebutkan dalam komentar

ini akan bekerja dalam banyak kasus tetapi ini bukan solusi umum karena bergantung pada variabel yang benar

Lihat pembaruan untuk pendekatan lain.


10
ini akan bekerja dalam banyak kasus tetapi itu bukan solusi umum karena ini bergantung pada variablekebenaran
Keith

6
@Keith Terima kasih telah menunjukkan ini. Anda dapat melihat jawaban saya yang diperbarui
yurzui

3
Ini harus menjadi jawaban baru karena 1) lebih modern daripada solusi lain 2) merangkum permintaan tarik yang ditautkan dalam jawaban saat ini dan menghemat banyak waktu 3) memasukkan contoh inline daripada oleh tautan eksternal. Terima kasih telah menunjukkan ini. AFAIK objek apa pun yang dibungkus {}akan dievaluasi kebenarannya, sehingga solusi ini cukup kuat.
kvanberendonck

4
Misalnya, tombol yang dapat diperluas: *ngIf="{ expanded: false } as scope"dan kemudian jika Anda menggunakan bootstrap, Anda bisa menggunakan [ngClass]="{ 'in': scope.expanded }"dan (click)="scope.expanded = !scope.expanded"bukannya menambahkan apa pun ke file js/ Anda ts.
kvanberendonck

1
masalah github terkait (menunjukkan penggunaan yang sederhana *ngIfalih-alih hal-hal ngvar khusus): github.com/angular/angular/issues/14985
phil294

81

Jelek, tapi:

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

Saat digunakan dengan pipa async:

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

4
Itulah yang saya buat secara naluriah - itu bekerja dengan *ngFor="let a of [(someStream$ | async).someA]baik juga. Saya kira digunakan dengan <ng-container>itu melayani pekerjaan dengan benar!
Angelos Pikoulas

2
Jika demikian *ngFor, ingatlah bahwa semua konten bersarang akan dibuat kembali jika nilai variabel berubah, hingga Anda menentukan trackByfungsi yang mengembalikan id yang sama untuk semua nilai.
Valeriy Katkov

76

Anda dapat mendeklarasikan variabel dalam kode html dengan menggunakan templateelemen di sudut 2 atau ng-templatedi sudut 4 +.

Templat memiliki objek konteks yang propertinya dapat ditetapkan ke variabel menggunakan letsintaks yang mengikat. Perhatikan bahwa Anda harus menentukan outlet untuk template, tetapi itu bisa menjadi referensi untuk dirinya sendiri.

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

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

Anda dapat mengurangi jumlah kode dengan menggunakan $implicitproperti dari objek konteks alih-alih properti kustom.

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

Objek konteks dapat berupa objek literal atau ekspresi yang mengikat lainnya. Bahkan pipa tampaknya berfungsi ketika dikelilingi oleh tanda kurung.

Contoh yang valid dari ngTemplateOutletContext:

  • [ngTemplateOutletContext]="{ aVariable: 123 }"
  • [ngTemplateOutletContext]="{ aVariable: (3.141592 | number:'3.1-5') }"
  • [ngTemplateOutletContext]="{ aVariable: anotherVariable }" Gunakan dengan let-a="aVariable"
  • [ngTemplateOutletContext]="{ $implicit: anotherVariable }" Gunakan dengan let-a
  • [ngTemplateOutletContext]="ctx"di mana ctxadalah milik umum

Untuk membuatnya berfungsi, saya harus mengubah kode Anda dari '<template ...' ke '<ng-template ...'.
Humppakäräjät

2
Yap, Anda hanya dapat menggunakan <template>dalam Angular 2. Anda dapat menggunakan salah satu <template>atau <ng-template>dalam Angular 4, tetapi Anda hanya harus menggunakan <ng-template>. 5 sudut menjatuhkan dukungan untuk <template>.
Steven Liekens

Untuk apa t?
matttm

1
@matttm #tadalah variabel templat yang menyimpan ng-template. Ini digunakan [ngTemplateOutlet]="t"untuk membuat referensi ng-template itu sendiri.
Steven Liekens

Ini aneh, tetapi berhasil! Sudut harus membuat ini lebih sederhana, dengan direktif variabel bawaan. Terima kasih.
TetraDev

57

pembaruan 3

Masalah 2451 diperbaiki dalam Angular 4.0.0

Lihat juga

pembaruan 2

Ini tidak didukung.

Ada variabel templat tetapi tidak didukung untuk menetapkan nilai arbitrer. Mereka hanya dapat digunakan untuk merujuk pada unsur-unsur yang mereka terapkan, diekspor nama arahan atau komponen dan variabel ruang lingkup untuk arahan struktural seperti ngFor,

Lihat juga https://github.com/angular/angular/issues/2451

Perbarui 1

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

dan menginisialisasi itu seperti

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

atau

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

dan gunakan variabel like

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

(tidak diuji)

  • #aVariablemembuat referensi ke VarDirective( exportAs: 'var')
  • var="abc"instantiates VarDirectivedan meneruskan nilai string "abc"ke input nilainya.
  • aVariable.varmembaca nilai yang diberikan ke input vararahan var.

Tidakkah mungkin untuk membuat arahan struktural untuk melakukannya?
Scipion

Jika Anda membutuhkan ini berulang kali maka arahan dapat melakukan apa yang Anda inginkan. Arahan struktural menciptakan pandangannya sendiri, itu mungkin bukan yang Anda inginkan.
Günter Zöchbauer

1
@ GünterZöchbauer, barang yang sangat bagus. Saya tahu bahwa ini mungkin praktik yang lebih baik untuk variabel dihitung / disiapkan dalam component.tsfile. Tetapi jauh lebih mudah bagi saya untuk melihatnya dalam beberapa kasus karena skema sinkronisasi yang saya terapkan di seluruh aplikasi saya. Saya mengambil keuntungan dari aturan referensi javascript ketika variabel yang berbeda menunjuk ke objek yang sama.
AmmarCSE

Saya mendapatkan kesalahan seperti There is no directive with "exportAs" set to "var". Adakah yang bisa memberi tahu saya kesalahan apa yang saya lakukan? Saya telah menggunakan arahan di atas.
Partha Sarathi Ghosh

Mungkin Anda tidak menambahkan direktif untuk declarations: [...]dari @NgModule(). Jika ini bukan masalahnya, buat pertanyaan baru dan berikan kode yang memungkinkan untuk mendiagnosis masalahnya.
Günter Zöchbauer


11

Berikut adalah arahan yang saya tulis yang memperluas penggunaan parameter dekorator exportAs, dan memungkinkan Anda untuk menggunakan kamus sebagai variabel lokal.

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( ) {
    }
}

Anda dapat menggunakannya sebagai berikut di templat:

<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>

Tentu saja #local dapat berupa nama variabel lokal yang valid.


Tidak lulus build 'produksi' sebagaimana adanya (juga ditampilkan sebagai kesalahan oleh IDE). Tambahkan [key: string]: any;ke Classuntuk menyiasati ini.
Charly

7

Jika Anda ingin mendapatkan respons dari suatu fungsi dan mengubahnya menjadi variabel, Anda dapat menggunakannya seperti yang berikut ini di templat, gunakan ng-containeruntuk menghindari memodifikasi templat.

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

Dan metode dalam komponen bisa berupa sesuatu

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

5

Jika Anda memerlukan dukungan pelengkapan otomatis dari dalam template Anda dari Layanan Bahasa Angular :

Sinkronis:

myVar = { hello: '' };

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

Menggunakan pipa async:

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

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

2

Saya menggunakan sudut 6x dan saya berakhir dengan menggunakan cuplikan di bawah ini. Saya memiliki scenerio tempat saya mencari pengguna dari objek tugas. ini berisi berbagai pengguna tetapi saya harus memilih pengguna yang ditugaskan.

<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

Ini jauh lebih sederhana, tidak perlu tambahan apa pun. Dalam contoh saya, saya menyatakan variabel "terbuka" dan kemudian menggunakannya.

   <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>

Anda memberi nama tag, itu tidak menyatakan variabel
Amirreza

1
@Amirreza, tepatnya saya menggunakan ElementRef untuk menyimpan nilai.
Jack Rus

Luar biasa! Saya harus menggunakan "?"karena saya punya pesan "Identifier 'value' tidak didefinisikan" seperti ini => "open? .Value" Tapi itu berfungsi !!
A. Morel

1

Saya menyukai pendekatan menciptakan arahan untuk melakukan ini (panggilan bagus @ yurzui).

Saya akhirnya menemukan sebuah artikel Sedang Angular "let" Directive yang menjelaskan masalah ini dengan baik dan mengusulkan petunjuk custom let yang akhirnya bekerja dengan baik untuk use case saya dengan perubahan kode minimal.

Inilah intinya (pada saat posting) dengan modifikasi saya:

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
  }
}

Perubahan utama saya adalah:

  • mengubah awalan dari 'ng' ke 'app' (Anda harus menggunakan apa pun awalan khusus aplikasi Anda)
  • berubah appLet: TmenjadiappLet: T | null

Tidak yakin mengapa tim Angular tidak hanya membuat arahan resmi tetapi juga apa saja.

Kredit kode sumber asli ke @AustinMatherne


Ini adalah pendekatan favorit saya pada halaman dan itu berhasil untuk saya.
Skychan

1

Jawaban singkat yang membantu seseorang

  • Variabel Referensi Templat sering merujuk ke elemen DOM dalam templat.
  • Juga merujuk ke komponen dan arahan sudut atau web.
  • Itu berarti Anda dapat dengan mudah mengakses varible di mana saja dalam templat

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

  • Nyatakan variabel referensi menggunakan simbol hash (#)
  • Dapat dapat meneruskan variabel sebagai parameter pada suatu acara

masukkan deskripsi gambar di sini

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

* Namun, Anda dapat menggunakan dekorator ViewChild untuk referensi di dalam komponen Anda.

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

Referensi firstNameInput variabel di dalam Komponen

@ViewChild('firstNameInput') nameInputRef: ElementRef;

Setelah itu, Anda dapat menggunakan this.nameInputRef di mana saja di dalam Komponen Anda.

Bekerja dengan ng-template

Dalam hal ng-template, ini sedikit berbeda karena masing-masing template memiliki set variabel input sendiri.

masukkan deskripsi gambar di sini

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


1

Bagi mereka yang memutuskan untuk menggunakan arahan struktural sebagai pengganti *ngIf, perlu diingat bahwa konteks arahan tidak tipe diperiksa secara default. Untuk membuat tipe ngTemplateContextGuardproperti direktif aman harus ditambahkan, lihat Mengetik konteks direktif . Sebagai contoh:

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;
}

Arahan dapat digunakan seperti *ngIf, kecuali bahwa itu dapat menyimpan nilai - nilai yang salah :

<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>

Satu-satunya kelemahan dibandingkan *ngIfadalah bahwa Layanan Bahasa Angular tidak dapat mengetahui tipe variabel sehingga tidak ada penyelesaian kode dalam templat. Saya harap ini akan segera diperbaiki.


Ini berfungsi tetapi intellisense tidak. Saya menggunakan sudut 8.
Tx_monster
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.