각도 2.0 및 모달 대화 상자


128

Angular 2.0에서 Confirmation 모달 대화 상자를 수행하는 방법에 대한 몇 가지 예를 찾으려고합니다. Angular 1.0에 Bootstrap 대화 상자를 사용하고 있으며 웹에서 Angular 2.0에 대한 예제를 찾을 수 없습니다. 또한 운없이 앵귤러 2.0 문서를 확인했습니다.

Angular 2.0에서 Bootstrap 대화 상자를 사용하는 방법이 있습니까?


이 예제를 찾았습니다. 아마 그것은 당신 에게
Puya Sarmidani

1
나는 이것을 RC3과 함께 사용하고 예쁜 내용을 가지고 있습니다 : valor-software.com/ng2-bootstrap/#/modals
mentat

@Sam 덕분에 시작이 좋았습니다. 그러나 호출 구성 요소가 어떤 버튼을 클릭했는지 알지 못합니다. 몇 가지 연구를 한 후에 EventEmitters 대신 Observables사용하여보다 우아한 솔루션을 만들 수 있었습니다.
Jon


답변:


199
  • 각도 2 이상
  • 부트 스트랩 CSS (애니메이션 유지)
  • 아니 JQuery
  • bootstrap.js 없음
  • 사용자 정의 모달 컨텐츠 지원 (허용 된 답변과 동일)
  • 최근에 여러 모달에 대한 지원이 추가되었습니다 .

