IT

각도 반전 2 *ng의 경우

itgroup 2023. 8. 11. 21:43
반응형

각도 반전 2 *ng의 경우

<li *ngFor="#user of users ">
    {{ user.name }} is {{ user.age }} years old.
</li>

항목이 상향식으로 추가될 경우 ngFor를 반전시킬 수 있습니까?

간단하게 의 자크의를 할 수 ..reverse() 용액은 필요 각도별 솔루션이 필요하지 않습니다.

<li *ngFor="#user of users.slice().reverse() ">
   {{ user.name }} is {{ user.age }} years old.
</li>

여기서 더 보기: https://www.w3schools.com/jsref/jsref_reverse.asp

JavaScript 배열의 역방향 방법을 활용하는 사용자 지정 파이프를 구현해야 합니다.

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({ name: 'reverse' })

export class ReversePipe implements PipeTransform {
  transform(value) {
    return value.slice().reverse();
  }
}

다음과 같이 사용할 수 있습니다.

<li *ngFor="let user of users | reverse">
    {{ user.name }} is {{ user.age }} years old.
</li>

구성 요소의 파이프 특성에 파이프를 추가하는 것을 잊지 마십시오.

이것이 효과가 있을 것입니다.

<li *ngFor="user of users?.reverse()">
  {{ user.name }} is {{ user.age }} years old.
</li>

선택한 답변에는 두 가지 문제가 있습니다.

첫째, 추가하지 않는 한 파이프는 소스 배열 수정을 인식하지 못합니다.pure: false파이프의 특성에 맞게.

둘째, 파이프는 배열 자체가 아니라 배열의 복사본이 반대로 되기 때문에 양방향 바인딩을 지원하지 않습니다.

최종 코드는 다음과 같습니다.

    import {Pipe} from 'angular2/core';

    @Pipe({
      name: 'reverse',
      pure: false
    })
    export class ReversePipe {
      transform (values) {
        if (values) {
          return values.reverse();
        }
      }
    }

플런커

http://plnkr.co/edit/8aYdcv9QZJk6ZB8LZePC?p=preview

놀랍게도, 그렇게 오랜 세월이 흘렀지만, 심각한 결함이 없는 솔루션은 여전히 여기에 게시되지 않았습니다.그렇기 때문에 저는 제 답변에서 현재의 모든 솔루션이 가지고 있는 단점을 설명하고 제가 더 낫다고 생각하는 이 문제에 대한 두 가지 새로운 접근 방식을 제시하려고 합니다.


현재 솔루션의 단점

각 솔루션에 대해 라이브 데모를 사용할 수 있습니다.설명 아래 링크를 확인해주시기 바랍니다.

▁▁with프이▁pureslice().reverse() 승인됨으)로 표시됨)

@Tierry Templier@rey_coder에 의해(이후)ngx-pipes 방법 사용)

@Pipe({ name: 'reverse' })
export class ReversePipe implements PipeTransform {
  transform(value) {
    return value.slice().reverse();
  }
}

파이프는 기본적으로 순수하므로 Angular에서는 동일한 입력이 주어지면 동일한 출력을 생성할 것으로 예상합니다.그것이 바로 그 이유입니다.transform()예를 들어 쓰기를 통해 이전 어레이를 업데이트할 때마다 새 어레이를 생성하지 않는 한 어레이를 변경할 때 메서드가 다시 호출되지 않습니다.

this.users = this.users.concat([{ name, age }]);

대신에

this.users.push({ name, age });

하지만 파이프가 필요하다고 해서 그렇게 하는 것은 나쁜 생각입니다.

따라서 이 솔루션은 어레이를 수정하지 않을 경우에만 작동합니다.

라이브 데모에서는 Reset 버튼만 작동하는 것을 볼 수 있는데, 이는 클릭하면 새 배열(빈 배열)이 생성되고 Add 버튼은 기존 배열만 변형되기 때문입니다.

라이브 데모

2. slice().reverse() 없이

@Andre Gois, @Trilok Singh, @WapShibam에 의해

<li *ngFor="let user of users.slice().reverse()">
   {{ user.name }} is {{ user.age }} years old.
</li>

