Angular의 템플릿에서 변수를 선언하는 방법


202

다음과 같은 템플릿이 있습니다.

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

그리고 결국 :

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

할 방법이 있습니까?


이 예제와 같은 바인딩 매개 변수의 이름을 변경하려는 요구 사항 / 사용 사례가 무엇인지 알고 싶습니까?
LDJ

31
예를 들어 tab [element] .val과 같은 것을 반복하지 않도록합니다. 구성 요소의 문제를 해결할 수 있다는 것을 알고 있지만 템플릿에서 수행하는 방법을 보았습니다 (해당 솔루션으로 끝나지 않을 수도 있음).
Scipion

2
@LDJ 하나의 샘플 사용 사례 : 효율성. stackmatitz.com/angular/… 샘플을 사용하십시오. <mat-checkbox [checked] = "descendantsAllSelected (node)"[indeterminate] = "descendantsPartiallySelected (node)"(change) = "todoItemSelectionToggle (node)"> {{node. item}} </ mat-checkbox> 실제로 하위 항목 인 PartiallySelected ()는 하위 항목 AllSelected ()를 호출합니다. 때때로 하위 항목 인 AllSelected가 두 번 호출됨을 의미합니다. 지역 변수가 있으면 피할 수 있습니다.
Steven.Xi

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 user같이 yurzui의 대답 .
CPHPython

답변:


175

최신 정보

우리는 단지 지시어를 만들고 *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

또한보십시오

원래 답변

앵귤러 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>

댓글에서 @Keith가 언급했듯이

이것은 대부분의 경우에 효과가 있지만 변수가 진실한 것에 의존하기 때문에 일반적인 해결책은 아닙니다.

다른 접근 방법은 업데이트를 참조하십시오.


10
이것은 대부분의 경우에 효과가있을 것이지만 그것이 variable진실 된 것에 의존하기 때문에 일반적인 해결책은 아닙니다
Keith

6
@Keith 이것을 지적 해 주셔서 감사합니다. 내 업데이트 된 대답에 좀 걸릴 수 있습니다
yurzui

3
1) 다른 솔루션보다 최신이므로 2) 현재 답변에 연결된 풀 요청을 요약하고 많은 시간을 절약합니다. 3) 예제는 외부 링크가 아닌 인라인으로 포함됩니다. 이것을 보여 주셔서 감사합니다. AFAIK에 싸인 모든 객체 {}는 진실로 평가되므로이 솔루션은 상당히 강력합니다.
kvanberendonck

4
예를 들어, 확장 버튼 : *ngIf="{ expanded: false } as scope"당신은 부트 스트랩을 사용하는 경우 다음 당신은 사용할 수 있습니다 [ngClass]="{ 'in': scope.expanded }"(click)="scope.expanded = !scope.expanded"대신에 무엇을 추가 js/ ts파일.
kvanberendonck

1
관련 github 문제 ( *ngIf사용자 지정 ngvar 물건 대신 간단한 것을 사용하여 지적함) : github.com/angular/angular/issues/14985
phil294

80

추악하지만

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

2
의 경우 *ngFor변수 값이 변경되면 trackBy모든 값에 대해 동일한 ID를 반환 하는 함수를 지정할 때까지 중첩 된 모든 컨텐츠가 다시 작성됩니다 .
Valeriy Katkov

76

templateAngular 2 또는 ng-templateAngular 4+ 의 요소를 사용하여 HTML 코드로 변수를 선언 할 수 있습니다 .

템플릿에는 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>Angular 2 에서만 사용할 수 있습니다. <template>또는 <ng-template>Angular 4에서 사용할 수 있지만을 사용해야합니다 <ng-template>. Angular 5에 대한 지원이 중단되었습니다 <template>.
Steven Liekens

무엇입니까 t?
matttm

1
@matttm #t은을 저장하는 템플릿 변수입니다 ng-template. [ngTemplateOutlet]="t"ng-template 참조 자체를 만드는 데 사용 됩니다.
Steven Liekens 2018 년

이것은 bizare이지만 작동합니다! Angular는 내장 변수 지시문을 사용하여 이것을 단순화해야합니다. 감사.
TetraDev

57

업데이트 3

Angular 4.0.0에서 문제 2451이 수정되었습니다.

또한보십시오

업데이트 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>

(검증되지 않은)

  • #aVariableVarDirective( exportAs: 'var')에 대한 참조를 만듭니다.
  • var="abc"를 인스턴스화하고 VarDirective문자열 값 "abc"을 값 입력에 전달합니다 .
  • aVariable.varvar지시문 var입력에 지정된 값을 읽습니다 .

그렇게하기 위해 구조적 지시문을 만들 수 없습니까?
Scipion

이것을 반복적으로 필요로하면 지시어가 원하는 것을 수행 할 수 있습니다. 구조적 지시문은 자체 관점을 생성하므로 아마도 원하는 것이 아닙니다.
Günter Zöchbauer

1
@ GünterZöchbauer, 아주 좋은 것들. component.ts파일 에서 변수를 계산 / 준비하는 것이 더 나은 방법 일 것입니다 . 그러나 앱 전체에서 구현하는 동기화 체계로 인해 경우에 따라보기가 훨씬 쉽습니다. 다른 변수가 동일한 객체를 가리킬 때 자바 스크립트 참조 규칙을 활용하고 있습니다.
AmmarCSE

과 같은 오류가 발생 There is no directive with "exportAs" set to "var"합니다. 내가 한 실수를 말해 줄 수 있습니까? 위의 지시문을 사용했습니다.
Partha Sarathi Ghosh

아마도에 지시문을 추가하지 않았을 것 declarations: [...]입니다 @NgModule(). 이것이 문제가 아닌 경우 새 질문을 작성하고 문제를 진단 할 수있는 코드를 제공하십시오.
Günter 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은 유효한 로컬 변수 이름 일 수 있습니다.


'production'빌드를 그대로 전달하지 않습니다 (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

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

훨씬 간단하며 추가 할 필요가 없습니다. 내 예에서는 변수 "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. Morel

1

나는 이것을하기위한 지시문을 만드는 접근법을 좋아했습니다 (@yurzui 호출).

나는 중간 기사 Angular "let"지시문을 찾았습니다. 이 문제를 잘 설명 하고 최소한의 코드 변경으로 유스 케이스에 잘 작동 하는 맞춤 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 요소를 참조합니다.
  • 각도 또는 웹 구성 요소 및 지시문도 참조하십시오.
  • 즉 템플릿의 어느 곳에서나 쉽게 변수에 액세스 할 수 있습니다.

여기에 이미지 설명을 입력하십시오

여기에 이미지 설명을 입력하십시오

  • 해시 기호 (#)를 사용하여 참조 변수 선언
  • 이벤트에서 변수를 매개 변수로 전달할 수 있음

여기에 이미지 설명을 입력하십시오

  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


1

대신에 구조적 지시문을 사용하기로 결정한 사람들의 *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;
}

지시문은 false 값을 *ngIf저장할 수 있다는 점을 제외하고 다음 과 같이 사용할 수 있습니다 .

<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가 변수 유형을 알아낼 수 없으므로 템플릿에 코드 완성이 없다는 것입니다. 곧 수정 되길 바랍니다.


이것은 작동하지만 지능은 그렇지 않습니다. angular 8을 사용하고 있습니다.
Tx_monster
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.