programing

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

goodsources 2023. 5. 26. 20:54
반응형

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

다음 템플릿이 있습니다.

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

그리고 다음과 같이 마무리하고 싶습니다.

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

그것을 할 방법이 방법이 있습니까?

갱신하다

우리는 다음과 같은 지시를 만들 수 있습니다.*ngIf▁it 끝것▁call.*ngVar

당신의 대답은 매우 편리했지만, 여기서 저는 타이핑도 할 수 있도록 그것을 조정했습니다.

ng-var.ts.

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

@Directive({
  selector: '[ngVar]',
})
export class NgVar<T = unknown> {
  private _context: NgVarContext<T> = new NgVarContext<T>();
  private _viewRef: EmbeddedViewRef<NgVarContext<T>> | null = null;

  @Input()
  set ngVar(context: T) {
    this._context.$implicit = this._context.ngVar = context;

    if (!this._viewRef) {
      this._viewRef = this._viewContainer.createEmbeddedView(
        this._templateRef,
        this._context
      );
    }
  }

  // https://github.com/angular/angular/blob/main/packages/common/src/directives/ng_if.ts

  /**
   * Assert the correct type of the expression bound to the `ngIf` input within the template.
   *
   * The presence of this static field is a signal to the Ivy template type check compiler that
   * when the `NgIf` structural directive renders its template, the type of the expression bound
   * to `ngIf` should be narrowed in some way. For `NgIf`, the binding expression itself is used to
   * narrow its type, which allows the strictNullChecks feature of TypeScript to work with `NgIf`.
   */

  static ngTemplateGuard_ngVar: 'binding';

  /**
   * Asserts the correct type of the context for the template that `NgIf` will render.
   *
   * The presence of this method is a signal to the Ivy template type-check compiler that the
   * `NgIf` structural directive renders its template with a specific context type.
   */

  // Passing down variable Type
  static ngTemplateContextGuard<T>(
    dir: NgVar<T>,
    ctx: any
  ): ctx is NgVarContext<T> {
    return true;
  }

  constructor(
    private _viewContainer: ViewContainerRef,
    private _templateRef: TemplateRef<NgVarContext<T>>
  ) {}
}

export class NgVarContext<T = unknown> {
  public $implicit: T = null!;
  public ngVar: T = null!;
}

와함께로*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>

플런커 예제 Angular4ngVar

참고 항목

원답

각진 v4

  1. div+ngIf+let

    a}{{}}{{} b}
  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>

구성 요소.ts

export class AppComponent {
  x = 5;
}
  1. 과 같은를 만들고 싶지 않은 경우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가 논평에서 언급했듯이.

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

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

html 코로변선할수있습다니언수를을 를 html 할 수 .template 2 각 2 요 ng-template각도 4+로 표시됩니다.

에는 템릿에다사용변여하속수할성수당을있있을 사용하여 할 수 .let자체에 가 될 수.템플릿에 대한 출구를 지정해야 하지만 템플릿 자체에 대한 참조가 될 수 있습니다.

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

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

당신은 사여코양줄수있다습니일을드다를 수 .$implicit사용자 지정 속성 대신 컨텍스트 개체의 속성입니다.

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

컨텍스트 개체는 리터럴 개체 또는 다른 바인딩 식일 수 있습니다.기타 유효한 예:

<!-- Use arbitrary binding expressions -->
<ng-template let-sum [ngTemplateOutletContext]="{ $implicit: 1 + 1 }">

<!-- Use pipes -->
<ng-template let-formatPi [ngTemplateOutletContext]="{ $implicit: 3.141592 | number:'3.1-5' }">

<!-- Use the result of a public method of your component -->
<ng-template let-root [ngTemplateOutletContext]="{ $implicit: sqrt(2116) }">

<!--
    You can create an alias for a public property of your component:
    anotherVariable: number = 123; 
-->
<ng-template let-aliased [ngTemplateOutletContext]="{ $implicit: anotherVariable }">

<!--
    The entire context object can be bound from a public property:
    ctx: { first: number, second: string } = { first: 123, second: "etc" }
-->
<ng-template let-a="first" let-b="second" [ngTemplateOutletContext]="ctx">

못생겼지만:

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

업데이트 3