여기서는 파이프 없이 동일한 배열 방법을 사용합니다. 즉, Angular가 각 변경 감지 사이클에서 이러한 방법을 호출합니다. 사항이가 되는 은 어이에에대변 UI반만여입니다.slice()그리고.reverse()어레이 변경이 변경 감지를 실행하는 유일한 원인이 아니기 때문에 너무 자주 호출될 수 있습니다.

파이프를 불순물로 만들기 위해 이전 솔루션의 코드를 수정해도 동일한 동작이 발생합니다. 하려면 면됩니다하설정다됩▁setting를 설정해야 합니다.pure: false 물에건된에 에서.Pipeㅠㅠㅠㅠㅠㅠㅠㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅠslice()그리고.reverse()전화를 받을 것입니다.배열을 변경하지 않고 변경 탐지를 트리거할 수 있는 버튼도 추가했습니다.클릭 후 콘솔에서 다음을 확인할 수 있습니다.slice()그리고.reverse()어레이가 수정되지 않았음에도 불구하고 호출되었으며, 이는 이상적인 솔루션에서는 원하지 않는 것입니다.그럼에도 불구하고, 이 솔루션은 현재의 모든 솔루션 중에서 최고입니다.

라이브 데모

역방향 어레이를 캐싱하여 성능 향상을 시도

@Gunter Zöchbauer에 의해

@Pipe({ name: 'reverse', pure: false })
export class ReversePipe implements PipeTransform {
  constructor(private differs: IterableDiffers) {
    this.differ = this.differs.find([]).create();
  }

  transform(value) {
    if (this.differ.diff(value)) {
      this.cached = value.slice().reverse();
    }
    return this.cached;
  }
}

이전 섹션에서 설명한 문제를 해결하기 위한 영리한 시도입니다.여기서,slice()그리고.reverse()배열의 내용이 실제로 변경된 경우에만 호출됩니다.변경되지 않은 경우 마지막 작업의 캐시된 결과가 반환됩니다.

배열 변경을 확인하기 위해 Angular의 객체가 사용됩니다.이러한 개체는 변경 감지 중에 Angular에서 내부적으로 사용되기도 합니다.라이브 데모에서 콘솔을 다시 확인하여 실제로 작동하는지 확인할 수 있습니다.

하지만, 저는 성능 향상은 없다고 생각합니다.반대로, 저는 이 해결책이 상황을 더 악화시킨다고 생각합니다.그 이유는 어레이가 변경되지 않았음을 확인하는 데 서로 다른 선형 시간이 소요되며, 이는 호출하는 것만큼 나쁘기 때문입니다.slice()그리고.reverse()또한 변경된 경우에도 시간 복잡성은 최악의 경우에도 선형적입니다. 경우에 따라 전체 어레이를 통과해야 차이가 변경을 감지할 수 있기 때문입니다.예를 들어 배열의 마지막 요소가 수정된 경우 이 문제가 발생합니다.을 두 번 . 즉, 를 와 를 할 때입니다.slice()그리고.reverse()그건 정말 끔찍합니다.

라이브 데모

reverse()

@프랭크100@댄에 의해

<li *ngFor="let user of users.reverse()">
   {{ user.name }} is {{ user.age }} years old.
</li>

이 해결책은 절대 됩니다.

는 그는이 때문입니다.reverse()새 배열을 만드는 대신 배열을 변환합니다. 이는 원래 배열이 다른 위치에 필요할 수 있기 때문에 필요하지 않을 수 있습니다.그렇지 않은 경우에는 애플리케이션에 어레이가 도착하는 즉시 어레이를 반대로 전환해야 하며 다시는 어레이에 대해 걱정할 필요가 없습니다.

훨씬 더 심각한 문제가 있는데, 개발 모드에서 볼 수 없기 때문에 특히 위험합니다.운영 모드에서는 각 변경 감지 주기 동안 어레이가 반전됩니다. 즉, 다음과 같은 어레이가[1,2,3]사이를 계속 전환합니다.[1,2,3]그리고.[3,2,1]당신은 분명히 그것을 원하지 않을 것입니다.

개발 모드에서는 각 변경 감지 실행 후 Angular가 추가 검사를 수행하므로 개발 모드에서는 이를 볼 수 없습니다. 이 모드에서는 원래 순서대로 반전된 배열이 한 번 더 반전됩니다.두 번째 점검의 부작용은 UI에 반영되지 않으며, 그렇기 때문에 모든 것이 정상적으로 작동하는 것처럼 보이지만 실제로는 그렇지 않습니다.