`

@Component({
  selector: 'app-component',
  template: `
  <button type="button" (click)="modal.show()">test</button>
  <app-modal #modal>
    <div class="app-modal-header">
      header
    </div>
    <div class="app-modal-body">
      Whatever content you like, form fields, anything
    </div>
    <div class="app-modal-footer">
      <button type="button" class="btn btn-default" (click)="modal.hide()">Close</button>
      <button type="button" class="btn btn-primary">Save changes</button>
    </div>
  </app-modal>
  `
})
export class AppComponent {
}

@Component({
  selector: 'app-modal',
  template: `
  <div (click)="onContainerClicked($event)" class="modal fade" tabindex="-1" [ngClass]="{'in': visibleAnimate}"
       [ngStyle]="{'display': visible ? 'block' : 'none', 'opacity': visibleAnimate ? 1 : 0}">
    <div class="modal-dialog">
      <div class="modal-content">
        <div class="modal-header">
          <ng-content select=".app-modal-header"></ng-content>
        </div>
        <div class="modal-body">
          <ng-content select=".app-modal-body"></ng-content>
        </div>
        <div class="modal-footer">
          <ng-content select=".app-modal-footer"></ng-content>
        </div>
      </div>
    </div>
  </div>
  `
})
export class ModalComponent {

  public visible = false;
  public visibleAnimate = false;

  public show(): void {
    this.visible = true;
    setTimeout(() => this.visibleAnimate = true, 100);
  }

  public hide(): void {
    this.visibleAnimate = false;
    setTimeout(() => this.visible = false, 300);
  }

  public onContainerClicked(event: MouseEvent): void {
    if ((<HTMLElement>event.target).classList.contains('modal')) {
      this.hide();
    }
  }
}

배경을 표시하려면 다음 CSS가 필요합니다.

.modal {
  background: rgba(0,0,0,0.6);
}

이 예에서는 이제 여러 모달을 동시에 허용합니다 . ( onContainerClicked()방법 참조 ).

Bootstrap 4 CSS 사용자의 경우 CSS 클래스 이름이 Bootstrap 3에서 업데이트되었으므로 약간의 변경이 필요합니다. 이 줄 [ngClass]="{'in': visibleAnimate}"은 다음과 같이 변경되어야합니다. [ngClass]="{'show': visibleAnimate}"

시연하기 위해 여기에 플런저가 있습니다.


그래도 문제가 있습니다. 여기에 버튼이 추가 요소로 싸여 있기 때문에 부트 스트랩 스타일링은 버튼에 여백을 적용하지 않습니다 (적어도 v4에서는). 줄 바꿈을 제거 div.modal-footer하고를 변경하면 문제 .app-modal-footer.modal-footer해결됩니다.
Axel Köhler

55

다음은 GitHub 의 Angular2 앱에서 Bootstrap 모달을 사용하는 방법에 대한 꽤 좋은 예입니다 .

핵심은 구성 요소에서 부트 스트랩 html 및 jquery 초기화를 래핑 할 수 있다는 것입니다. modal템플릿 변수를 사용하여 열기를 트리거 할 수 있는 재사용 가능한 구성 요소를 만들었습니다 .

<button type="button" class="btn btn-default" (click)="modal.open()">Open me!</button>

<modal #modal>
    <modal-header [show-close]="true">
        <h4 class="modal-title">I'm a modal!</h4>
    </modal-header>
    <modal-body>
        Hello World!
    </modal-body>
    <modal-footer [show-default-buttons]="true"></modal-footer>
</modal>

npm 패키지를 설치하고 앱 모듈에 모달 모듈을 등록하면됩니다.

import { Ng2Bs3ModalModule } from 'ng2-bs3-modal/ng2-bs3-modal';

@NgModule({
    imports: [Ng2Bs3ModalModule]
})
export class MyAppModule {}

8
Bummer-jquery를 의존성으로 사용 :(
brando

52
글쎄, 부트 스트랩은 그것에 의존하며 라이브러리를 다시 작성하는 것은 아닙니다.
Douglas Ludlow

2
이것은 jQuery없이 수행 할 수 있습니다. 나는 koscielniak.me/post/2016/03/angular2-confirm-dialog-component 의 튜토리얼과 함께 Sam의 답변을 사용하여 서비스 및 관련 모달 구성 요소를 작성했습니다.
BeetleJuice

프로젝트에서 부트 스트랩을 사용하지 않는 경우 bootstrap.css에 링크를 추가하는 것을 잊지 마십시오. github 페이지는 이것을 언급하는 것을 잊어 버렸습니다.
Shekhar

46

이것은 jquery 또는 Angular 2를 제외한 다른 라이브러리에 의존하지 않는 간단한 접근 방식입니다. 아래 구성 요소 (errorMessage.ts)는 다른 구성 요소의 자식보기로 사용할 수 있습니다. 항상 열려 있거나 표시되는 부트 스트랩 모달입니다. 가시성은 ngIf 문에 의해 관리됩니다.

errorMessage.ts

import { Component } from '@angular/core';
@Component({
    selector: 'app-error-message',
    templateUrl: './app/common/errorMessage.html',
})
export class ErrorMessage
{
    private ErrorMsg: string;
    public ErrorMessageIsVisible: boolean;

    showErrorMessage(msg: string)
    {
        this.ErrorMsg = msg;
        this.ErrorMessageIsVisible = true;
    }

    hideErrorMsg()
    {
        this.ErrorMessageIsVisible = false;
    }
}

errorMessage.html

<div *ngIf="ErrorMessageIsVisible" class="modal fade show in danger" id="myModal" role="dialog">
    <div class="modal-dialog">

        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal">&times;</button>
                <h4 class="modal-title">Error</h4>
            </div>
            <div class="modal-body">
                <p>{{ErrorMsg}}</p>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" (click)="hideErrorMsg()">Close</button>
            </div>
        </div>
    </div>
</div>

다음은 부모 컨트롤의 예입니다 (간결하게하기 위해 일부 관련이없는 코드는 생략했습니다).

parent.ts

import { Component, ViewChild } from '@angular/core';
import { NgForm } from '@angular/common';
import {Router, RouteSegment, OnActivate, ROUTER_DIRECTIVES } from '@angular/router';
import { OnInit } from '@angular/core';
import { Observable } from 'rxjs/Observable';


@Component({
    selector: 'app-application-detail',
    templateUrl: './app/permissions/applicationDetail.html',
    directives: [ROUTER_DIRECTIVES, ErrorMessage]  // Note ErrorMessage is a directive
})
export class ApplicationDetail implements OnActivate
{
    @ViewChild(ErrorMessage) errorMsg: ErrorMessage;  // ErrorMessage is a ViewChild



    // yada yada


    onSubmit()
    {
        let result = this.permissionsService.SaveApplication(this.Application).subscribe(x =>
        {
            x.Error = true;
            x.Message = "This is a dummy error message";

            if (x.Error) {
                this.errorMsg.showErrorMessage(x.Message);
            }
            else {
                this.router.navigate(['/applicationsIndex']);
            }
        });
    }

}

parent.html

<app-error-message></app-error-message>
// your html...

3
좋은-설명 할 수 있습니다class="modal fade show in danger"
bensiu

@bensiu 나는 클래스 선택기가 사용되지 않는다고 추측하고있다-예를 들어 'in'과 같은 모든 단어에 대한 CSS 스타일 선택기가 없다면
Drenai

이것으로 페이드 인 / 아웃 효과를 어떻게 얻습니까?
Big McLargeHuge

10

A와 사용할 수 NPM 패키지

각도 맞춤 모달


@Stephen Paul 계속 ...

  • 각도 2 및 부트 스트랩 CSS (애니메이션은 유지됨)
  • 아니 JQuery
  • bootstrap.js 없음
  • 커스텀 모달 컨텐츠 지원
  • 서로의 여러 모달을 지원합니다.
  • 모듈화
  • 모달이 열려있을 때 스크롤 비활성화
  • 탐색하면 모달이 파괴됩니다.
  • 게으른 콘텐츠 초기화 ngOnDestroy. 모달이 종료되면 가져 옵니다.
  • 모달이 표시되면 부모 스크롤이 비활성화됩니다.

게으른 콘텐츠 초기화

왜?

어떤 경우에는 닫은 후에 상태를 유지하기 위해 모달을 원하지 않고 오히려 초기 상태로 복원 할 수 있습니다.

원래 모달 문제

내용을 뷰로 직접 전달하면 실제로 모달이 가져 오기 전에도 내용을 초기화합니다. 모달에는 *ngIf래퍼를 사용하더라도 이러한 내용을 죽일 수있는 방법이 없습니다 .

해결책

ng-template. ng-template그렇게 명령하기 전까지는 렌더링되지 않습니다.

my-component.module.ts

...
imports: [
  ...
  ModalModule
]

my-component.ts

<button (click)="reuseModal.open()">Open</button>
<app-modal #reuseModal>
  <ng-template #header></ng-template>
  <ng-template #body>
    <app-my-body-component>
      <!-- This component will be created only when modal is visible and will be destroyed when it's not. -->
    </app-my-body-content>
    <ng-template #footer></ng-template>
</app-modal>

modal.component.ts

export class ModalComponent ... {
  @ContentChild('header') header: TemplateRef<any>;
  @ContentChild('body') body: TemplateRef<any>;
  @ContentChild('footer') footer: TemplateRef<any>;
 ...
}

modal.component.html

<div ... *ngIf="visible">
  ...
  <div class="modal-body">
    ng-container *ngTemplateOutlet="body"></ng-container>
  </div>

참고 문헌

인터넷에 대한 훌륭한 공식 및 커뮤니티 문서가 없으면 불가능했을 것입니다. 그것은 당신의 일부가 너무 더 나은 방법을 이해하는 데 도움이 될 ng-template, *ngTemplateOutlet@ContentChild작동합니다.

https://angular.io/api/common/NgTemplateOutlet
https://blog.angular-university.io/angular-ng-template-ng-container-ngtemplateoutlet/
https://medium.com/claritydesignsystem/ng-content -the-hidden-docs-96a29d70d11b
https://netbasal.com/understanding-viewchildren-contentchildren-and-querylist-in-angular-896b0c689f6e
https://netbasal.com/understanding-viewchildren-contentchildren-and-querylist-in 각도 896b0c689f6e

전체 복사-붙여 넣기 솔루션

modal.component.html

<div
  (click)="onContainerClicked($event)"
  class="modal fade"
  tabindex="-1"
  [ngClass]="{'in': visibleAnimate}"
  [ngStyle]="{'display': visible ? 'block' : 'none', 'opacity': visibleAnimate ? 1 : 0}"
  *ngIf="visible">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <ng-container *ngTemplateOutlet="header"></ng-container>
        <button class="close" data-dismiss="modal" type="button" aria-label="Close" (click)="close()">×</button>
      </div>
      <div class="modal-body">
        <ng-container *ngTemplateOutlet="body"></ng-container>
      </div>
      <div class="modal-footer">
        <ng-container *ngTemplateOutlet="footer"></ng-container>
      </div>
    </div>
  </div>
</div>

modal.component.ts

/**
 * @Stephen Paul https://stackoverflow.com/a/40144809/2013580
 * @zurfyx https://stackoverflow.com/a/46949848/2013580
 */
import { Component, OnDestroy, ContentChild, TemplateRef } from '@angular/core';

@Component({
  selector: 'app-modal',
  templateUrl: 'modal.component.html',
  styleUrls: ['modal.component.scss'],
})
export class ModalComponent implements OnDestroy {
  @ContentChild('header') header: TemplateRef<any>;
  @ContentChild('body') body: TemplateRef<any>;
  @ContentChild('footer') footer: TemplateRef<any>;

  public visible = false;
  public visibleAnimate = false;

  ngOnDestroy() {
    // Prevent modal from not executing its closing actions if the user navigated away (for example,
    // through a link).
    this.close();
  }

  open(): void {
    document.body.style.overflow = 'hidden';

    this.visible = true;
    setTimeout(() => this.visibleAnimate = true, 200);
  }

  close(): void {
    document.body.style.overflow = 'auto';

    this.visibleAnimate = false;
    setTimeout(() => this.visible = false, 100);
  }

  onContainerClicked(event: MouseEvent): void {
    if ((<HTMLElement>event.target).classList.contains('modal')) {
      this.close();
    }
  }
}

modal.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { ModalComponent } from './modal.component';

@NgModule({
  imports: [
    CommonModule,
  ],
  exports: [ModalComponent],
  declarations: [ModalComponent],
  providers: [],
})
export class ModalModule { }

7

내 프로젝트에 ngx-bootstrap 을 사용 합니다.

여기서 데모를 찾을 수 있습니다

github가 여기 있습니다

사용하는 방법:

  1. ngx-bootstrap 설치

  2. 모듈로 가져 오기

// RECOMMENDED (doesn't work with system.js)
import { ModalModule } from 'ngx-bootstrap/modal';
// or
import { ModalModule } from 'ngx-bootstrap';

@NgModule({
  imports: [ModalModule.forRoot(),...]
})
export class AppModule(){}
  1. 간단한 정적 모달
<button type="button" class="btn btn-primary" (click)="staticModal.show()">Static modal</button>
<div class="modal fade" bsModal #staticModal="bs-modal" [config]="{backdrop: 'static'}"
tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm">
   <div class="modal-content">
      <div class="modal-header">
         <h4 class="modal-title pull-left">Static modal</h4>
         <button type="button" class="close pull-right" aria-label="Close" (click)="staticModal.hide()">
         <span aria-hidden="true">&times;</span>
         </button>
      </div>
      <div class="modal-body">
         This is static modal, backdrop click will not close it.
         Click <b>&times;</b> to close modal.
      </div>
   </div>
</div>
</div>

4

다음은 모달 부트 스트랩 angular2 구성 요소의 전체 구현입니다.

태그의 맨 아래에있는 기본 index.html 파일 ( <html><body>태그 포함)에 다음이 있다고 가정합니다 <body>.

  <script src="assets/js/jquery-2.1.1.js"></script>
  <script src="assets/js/bootstrap.min.js"></script>

modal.component.ts :

import { Component, Input, Output, ElementRef, EventEmitter, AfterViewInit } from '@angular/core';

declare var $: any;// this is very importnant (to work this line: this.modalEl.modal('show')) - don't do this (becouse this owerride jQuery which was changed by bootstrap, included in main html-body template): let $ = require('../../../../../node_modules/jquery/dist/jquery.min.js');

@Component({
  selector: 'modal',
  templateUrl: './modal.html',
})
export class Modal implements AfterViewInit {

    @Input() title:string;
    @Input() showClose:boolean = true;
    @Output() onClose: EventEmitter<any> = new EventEmitter();

    modalEl = null;
    id: string = uniqueId('modal_');

    constructor(private _rootNode: ElementRef) {}

    open() {
        this.modalEl.modal('show');
    }

    close() {
        this.modalEl.modal('hide');
    }

    closeInternal() { // close modal when click on times button in up-right corner
        this.onClose.next(null); // emit event
        this.close();
    }

    ngAfterViewInit() {
        this.modalEl = $(this._rootNode.nativeElement).find('div.modal');
    }

    has(selector) {
        return $(this._rootNode.nativeElement).find(selector).length;
    }
}

let modal_id: number = 0;
export function uniqueId(prefix: string): string {
    return prefix + ++modal_id;
}

modal.html :

<div class="modal inmodal fade" id="{{modal_id}}" tabindex="-1" role="dialog"  aria-hidden="true" #thisModal>
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header" [ngClass]="{'hide': !(has('mhead') || title) }">
                <button *ngIf="showClose" type="button" class="close" (click)="closeInternal()"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
                <ng-content select="mhead"></ng-content>
                <h4 *ngIf='title' class="modal-title">{{ title }}</h4>
            </div>
            <div class="modal-body">
                <ng-content></ng-content>
            </div>

            <div class="modal-footer" [ngClass]="{'hide': !has('mfoot') }" >
                <ng-content select="mfoot"></ng-content>
            </div>
        </div>
    </div>
</div>

클라이언트 에디터 컴포넌트의 사용법 예 : client-edit-component.ts :

import { Component } from '@angular/core';
import { ClientService } from './client.service';
import { Modal } from '../common';

@Component({
  selector: 'client-edit',
  directives: [ Modal ],
  templateUrl: './client-edit.html',
  providers: [ ClientService ]
})
export class ClientEdit {

    _modal = null;

    constructor(private _ClientService: ClientService) {}

    bindModal(modal) {this._modal=modal;}

    open(client) {
        this._modal.open();
        console.log({client});
    }

    close() {
        this._modal.close();
    }

}

client-edit.html :

<modal [title]='"Some standard title"' [showClose]='true' (onClose)="close()" #editModal>{{ bindModal(editModal) }}
    <mhead>Som non-standart title</mhead>
    Some contents
    <mfoot><button calss='btn' (click)="close()">Close</button></mfoot>
</modal>

당연히 title, showClose, <mhead><mfoot>선택적 매개 변수 / 태그 싶었어.


2
대신 bindModal(modal) {this._modal=modal;}angular의 ViewChild주석을 사용할 수 있습니다 @ViewChild('editModal') _modal: Modal;. 배후에서 바인딩을 처리합니다.
Douglas Ludlow


0

ng-window를 사용하면 개발자가 단일 페이지 응용 프로그램에서 여러 창을 간단한 방법으로 열거 나 완벽하게 제어 할 수 있습니다 .Jquery 없음, Bootstrap 없음.

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

가능한 구성

  • 최대화 창
  • 창 최소화
  • 사용자 정의 크기,
  • 맞춤 위치
  • 창을 드래그 할 수 있습니다
  • 부모 창 차단
  • 창 중앙에
  • Chield 창에 값 전달
  • Chield 창에서 부모 창으로 값 전달
  • 부모 창에서 닫기 chield 창 듣기
  • 커스텀 리스너로 이벤트 크기 조정 듣기
  • 최대 크기로 열거 나
  • 창 크기 조정 활성화 및 비활성화
  • 최대화 활성화 및 비활성화
  • 최소화 활성화 및 비활성화

-1 이것이 어떻게 유용합니까? OP에서 지정한 요구 사항은 다루지 않습니다. 이것은 당신이 당신의 답변을 트롤링하는 네 번째 게시물입니다!
avn

0

앵귤러 7 + NgBootstrap

주요 컴포넌트에서 모달을 열고 결과를 다시 전달하는 간단한 방법. 내가 원하는 것입니다. 처음부터 새 프로젝트를 작성하고 ngbootstrap을 설치하고 Modal을 작성하는 단계별 자습서를 작성했습니다. 복제하거나 가이드를 따를 수 있습니다.

이것이 Angular에 새로운 도움이되기를 바랍니다.!

https://github.com/wkaczurba/modal-demo

세부:

모달 단순 템플릿 (modal-simple.component.html) :

<ng-template #content let-modal>
  <div class="modal-header">
    <h4 class="modal-title" id="modal-basic-title">Are you sure?</h4>
    <button type="button" class="close" aria-label="Close" (click)="modal.dismiss('Cross click')">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>
  <div class="modal-body">
    <p>You have not finished reading my code. Are you sure you want to close?</p>
  </div>
  <div class="modal-footer">
    <button type="button" class="btn btn-outline-dark" (click)="modal.close('yes')">Yes</button>
    <button type="button" class="btn btn-outline-dark" (click)="modal.close('no')">No</button>
  </div>
</ng-template>

모달 -simple.component.ts :

import { Component, OnInit, ViewChild, Output, EventEmitter } from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';

@Component({
  selector: 'app-modal-simple',
  templateUrl: './modal-simple.component.html',
  styleUrls: ['./modal-simple.component.css']
})
export class ModalSimpleComponent implements OnInit {
  @ViewChild('content') content;
  @Output() result : EventEmitter<string> = new EventEmitter();

  constructor(private modalService : NgbModal) { }

  open() {
    this.modalService.open(this.content, {ariaLabelledBy: 'modal-simple-title'})
      .result.then((result) => { console.log(result as string); this.result.emit(result) }, 
        (reason) => { console.log(reason as string); this.result.emit(reason) })
  }

  ngOnInit() {
  }

}

데모 (app.component.html)-리턴 이벤트를 처리하는 간단한 방법 :

<app-modal-simple #mymodal (result)="onModalClose($event)"></app-modal-simple>
<button (click)="mymodal.open()">Open modal</button>

<p>
Result is {{ modalCloseResult }}
</p>

app.component.ts-모달이 닫히면 onModalClosed가 실행됩니다.

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  modalCloseResult : string;
  title = 'modal-demo';

  onModalClose(reason : string) {
    this.modalCloseResult = reason;
  }    
}

건배

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.