문제 https://github.com/angular/angular/issues/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>

(테스트되지 않음)

  • #aVariable 참를생다니합성에 .VarDirective(exportAs: 'var')
  • var="abc"를인스합니다화를 합니다.VarDirective 값 문열값전달니다합을자▁the▁string다▁value를 전달합니다."abc"그것은 가치 입력입니다.
  • aVariable.var 값된읽다에 .varvar입력하다

저는 이것을 제안하고 싶습니다: https://medium.com/ @AustinMatherne/angular-let-direction-a168d4248138

이 지침을 사용하면 다음과 같은 내용을 작성할 수 있습니다.

<div *ngLet="'myVal' as myVar">
  <span> {{ myVar }} </span>
</div>

여기 exportAs decorator 매개 변수의 사용을 확장하고 사전을 로컬 변수로 사용할 수 있도록 하는 지침이 있습니다.

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은 유효한 로컬 변수 이름일 수 있습니다.

.ng-container템플릿을 수정하지 않도록 합니다.

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

그리고 구성 요소의 방법은 다음과 같을 수 있습니다.

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

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>

제 요구사항에 맞는 간단한 솔루션은 다음과 같습니다.

 <ng-container *ngIf="lineItem.productType as variable">
       {{variable}}
 </ng-container>

OR

 <ng-container *ngIf="'ANY VALUE' as variable">
       {{variable}}
  </ng-container>

나는 Angular 버전을 사용하고 있습니다: 12.다른 버전에서도 작동할 수 있을 것 같습니다.

각도 12 포함:

  <div *ngIf="error$ | async as error">
     <span class="text-warn">{{error.message}}</span>
   </div>

저는 이를 위한 지침을 만드는 접근 방식이 좋았습니다(좋은 결정 @yurzui).

저는 이 문제를 잘 설명하고 사용자 지정 지침을 제안하는 중간 기사 Angular "let" Directive를 발견하게 되었습니다. 이 지침은 최소한의 코드 변경으로 제 사용 사례에 잘 작동했습니다.

다음은 제가 수정한 내용에 대한 요점입니다(게시 시점).

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에게 전달됩니다.

구조적 지침을 대체하기 위해 사용하기로 결정한 사람들을 위해.*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;
}

▁like다처럼 사용될 수.*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 6x를 사용하고 있으며 아래 스니펫을 사용하게 되었습니다.작업 개체에서 사용자를 찾아야 하는 시나리오가 있습니다.사용자 배열이 포함되어 있지만 할당된 사용자를 선택해야 합니다.

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

비슷한 것을 하려고 했는데 이것은 새로운 버전의 앵귤러로 수정된 것 같습니다.

    <div *ngIf="things.car; let car">
      Nice {{ car }}!
    </div>
    <!-- Nice Honda! -->

누군가에게 도움이 되는 짧은 대답

  • 템플릿 참조 변수는 종종 템플릿 내의 DOM 요소를 참조합니다.
  • 각도 또는 웹 구성 요소 및 지침에 대한 참조.
  • 즉, 템플릿의 모든 위치에서 변수에 쉽게 액세스할 수 있습니다.

여기에 이미지 설명 입력

여기에 이미지 설명 입력

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

여기에 이미지 설명 입력

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

*그러나 ViewChild 장식기를 사용하여 구성요소 내에서 참조할 수 있습니다.

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

구성 요소 내부의 참조 firstNameInput 변수

@ViewChild('firstNameInput') nameInputRef: ElementRef;

그런 다음 이 .nameInputRef를 구성요소 내의 임의의 위치에서 사용할 수 있습니다.

ng-template 작업

ng-template의 경우 템플릿마다 고유한 입력 변수 집합이 있기 때문에 약간 다릅니다.

여기에 이미지 설명 입력

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

저는 https://www.npmjs.com/package/ng-let 의 저자입니다.

html 구성 요소 템플릿으로 로컬 변수로 데이터를 공유하기 위한 구조 지침입니다.

소스 코드:

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

interface NgLetContext<T> {
    ngLet: T;
    $implicit: T;
}

@Directive({
    // tslint:disable-next-line: directive-selector
    selector: '[ngLet]'
})
export class NgLetDirective<T> {