라이브 데모 (생산 모드)


대체 솔루션

배열 인덱스만 사용

// In the component:
userIdentity = i => this.users[this.users.length - 1 - i];
<li *ngFor="let _ of users; index as i; trackBy:userIdentity">
  {{ users[users.length - 1 - i].name }} is {{ users[users.length - 1 - i].age }} years old.
</li>

사용자를 예요.i그리고 그것을 사용하여 그것을 얻습니다.i배열의 마지막 요소입니다.(기술적으로, 우리는 사용자도 붙잡지만, 우리는 사용합니다. _ 해당 변수를 사용하지 않을 것임을 나타내는 변수 이름입니다.그것은 꽤 흔한 관습입니다.)

를 써야 하는 것.users[users.length - 1 - i]여러 번은 귀찮습니다.다음과 같은 트릭을 사용하여 코드를 단순화할 수 있습니다.

<li *ngFor="let _ of users; index as i; trackBy:userIdentity">
  <ng-container *ngIf="users[users.length - 1 - i] as user">
    {{ user.name }} is {{ user.age }} years old.
  </ng-container>
</li>

식으로, 는 방식로으내사부수우는, 안에 사용할 수.<ng-container>합니다. 그는 열 요 작 다 경 제 니 합 는 것 저 실 은 때 다 변 문 입 니 기 다 조 이 대 건 에 수 음 한 이 로 제 배 하 장 변 수 에 소 동 거 가 대 로 짓 우 값 에 만 아 이 닌 ▁for ▁what ▁note ▁because ▁elements ▁is ▁condition ▁the ▁properly ▁are *ngIfdirection.

또한 사용자 정의를 사용해야 하며, 사용자 정의 없이도 잘 작동하는 간단한 예제이지만 나중에 디버깅하는 데 많은 시간을 할애하지 않으려면 이 작업이 반드시 필요합니다.

라이브 데모

반복 가능한 개체를 반환하는 순수 파이프

@Pipe({ name: 'reverseIterable' })
export class ReverseIterablePipe implements PipeTransform {
  transform<T>(value: T[]): Iterable<T> {
    return {
      *[Symbol.iterator]() {
        for (let i = value.length - 1; i >= 0; i--) {
          yield value[i];
        }
      }
    };
  }
}

*ngFor루프는 내부적으로 참을 수 있는 물체와 함께 작동하기 때문에 우리는 파이프를 사용하여 우리의 요구를 충족시키는 것을 구성합니다.[Symbol.iterator]우리 객체의 방법은 배열을 역순으로 통과시킬 수 있는 반복기를 반환하는 생성기 함수입니다.반복 가능한 것에 대해 처음 듣는 경우 또는 별표 구문과 다음과 같은 경우 이 가이드를 읽어 주십시오.yield키워드는 당신에게 생소합니다.

이 접근 방식의 아름다운 점은 어레이에 대해 반복 가능한 개체 하나만 생성해도 충분하다는 것입니다.생성기 함수는 호출될 때마다 새 반복기를 반환하기 때문에 배열을 변경해도 앱이 제대로 작동합니다.가 새로운 배열을 반복 한 파이프가 을 의미합니다. 은 이 을 새, 열배즉라하생때생되면새, 성항며만을순여따목로반서낫더것사충파만, 을▁the▁better▁that▁is▁with,,▁solution▁one▁than즉▁this더낫것,사습니▁when다▁means▁a▁that보▁we다는▁makes하▁which▁pipe용솔을이slice()그리고.reverse().

스토리지 인덱스를 사용할 필요가 없기 때문에 이전 솔루션보다 더 우아한 솔루션이라고 생각합니다.*ngFor루프. 사실 파이프를 추가하는 것 외에는 구성 요소에서 변경할 필요가 없습니다. 전체 기능이 파이프 안에 포함되어 있기 때문입니다.

<li *ngFor="let user of users | reverseIterable">
  {{ user.name }} is {{ user.age }} years old.
</li>

또한 모듈에서 파이프를 가져오고 선언하는 것을 잊지 마십시오.

