Angularのテンプレートで変数を宣言する方法


199

次のテンプレートがあります。

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

そして終わりにしたいと思います:

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

行う方法はありますか?


この例のようなバインディングパラメータの名前を変更したい場合の要件/使用例を知りたいですか?
LDJ 2016

29
これは、インスタンスによってtab [element] .valなどの繰り返しを防ぐためだけです。私はコンポーネントで問題を解決できることを知っていますが、テンプレートでそれを行う方法を検討していました(その解決策にはならなかったとしても)。
Scipion

2
@LDJの1つのサンプルユースケース:効率。stackblitz.com/angular/…のサンプルを使用します。 <mat-checkbox [checked] = "descendantsAllSelected(node)" [indeterminate] = "descendantsPartiallySelected(node)"(change)= "todoItemSelectionToggle(node)"> {{node。 item}} </ mat-checkbox>実際には、descendantsPartiallySelected()がdescendantsAllSelected()を呼び出します。つまり、descendantsAllSelectedが2回呼び出されることがあります。ローカル変数がある場合、これは回避できます。
Steven.Xi 2018

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

@dasfdsa私は信じているuser1 === userので、あなたはそうする*ngIf="{name:'john'} as user1*ngIf="{name:'john'};let useryurzuiの答えのように
CPHPython

回答:


168

更新

のようなディレクティブを作成*ngIfして呼び出すことができます*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);
  }
}

この*ngVarディレクティブを使用すると、次を使用できます

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

または

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

または

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

または

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

プランカーの例Angular4 ngVar

こちらもご覧ください

元の答え

Angular 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

見る

<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)次のようなラッパーを作成したくない場合 div使用できるng-container

見る

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

@キースがコメントで述べたように

これはほとんどの場合に機能しますが、変数が真実であることに依存しているため、一般的な解決策ではありません

別のアプローチについては、更新を参照してください。


10
これは、ほとんどの場合に動作しますが、それはに依存しているので、それが一般的な解決策ではありませんvariabletruthyいる
キース・

6
@キースこれを指摘してくれてありがとう。私の更新された回答を見ることができます
yurzui

3
これは、1)他のソリューションよりも新しい2)現在の回答にリンクされたプルリクエストを要約し、多くの時間を節約するので、新しい回答になるはずです3)外部リンクではなくインラインで例が含まれています。これを見せてくれてありがとう。AFAIKでラップされたオブジェクトは真実{}と評価されるため、このソリューションはかなり堅牢です。
kvanberendonck 2017

4
例えば、拡張可能なボタンは:*ngIf="{ expanded: false } as scope"あなたは、ブートストラップを使用しているならば、あなただけ使用することができます[ngClass]="{ 'in': scope.expanded }"し、(click)="scope.expanded = !scope.expanded"代わりにあなたに何かを追加するjs/ tsファイル。
kvanberendonck 2017

1
関連するgithubの問題(*ngIfカスタムのngvarの代わりに単純なものを使用することを指摘):github.com/angular/angular/issues/14985
phil294

79

醜いですが:

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

非同期パイプで使用する場合:

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

4
それは私が本能的に思いついたものです-それ*ngFor="let a of [(someStream$ | async).someA]は同様に動作します。私は<ng-container>それを使って推測すると、仕事にかなり役立ちます!
Angelos Pikoulas

1
の場合、すべての値に対して同じIDを返す関数を*ngFor指定するまで、変数の値が変更されると、すべてのネストされたコンテンツが再作成されることに注意してくださいtrackBy
Valeriy Katkov

72

を使用して、htmlコードで変数を宣言できます。 templateAngular 2の要素か、ng-template Angular 4+の。

テンプレートにはコンテキストオブジェクトがあり、そのプロパティを使用して変数に割り当てることができます。 letバインディング構文ます。テンプレートのアウトレットを指定する必要がありますが、それ自体への参照にすることもできます。

<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カスタムプロパティの代わりにコンテキストオブジェクトのプロパティをます。

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

コンテキストオブジェクトは、リテラルオブジェクトまたはその他のバインディング式にすることができます。かっこで囲まれていると、パイプでも機能するようです。

の有効な例ngTemplateOutletContext

  • [ngTemplateOutletContext]="{ aVariable: 123 }"
  • [ngTemplateOutletContext]="{ aVariable: (3.141592 | number:'3.1-5') }"
  • [ngTemplateOutletContext]="{ aVariable: anotherVariable }" と一緒に使用 let-a="aVariable"
  • [ngTemplateOutletContext]="{ $implicit: anotherVariable }" と一緒に使用 let-a
  • [ngTemplateOutletContext]="ctx"ctx公共施設はどこですか

これを機能させるには、コードを '<template ...'から '<ng-template ...'に変更する必要がありました。
Humppakäräjät

2
うん、あなただけ使用することができます<template>あなたがいずれかを使用することができます角度2に<template>または<ng-template>角度4に、しかし、あなただけ使用する必要があります<ng-template>。Angular 5はのサポートを終了しました<template>
Steven Liekens、2018年

何のtためですか?
matttm

1
@matttm #tはを格納するテンプレート変数ですng-template[ngTemplateOutlet]="t"ng-template自体を参照するために使用されます。
Steven Liekens

これは奇妙ですが、うまくいきます!Angularは組み込みの変数ディレクティブでこれをより簡単にする必要があります。ありがとう。
TetraDev

57

アップデート3

問題2451はAngular 4.0.0で修正されています

こちらもご覧ください

アップデート2

これはサポートされていません。

