Angular 2.0 i okno dialogowe modalne


129

Próbuję znaleźć kilka przykładów, jak wykonać modalne okno dialogowe Potwierdzenie w Angular 2.0. Używałem okna dialogowego Bootstrap dla Angular 1.0 i nie mogę znaleźć żadnych przykładów w sieci dla Angular 2.0. Też sprawdziłem doktorów kątowych 2.0 bez powodzenia.

Czy istnieje sposób na użycie okna dialogowego Bootstrap w Angular 2.0?


Znalazłem ten przykład. Może to ci pomoże angularscript.com/angular2-modal-window-with-bootstrap-style
Puya Sarmidani

1
Używam tego jednego z RC3 i ładny treści z nim: valor-software.com/ng2-bootstrap/#/modals
Mentat

Dzięki @Sam mam dobry start. Zauważyłem jednak, że komponent wywołujący nie wie, który przycisk został kliknięty. Po kilku badaniach mogłem użyć Observables zamiast EventEmitters, aby wymyślić bardziej eleganckie rozwiązanie .
Jon


@mentat, zaktualizowany adres URL valor-software.com/ngx-bootstrap/#/modals
Anand Rockzz

Odpowiedzi:


199
  • Angular 2 i nowsze
  • Bootstrap css (animacja jest zachowana)
  • NO JQuery
  • BRAK pliku bootstrap.js
  • Obsługuje niestandardową zawartość modalną (podobnie jak zaakceptowana odpowiedź)
  • Niedawno dodane wsparcie dla wielu modali jeden na drugim .