반복 가능한 컨텍스트에서만 작동한다는 것을 나타내기 위해 이번에는 파이프 이름을 다르게 지정했습니다.할 수 , 하는 데 할 수 .{{ users | reverseIterable }}할 수 있는 에서, 가 반복가구지되않현기때문에일서반템에를 입니다.toString()방법(사용 사례에서 의미가 있는 경우에는 어떤 방법도 구현을 방해하지 않습니다.)그것이 이 파이프가 있는 파이프와 비교하여 가지고 있는 단점입니다.slice()그리고.reverse()하지만 당신이 원하는 것이 그것을 사용하는 것이라면 확실히 더 좋습니다.*ngFor 루프

라이브 데모

상태 저장 순수 파이프를 통한 최적화 가능

"스테이트풀 퓨어 파이프"는 모순어법처럼 들릴 수 있지만, 실제로 Angular는 Ivy라고 불리는 비교적 새로운 컴파일 및 렌더링 엔진을 사용하면 우리가 만들 수 있는 것입니다.

Ivy가 도입되기 전에 Angular는 템플릿에서 한 번 이상 사용한 경우에도 순수 파이프의 인스턴스를 하나만 생성했습니다.은 즉이transform()메서드는 항상 동일한 개체에서 호출됩니다.따라서 템플릿의 모든 파이프에서 해당 개체가 공유되었기 때문에 해당 개체에 저장된 상태를 사용할 수 없습니다.

그러나 Ivy는 각각의 발생에 대해 별도의 파이프 인스턴스를 생성하여 다른 접근 방식을 취합니다. 즉, 이제 순수 파이프를 상태로 만들 수 있습니다.왜 우리가 그걸 원하겠어요?현재 솔루션의 문제는 어레이를 수정할 때 반복 가능한 개체를 새로 생성할 필요는 없지만 새로운 개체를 생성할 때는 계속 생성해야 한다는 것입니다.우리는 파이프 인스턴스의 속성에 배열을 스트라이핑하고 배열이 전달되는 대신 해당 속성에 의존하도록 함으로써 이 문제를 해결할 수 있습니다.transform()방법.그런 다음 새 어레이를 기존 속성에 할당할 때만 필요합니다.transform()이 호출되고 나중에 기존 반복 가능 개체를 반환합니다.

@Pipe({ name: 'reverseIterable' })
export class ReverseIterablePipe implements PipeTransform {
  private array: any[] = [];
  private reverseIterable: Iterable<any>;

  constructor() {
    this.reverseIterable = {
      [Symbol.iterator]: function*(this: ReverseIterablePipe) {
        for (let i = this.array.length - 1; i >= 0; i--) {
          yield this.array[i];
        }
      }.bind(this)
    };
  }

  transform<T>(value: T[]): Iterable<T> {
    this.array = value;
    return this.reverseIterable;
  }
}

제너레이터 기능을 다음과 같이 바인딩해야 합니다.thisthis우리가 그렇지 않다면 다른 맥락에서 다른 의미를 가질 수도 있습니다.일반적으로 화살표 함수를 사용하여 수정하지만 제너레이터 함수에 대한 구문이 없으므로 명시적으로 바인딩해야 합니다.

아이비는 Angular 버전 9부터 기본적으로 활성화되어 있지만, 라이브 데모에서 비활성화했습니다. 왜 아이비 없이 순수 파이프를 스테이트풀하게 만들 수 없는지 보여주기 위해서입니다.앱이 올바르게 작동하려면 다음을 설정해야 합니다.angularCompilerOptions.enableIvytrue에 시대에tsconfig.jsonjava.

라이브 데모

갱신하다

@Pipe({
  name: 'reverse',
  pure: false
})
export class ReversePipe implements PipeTransform {
  constructor(private differs: IterableDiffers) {
    this.differ = this.differs.find([]).create();
  }

  transform(value) {
    const changes = this.differ.diff(value);
    if (changes) {
      this.cached = value.slice().reverse();
    }
    return this.cached;    
  }
}

기는으로파이프의적본▁합니다.transform()배열 참조가 변경되어 항목이 배열에 추가되거나 배열에서 제거될 때 호출되지 않으므로 배열에 대한 변경 사항이 UI에 반영되지 않습니다.