テンプレート変数はありますが、任意の値を割り当てることはサポートされていません。これらは、適用される要素、エクスポートされたディレクティブまたはコンポーネントの名前、および構造化ディレクティブのスコープ変数の参照にのみ使用できますngFor

https://github.com/angular/angular/issues/2451も参照してください

アップデート1

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

のように初期化します

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

または

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

のような変数を使用します

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

(未検証)

  • #aVariableVarDirectiveexportAs: 'var')への参照を作成します
  • var="abc"をインスタンス化しVarDirective、文字列値"abc"をその値入力に渡します。
  • aVariable.varvarディレクティブvar入力に割り当てられた値を読み取ります。

そうするための構造ディレクティブを作成することは可能ではないでしょうか?
Scipion 2016

これを繰り返し必要とする場合、ディレクティブはあなたが望むことをするかもしれません。構造的なディレクティブはそれ自身のビューを作成します、それはおそらくあなたが望むものではありません。
ギュンターZöchbauer

1
@GünterZöchbauer、非常に良いもの。変数をcomponent.tsファイル内で計算/準備することは、おそらくより良い方法であることを知っています。しかし、アプリ全体で実装している同期スキームにより、場合によってはそれらを表示する方がはるかに簡単です。異なる変数が同じオブジェクトを指す場合、JavaScript参照ルールを利用しています。
AmmarCSE 2016年

のようなエラーが発生しますThere is no directive with "exportAs" set to "var"。誰が私の間違いを教えてくれますか?上記のディレクティブを使用しました。
Partha Sarathi Ghosh 2017

おそらく、ディレクティブをdeclarations: [...]ofに追加していません@NgModule()。これが問題でない場合は、新しい質問を作成し、問題を診断できるコードを提供してください。
ギュンターZöchbauer

11

これは、exportAsデコレータパラメータの使用を拡張し、ディクショナリをローカル変数として使用できるようにするために記述したディレクティブです。

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

テンプレートで次のように使用できます。

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

もちろん、#localは任意の有効なローカル変数名にすることができます。


「プロダクション」ビルドをそのまま渡しません(IDEによってエラーとしても表示されます)。に追加[key: string]: any;して、Classこれを回避します。
Charly


7

関数の応答を取得して変数に設定する場合は、テンプレートでのng-container変更を回避するために、テンプレートで次のように使用できます。

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

そして、コンポーネントのメソッドは次のようになります

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

5

Angular Language Serviceのテンプレート内からオートコンプリートサポートが必要な場合

同期:

myVar = { hello: '' };

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

非同期パイプを使用する:

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

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

2

それははるかに簡単で、何も追加する必要はありません。私の例では、変数「open」を宣言して使用します。

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

タグに名前を付けても、変数は宣言されません
Amirreza

1
@Amirreza、正確には、ElementRefを使用して値を一時的に保存しています。
Jack Rus

驚くばかり!"?"「識別子 '値'が定義されていません」というメッセージが表示されたため、使用する必要がありました=> "open?.value"しかし、正常に機能しています!!
A.モレル

2

私はangular 6xを使用していますが、最終的に以下のスニペットを使用しています。私は、タスクオブジェクトからユーザーを見つける必要があるscenerioを持っています。ユーザーの配列が含まれていますが、割り当てられたユーザーを選択する必要があります。

<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

これを行うためのディレクティブを作成する方法が気に入りました(@yurzuiに電話してください)。

私は、この問題を適切に説明し、最小限のコード変更で私のユースケースにうまく機能するカスタムletディレクティブを提案する、Mediumの記事Angular "let"ディレクティブを見つけました。

これが私の変更の要点です(投稿時)。

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

主な変更点は次のとおりです。

  • 接頭辞を「ng」から「app」に変更します(アプリのカスタム接頭辞が何であっても使用する必要があります)
  • 変更appLet: TappLet: T | null

Angularチームが公式のngLetディレクティブを作成しただけでなく、その理由もわかりません。

元のソースコードのクレジットは@AustinMatherneに送られます


これは私のページで私のお気に入りのアプローチであり、私にとってはうまくいきました。
Skychan

1

誰かを助ける短い答え

  • テンプレート参照変数は、多くの場合、テンプレート内のDOM要素を参照します。
  • 角度コンポーネントまたはWebコンポーネントおよびディレクティブも参照してください。
  • つまり、テンプレート内のどこからでも変数に簡単にアクセスできます

ここに画像の説明を入力してください

ここに画像の説明を入力してください

  • ハッシュ記号(#)を使用して参照変数を宣言する
  • イベントのパラメータとして変数を渡すことができます

ここに画像の説明を入力してください

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

*ただし、コンポーネント内でViewChildデコレーターを使用して参照できます。

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

Component内のfirstNameInput変数を参照する

@ViewChild('firstNameInput') nameInputRef: ElementRef;

その後、コンポーネント内の任意の場所でthis.nameInputRefを使用できます。

ng-templateの操作

ng-templateの場合、各テンプレートには独自の入力変数のセットがあるため、少し異なります。

ここに画像の説明を入力してください

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


0

の代わりに構造ディレクティブを使用することに決めた場合*ngIf、ディレクティブコンテキストはデフォルトでタイプチェックされないことに注意してください。タイプセーフディレクティブngTemplateContextGuardプロパティを作成するには、追加する必要がありますディレクティブのコンテキストの入力を参照してください。例えば:

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

ディレクティブは*ngIffalse値を格納できることを除いて、と同じように使用できます。

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

と比較した唯一の欠点*ngIfは、Angular Language Serviceが変数の型を理解できないため、テンプレートにコード補完がないことです。すぐに修正されるといいですね。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.