如何在 Angular4 中为多个项目显示带有 *ngFor 的模态 window

How to show a modal window with *ngFor for multiple items in Angular4

我正在尝试一个简单的项目来学习 Angular,但我目前遇到了一个问题: 我正在为一些虚拟人加载服务​​,然后显示带有这些人姓名的框。当我单击一个框时,会出现一个模式弹出窗口并显示有关此人的更多信息 - 目前只是 string 的简短简历。

问题是我有一个 *ngFor 迭代 persons 然后我怀疑发生的是我还为每个人创建了一个模态 window。然后模态 window 不知道当前选择的人是谁,所以它只显示列表中第一个人的简历 ...

所以问题是我如何让它适用于每个当前选定的人;即当我点击 id = 3 的人时,模态显示同一个人的简历。

我想这需要以编程方式完成,这就是为什么我不使用 href="#modal" data-toggle="modal" 之类的东西将模式 window 绑定到事件的原因。

有什么更好的主意吗?

这是我的:PersonComponent

@Component({
    selector: 'person',
    templateUrl: './person.component.html'
})
export class PersonComponent implements OnInit {

    people: Person[];

    selectedPerson: Person;

    personBio: string;

    @ViewChild('personModal') private personModal;

    constructor(private router: Router,
                private activatedRoute: ActivatedRoute,
                private stateService: StateService,
                private personService: PersonService) {
    }

    ngOnInit() {
        this.loadAllPeople();
    }

    private loadAllPeople() {

        this.personService.getPeople()
            .subscribe(result => {
                this.people = result;
            }, error => {
                this.console.log(error);
            });
    }

    goToPersonEditComponent(person: Person) {
        this.stateService.person = this.selectedPerson;
        this.router.navigate(['../' + FrontendRoute.EDIT], {relativeTo: this.activatedRoute});
    }


    loadPersonBioModal(person: Person) {
        if (this.personModal) {
            this.selectedPerson = person;
            jQuery(this.personModal.nativeElement).modal('show');
        }

        this.personService.getPersonBio(person.id)
            .subscribe((bio) => this.personBio = bio);
    }

    closeModal() {
        if (this.personModal) {
            jQuery(this.personModal.nativeElement).on('hide.bs.modal', (evt) => {
                this.selectedPerson = null;
            });
        }
    }
}

人物编辑组件:为了简单起见,我没有展示整个内容,但我的想法是我得到了选定的人物,我可以从 id 属性编辑它的个人简介。

@Component({
    selector: 'person-edit',
    templateUrl: './person-edit.component.html'
})

export class PersonEditComponent implements OnInit {

    person: Person;

    constructor(private router: Router,
                private activatedRoute: ActivatedRoute,
                private packService: PackService,
                private orderService: PackOrderService,
                private stateService: StateService,
                private eventBusService: EventBusService,
                private loggingService: LoggingService) {

    }

    ngOnInit() {
        this.person = this.stateService.person;
    }     

}

用于在组件之间传递内容的简单服务(我想要这种方式而不是使用@Input):

@Injectable()
export class StateService {

    private _person: Person;

    constructor() {
    }

    get person() {
        return this._person;
    }

    set person(person: Person) {
        this._person = person;
    }

    clear() {
        this._person = null;
    }
}

这是我的模板,其中有 modal:

<div>
    <h2 class="h2">People</h2>
    <div class="item-collection item-collection-3-columns item-collection-tablet item-collection-wide">
        <div class="items">
            <article *ngFor="let person of people"
                     (click)="loadPersonBioModal(person)">
                <div class="content">
                    <div class="headline">
                        <span>{{person.name}}</span>
                        <span data-original-title="Show Person's Bio"></span>
                    </div>
                </div>
            </article>
        </div>
    </div>        
</div>

<div #personModal tabindex="-1" role="dialog" class="modal fade" style="display: none;"
     aria-hidden="true">
    <div role="document" class="modal-dialog modal-lg modal-has-header modal-has-footer">
        <div class="modal-content">{{personBio}}</div>
        <div class="modal-footer">
            <div class="section-btns">
                <button type="button" data-dismiss="modal"
                        (click)="closeModal()">Close
                </button>
                <button type="button" data-dismiss="modal"
                        (click)="goToPersonEditComponent(selectedPerson)">Edit Bio
                </button>
            </div>
        </div>
    </div>
</div>

这里是进行 http 调用的 PersonService:

@Injectable()
export class PersonService {

    constructor(private http: HttpClient, private router: Router) {
    }

    getPeople(): Observable<Person[]> {
        return this.http.get<Person[]>(BackendRoute.PERSON_DATA)
            .catch(error => {
                return Observable.throw(new Error('An unexpected error occurred' + error));
            });
    }

    getPersonBio(): Observable<Person> {
        return this.http.get<Person>(BackendRoute.PERSON_BIO)
            .catch(error => Observable.throw(new Error(error)));
            });
    }
}

好的,根据您的意见,我认为可能发生的情况是您在 getPersonBio() returns 人员信息之前显示您的模态并将其分配给 personBio 属性.

解决这个问题的一个可能简单的方法是使用 async 管道为您异步更新值。试试这个,

在你的 PersonComponent 中,

personBio: Observable<Person>;

loadPersonBioModal(person: Person) {
  if (this.personModal) {
    this.selectedPerson = person;
    // directly assigning the returned observable of Person type and let async pipe do its magic in the template
    this.personBio = this.personService.getPersonBio(person.id);
    jQuery(this.personModal.nativeElement).modal('show');
  }
}

在您的模板中,

<div class="modal-content">{{ personBio | async }}</div>

您必须导入 CommonModule 才能正常工作,正如 docs 中可能看到的那样。此外,不建议直接在 angular 中使用 jQuery 方法,除非没有其他支持的方法。

如果有帮助请告诉我。