변경 감지가 호출될 때마다 파이프가 호출되도록 파이프를 불순물로 만들었습니다.불순한 파이프는 매우 자주 불리게 되므로 효율적으로 작동하는 것이 중요합니다.어레이의 복사본(아마도 대규모 어레이)을 생성한 다음 순서를 되돌리는 데는 상당한 비용이 듭니다.

따라서 일부 변경 사항이 인식된 경우에만 실제 작업을 수행하고 그렇지 않은 경우에는 이전 호출의 캐시된 결과를 반환하는 것이 다릅니다.

원래의

배열을 역순으로 반환하는 사용자 지정 파이프를 만들거나 데이터를 역순으로 제공할 수 있습니다.

참고 항목

ngx-파이프를 사용할 수 있습니다.

npm 설치 ngx-dll --저장

모듈

import {NgPipesModule} from 'ngx-pipes';

@NgModule({
 // ...
 imports: [
   // ...
   NgPipesModule
 ]
})

요소

@Component({
  // ..
  providers: [ReversePipe]
})
export class AppComponent {
  constructor(private reversePipe: ReversePipe) {
  }
}

다음 합니다.<div *ngFor="let user of users | reverse">

사용해 보십시오.

<ul>
  <li *ngFor="let item of items.slice().reverse()">{{item}}</li>
</ul>

자바스크립트 기능을 사용하여 할 수 있습니다.

<li *ngFor="user of users?.slice()?.reverse()">
    {{ user.name }} is {{ user.age }} years old.
</li>

사용하는 .slice().reverse()템플릿에서 단순하고 효과적입니다.그러나 반복 인덱스를 사용할 때는 주의해야 합니다.

는 는이유 때문입니다..slice()method는 뷰에 대한 새 배열을 반환하여 초기 배열이 변경되지 않도록 합니다.문제는 역방향 배열이 역방향 인덱스도 가지고 있다는 것입니다.

따라서 인덱스를 변수로 사용하려면 인덱스도 반대로 사용해야 합니다.예:

<ul>
  <li *ngFor="let item of items.slice().reverse(); index as i" (click)="myFunction(items.length - 1 - i)">{{item}}</li>
</ul>

위서에 에신대에.i우리는 반대로 사용합니다.items.length - 1 - i클릭한 항목이 초기 배열의 동일한 항목과 일치하도록 합니다.

다음 스택 블리츠를 확인하십시오. https://stackblitz.com/edit/angular-vxasr6?file=src%2Fapp%2Fapp.component.html

용사를 합니다.transform을 요구합니다.PipeTransform:

    import { Pipe, PipeTransform } from '@angular/core';

    @Pipe({
      name: 'reverse',
      pure: false
    })
    
    export class ReversePipe implements PipeTransform {
      transform (values: any) {
        if (values) {
          return values.reverse();
        }
      }
    }

으로 .<div *ngFor="let user of users | reverse">

스레드 작성자의 요구 사항이 무엇인지 확실하지 않지만 항목을 역순으로 표시하는 경우 다음을 사용하여 CSS 전용 솔루션을 수행할 수 있습니다.

display: flex;
flex-direction: column-reverse;

고객님의 물품을 보관하는 컨테이너에 있습니다.프로젝트에 그 요구 사항이 있었고 이것이 가장 잘 작동했습니다.

만약 타자기를 사용하는 사람이 있다면, @Günter Zöchbauer의 대답을 사용하여 어떻게 제가 그것을 작동시킬 수 있었는지입니다.

@Pipe({
  name: 'reverse',
  pure: false
})
export class ReversePipe implements PipeTransform {

  differs: any
  cashed: any
  constructor(private _differs: IterableDiffers) {
    this.differs = this._differs.find([]).create(null);
  }
  /**
   * Takes a value and makes it lowercase.
   */
  transform(value, ...args) {
    const changes = this.differs.diff(value)
    if (changes) {
      this.cashed = value.slice().reverse();;
    };
    return this.cashed
  }
}

다음과 같이 슬라이스()를 추가하고 역()을 추가할 수 있습니다.

<li *ngFor="let user of users.slice().reverse() ">
   {{ user.name }} is {{ user.age }} years old.
</li>

언급URL : https://stackoverflow.com/questions/35703258/invert-angular-2-ngfor

반응형