    private context: NgLetContext<T | null> = { ngLet: null, $implicit: null };
    private hasView: boolean = false;

    // eslint-disable-next-line no-unused-vars
    constructor(private viewContainer: ViewContainerRef, private templateRef: TemplateRef<NgLetContext<T>>) { }

    @Input()
    set ngLet(value: T) {
        this.context.$implicit = this.context.ngLet = value;
        if (!this.hasView) {
            this.viewContainer.createEmbeddedView(this.templateRef, this.context);
            this.hasView = true;
        }
    }

    /** @internal */
    public static ngLetUseIfTypeGuard: void;

    /**
     * Assert the correct type of the expression bound to the `NgLet` input within the template.
     *
     * The presence of this static field is a signal to the Ivy template type check compiler that
     * when the `NgLet` structural directive renders its template, the type of the expression bound
     * to `NgLet` should be narrowed in some way. For `NgLet`, the binding expression itself is used to
     * narrow its type, which allows the strictNullChecks feature of TypeScript to work with `NgLet`.
     */
    static ngTemplateGuard_ngLet: 'binding';

    /**
     * Asserts the correct type of the context for the template that `NgLet` will render.
     *
     * The presence of this method is a signal to the Ivy template type-check compiler that the
     * `NgLet` structural directive renders its template with a specific context type.
     */
    static ngTemplateContextGuard<T>(dir: NgLetDirective<T>, ctx: any): ctx is NgLetContext<Exclude<T, false | 0 | '' | null | undefined>> {
        return true;
    }
}

용도:

import { Component } from '@angular/core';
import { defer, Observable, timer } from 'rxjs';

@Component({
  selector: 'app-root',
  template: `
  <ng-container *ngLet="timer$ | async as time"> <!-- single subscription -->
    <div>
      1: {{ time }}
    </div>
    <div>
      2: {{ time }}
    </div>
  </ng-container>
  `,
})
export class AppComponent {
  timer$: Observable<number> = defer(() => timer(3000, 1000));
}

이렇게 해보세요.

<ng-container
     [ngTemplateOutlet]="foo"
     [ngTemplateOutletContext]="{ test: 'Test' }"
></ng-container>

<ng-template #foo let-test="test">
    <div>{{ test }}</div>
</ng-template>

@yurzui의 원래 답변은 각도 8을 9로 마이그레이션하는 이상한 문제로 인해 각도 9부터 작동하지 않습니다.그러나 ngVar 디렉티브를 가지고 있고 다음과 같이 사용함으로써 여전히 이점을 얻을 수 있습니다.

<ng-template [ngVar]="variable">
your code
</ng-template>

IDE 경고가 발생할 수 있지만 "변수가 정의되지 않았습니다."

yurzui의 답변은 이미 훌륭했습니다.여기에 약간의 추가 사항이 있습니다.

지시어 *ngVar 유형을 안전하게 만들기 위해 정적 방법을 추가할 수 있습니다.ngTemplateContextGuard지침에 따라:

@Directive({
    // eslint-disable-next-line @angular-eslint/directive-selector
    selector: '[ngVar]'
})
export class VarDirective<Type> {
    @Input()
    set ngVar(context: Type) {
        console.log(context)
        this.context.$implicit = this.context.ngVar = context

        if (!this.hasView) {
            this.vcRef.createEmbeddedView(this.templateRef, this.context)
            this.hasView = true
        }
    }

    private context: {
        $implicit: Type
        ngVar: Type
    } = {
        $implicit: null,
        ngVar: null
    }

    private hasView: boolean = false

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

    // this magic is how we tell Angular the context type for this directive, which then propagates down to the type of the template
    static ngTemplateContextGuard<Type>(dir: VarDirective<Type>, ctx: NgVarContext<Type>): ctx is NgVarContext<Type> {
        return true
    }
}

interface NgVarContext<T> {
    $implicit: T
    ngVar: T
}

VisualStudioCode와 같은 IDE는 변수의 유형을 알기 때문에 자동 완성에 도움이 됩니다.

그것은 훨씬 간단하며, 추가적인 것이 필요하지 않습니다.이 예에서는 변수를 "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>

언급URL : https://stackoverflow.com/questions/38582293/how-to-declare-a-variable-in-a-template-in-angular

반응형