`

@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();
    }
  }
}

Aby wyświetlić tło , potrzebujesz czegoś takiego jak ten CSS:

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

Przykład pozwala teraz na jednoczesne użycie wielu modali . (zobacz onContainerClicked()metodę).

Dla użytkowników css Bootstrap 4 , musisz dokonać 1 drobnej zmiany (ponieważ nazwa klasy css została zaktualizowana z Bootstrap 3). Ten wiersz: [ngClass]="{'in': visibleAnimate}"należy zmienić na: [ngClass]="{'show': visibleAnimate}"

Aby zademonstrować, oto plunkr


Jest jednak gotcha. Ponieważ przyciski są tutaj zawinięte w dodatkowy element, styl bootstrap nie zastosuje marginesów do przycisków (przynajmniej w wersji 4). usunięcie opakowania div.modal-footeri zmiana, .app-modal-footeraby .modal-footerto naprawić.
Axel Köhler

55

Oto całkiem przyzwoity przykład tego, jak można używać modalu Bootstrap w aplikacji Angular2 na GitHub .

Istotą tego jest to, że możesz opakować inicjalizację bootstrap html i jquery w komponent. Stworzyłem modalkomponent wielokrotnego użytku , który umożliwia otwieranie za pomocą zmiennej szablonu.

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

Wystarczy zainstalować pakiet npm i zarejestrować moduł modalny w module aplikacji:

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

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

8
Bummer - polega na jquery jako zależności :(
brando

52
Cóż, tak, bootstrap polega na tym, a ja nie zajmuję się przepisywaniem bibliotek.
Douglas Ludlow

2
Można to zrobić bez jQuery. Użyłem odpowiedzi Sama wraz z samouczkiem na koscielniak.me/post/2016/03/angular2-confirm-dialog-component do napisania usługi i związanego z nią komponentu modalnego.
BeetleJuice

Jeśli nie używasz bootstrap w swoim projekcie, nie zapomnij dodać linku do bootstrap.css. Strona github zapomina o tym wspomnieć.
Shekhar,

46

Jest to proste podejście, które nie zależy od jquery ani żadnej innej biblioteki poza Angular 2. Poniższy komponent (errorMessage.ts) może być użyty jako widok potomny dowolnego innego komponentu. Jest to po prostu modal bootstrap, który jest zawsze otwarty lub pokazany. O jego widoczności decyduje instrukcja 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>

Oto przykład kontroli rodzicielskiej (część nieistotnego kodu została pominięta ze względu na zwięzłość):

rodzic.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
fajny - mógłby wyjaśnićclass="modal fade show in danger"
bensiu

@bensiu Domyślam się, że selektor klasy nie jest używany - chyba że mają selektory w stylu css dla wszystkich tych słów, np. „in”
Drenai

Jak dzięki temu uzyskać efekt zanikania / zanikania?
Big McLargeHuge

10

Teraz dostępny jako pakiet NPM

kątowe-niestandardowe-modalne


@Stephen Paul kontynuacja ...

  • Angular 2 i nowsze Bootstrap CSS (animacja jest zachowana)
  • NO JQuery
  • BRAK pliku bootstrap.js
  • Obsługuje niestandardową zawartość modalną
  • Wsparcie dla wielu modali jeden na drugim.
  • Zmoduralizowany
  • Wyłącz przewijanie, gdy modalne jest otwarte
  • Modal zostaje zniszczony podczas nawigacji.
  • Leniwa inicjalizacja treści, która zostaje ngOnDestroy(ed) po wyjściu z trybu modalnego.
  • Przewijanie rodzica wyłączone, gdy widoczne jest modalne

Leniwa inicjalizacja treści

Czemu?

W niektórych przypadkach możesz nie chcieć modować, aby zachować jego status po zamknięciu, ale raczej przywrócić stan początkowy.

Oryginalny problem modalny

Przekazanie zawartości bezpośrednio do widoku faktycznie generuje ją, inicjalizując ją jeszcze przed pobraniem przez modal. Modal nie ma sposobu na zabicie takiej zawartości, nawet jeśli używa *ngIfopakowania.

Rozwiązanie

ng-template. ng-templatenie renderuje się, dopóki nie otrzyma polecenia.

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>

Bibliografia

Muszę powiedzieć, że nie byłoby to możliwe bez doskonałej oficjalnej i społecznościowej dokumentacji dostępnej w sieci. To może pomóc niektórym z was też lepiej zrozumieć, w jaki sposób ng-template, *ngTemplateOutleti @ContentChildpraca.

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 -angular-896b0c689f6e

Pełne rozwiązanie kopiuj-wklej

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

W moim projekcie używam ngx-bootstrap .

Możesz znaleźć demo tutaj

Github jest tutaj

Jak używać:

  1. Zainstaluj plik ngx-bootstrap

  2. Importuj do swojego modułu

// 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. Prosty statyczny modalny
<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

Oto moja pełna implementacja modalnego komponentu angular2 bootstrap:

Zakładam, że w swoim głównym pliku index.html (z tagami <html>i <body>) na dole <body>tagu masz:

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

I przykład użycia w komponencie Client Editor: 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>

Oczywiście title, showClose, <mhead>a <mfoot>ar opcjonalne Parametry / tagi.


2
Zamiast bindModal(modal) {this._modal=modal;}można użyć kątowych za ViewChildadnotacji, tak jak poniżej: @ViewChild('editModal') _modal: Modal;. Zajmuje się wiązaniem za kulisami.
Douglas Ludlow


0

spróbuj użyć ng-window, pozwala programistom na otwieranie i pełną kontrolę wielu okien w aplikacjach jednostronicowych w prosty sposób, bez Jquery, bez Bootstrap.

wprowadź opis obrazu tutaj

Avilable Configration

  • Maksymalizuj okno
  • Zminimalizuj okno
  • Niestandardowy rozmiar,
  • Pozycja niestandardowa
  • okno można przeciągać
  • Zablokuj okno nadrzędne, czy nie
  • Wyśrodkuj okno lub nie
  • Przekaż wartości do okna chield
  • Przekaż wartości z okna chield do okna nadrzędnego
  • Słucham zamykania okna chielda w oknie nadrzędnym
  • Słuchaj zdarzenia zmiany rozmiaru za pomocą niestandardowego odbiornika
  • Otwórz z maksymalnym rozmiarem lub nie
  • Włącz i wyłącz zmianę rozmiaru okna
  • Włącz i wyłącz maksymalizację
  • Włącz i wyłącz minimalizację

-1 Jak to w ogóle jest przydatne? Nie odnosi się do żadnego z wymagań określonych w PO. To jest czwarty post Widzę, jak trollujesz swoją odpowiedź!
avn

0

Kątowy 7 + NgBootstrap

Prosty sposób na otwarcie modalu z głównego komponentu i przekazanie do niego wyniku. jest tym, czego chciałem. Stworzyłem samouczek krok po kroku, który obejmuje tworzenie nowego projektu od podstaw, instalację ngbootstrap i tworzenie modalu. Możesz go sklonować lub postępować zgodnie z instrukcjami.

Mam nadzieję, że to pomoże nowicjuszom w Angular.!

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

Detale:

szablon modal-simple (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>

Plik modal-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() {
  }

}

Demo (app.component.html) - prosty sposób radzenia sobie ze zdarzeniem zwrotu:

<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 jest wykonywany po zamknięciu modalu:

@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;
  }    
}

Twoje zdrowie

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.