Show loading image on each api call till response comes in axios library globally - axios

Sometimes, when we call an api,it takes long time to respond so we prefer to show loading image till response come.
there is start and end event in ajax request to show loading image , I want same kind of stuff in axios.
I want to make it globally for each request in axios library for react.
please suggest me something for this.

import React, {Component} from 'react';
import axios from 'axios';
import loading from '../loading.gif' // relative path to image
class Home extends Component {
constructor() {
super()
this.state = {
time: null,
loading: true,
retJobs: []
}
this.getJobs();
}
getJobs() {
axios.get('http://example.com/getData.php')
.then(response => {
this.setState({retJobs: response.data});
console.log(response);
console.log(this.state.retJobs.results.length);
console.log(this.state.retJobs.results);
this.setState({
time: response.data.time,
loading: false
});
})
.catch(function (error) {
console.log(error);
});
}
render() {
let content;
if (this.state.loading) {
content = <img src={loading} alt="loading"/>// or another graceful content
} else {
content = <p className="jobCount">Found {this.state.retJobs.results.length} Jobs</p>;
}
return (
<div>
<h4>Home</h4>
<div className="App-intro">
<div className="container">
<div className="row mainContent">
<div className=" row mainContent">
{content}
{this.state.retJobs.results && this.state.retJobs.results.map(function (item, idx) {
return <div key={idx} className="col-lg-12">
<div className="jobs">
<div className="row jobHeader">
<div className="col-lg-6">
<h1>{item.jobTitle}</h1>
</div>
<div className="col-lg-6">
<h3>{item.locationName}</h3>
</div>
</div>
<div className="row">
<div className="col-lg-2">
<h2>{item.employerName}</h2>
</div>
<div className="col-lg-10">
<p>{item.jobDescription}</p>
</div>
</div>
</div>
</div>
})}
</div>
</div>
</div>
</div>
</div>
);
}
}
export default Home;

Related

Vue3 data is null

I've created a small sample with vuejs3 to display some data.
I do have connection to the server. I had a CORS issue but have configured a proxy to access data from the client.
main.js
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
App.vue
<template>
<div class="container mt-5">
<div class="row">
<div class="col-12">
<contract-data/>
</div>
</div>
</div>
</template>
<script>
import ContractData from "./components/ContractData.vue";
export default {
name: "App",
components: {
ContractData,
}
}
ContractData.vue
<template>
<table class="table">
<tr><td>Contract-Id</td><td>{{ contractData.id }}</td></tr>
</table>
</template>
<script>
import axios from 'axios';
export default {
name: "contract-data",
data() {
return {
contractData: null
};
},
async created() {
const response = await axios.get("http://localhost:8080/contract/123456");
console.log(response.data);
this.contractData = response.data;
}
};
</script>
The thing is: I see the json data returned in the console.log statement in the async block. However it seems that the assignement to contractData is not working.

Reactjs submit form and setState not working first time

I have a submit action for my form which basically validates on submit.
It is working as i expect because when i submit the form it renders the errors. But the issue occurs when i do the submit i do not want to do the ajax request as the form is invalid. I notice that on the first submit the emailError is not set (default) but the second submit the state contains the correct emailError set to true.
I understand from the react docs that setState is not available immeditely as it is pending.
How can i get around this issue?
My code is below
import React, { Component } from 'react';
import isEmail from 'validator/lib/isEmail';
class formExample extends Component
{
constructor(props) {
super(props);
this.state = {
email: '',
emailError: false
};
this.register = this.register.bind(this);
this.updateState = this.updateState.bind(this);
}
updateState(e) {
this.setState({ email: e.target.value });
}
validateEmail() {
if (!isEmail(this.state.email)) {
console.log("setting state");
this.setState({ emailError: true });
return;
}
console.log(this.state);
this.setState({ emailError: false });
}
register(event) {
event.preventDefault();
this.validateEmail();
//only if valid email then submit further
}
render() {
return (
<div className="row">
<div className="col-md-2 col-md-offset-4"></div>
<div className="col-lg-6 col-lg-offset-3">
<form role="form" id="subscribe" onSubmit={this.register}>
<div className="form-group">
<input type="text" className="form-control" placeholder="Email..." name="email" value={this.state.email} onChange={this.updateState} />
<div className="errorMessage">
{this.state.emailError ? 'Email address is invalid' : ''}
</div>
</div>
<div className="input-group input-group-md inputPadding">
<span className="input-group-btn">
<button className="btn btn-success btn-lg" type="submit">
Submit
</button>
</span>
</div>
</form>
</div>
</div>
);
}
}
export default formExample;
in register you call validateEmail, but not return anything, so the rest of the function get's called.
setState is async! so you cannot count on it in the rest of register.
Try this:
validateEmail() {
const isEmailError = !isEmail(this.state.email)
this.setState({ emailError: isEmailError });
return isEmailError;
}
register(event) {
if(this.validateEmail()){
//ajax
};
}
other approach will be:
validateEmail(ajaxCb) {
const isEmailError = !isEmail(this.state.email)
this.setState({ emailError: isEmailError }, ajaxCb);
}
register(event) {
function ajaxCb(){...}
this.validateEmail(ajaxCb)
}

Meteor-react inserting url into mongodb stores 'null'

I am using form component to insert data into the Mongo-Collection. When I check in terminal for stored information I do successfuly store Title and data from Select input, but have value of null for both url and file inputs.
Here is the code for handling insert method on import folder:
Meteor.methods({
'posts.insert' : function(post) {
return Posts.insert({
createdAt: new Date(),
title: post.title,
social: post.social,
link: this.link,
file: this.file
});
}
});
Here is the component code for handling form submit:
import React, { Component } from 'react';
class AddPost extends Component {
constructor(props) {
super(props);
this.state = {error: ''};
}
handleSubmit(event) {
event.preventDefault();
const title = this.refs.title.value;
const social = this.refs.social.value;
const link = this.refs.link.value;
const file = this.refs.file.value;
Meteor.call('posts.insert', {title, social, link, file});
}
render() {
return (
<div className="modal fade" id="myModal" tabIndex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div className="form-outer">
<form id='add_post' onSubmit={this.handleSubmit.bind(this)}>
<div className='form-text form-header'>
<p><strong>Hey</strong>, master<span className='error'>{this.state.error}</span></p>
<p>Lets share something new today?</p>
</div>
<input ref="title" type="text" className="form-input" placeholder="What about the title?" />
<div className='form-text form-header form-header-distance'>
<p>Where should I point the way?</p>
</div>
<select ref="social" className="form-select">
<option>Select</option>
<option>Instagram</option>
<option>Twitter</option>
</select>
<input ref="link" type="url" className="form-input" placeholder="Point the way" />
<div className='form-text form-header form-header-distance'>
<p>And what about the image?</p>
</div>
<label className="file form-file">
<input ref='file' className='form-input' type="file" id="file" />
<span className="file-custom"></span>
</label>
<button type="button" className="form-button" data-dismiss="modal">Close</button>
<button type="sumbit" className="form-button" >Save</button>
</form>
</div>
</div>
);
}
}
export default AddPost;
P.S: It's out of topic of these question, but I will do appreciate a lot if you could point me to some external resource or explain if it's possible to upload/store new images (not static from public folder) from local machine and serve them to front-end view?
Make your meteor method as below:
Meteor.methods({
'posts.insert'(post){
post.createdAt: new Date();
Posts.insert(post);
}
})

Meteor + React: Append response to DOM after a Meteor.call?

I am super new to React and quite new to Meteor.
I am doing a Meteor.call to a function ('getTheThing'). That function is fetching some information and returns the information as a response. In my browser I can see that the method is returning the correct information (a string), but how do I get that response into the DOM?
(As you can see, I have tried to place it in the DOM with the use of ReactDOM.findDOMNode(this.refs.result).html(response);, but then I get this error in my console: Exception in delivering result of invoking 'getTheThing': TypeError: Cannot read property 'result' of undefined)
App = React.createClass({
findTheThing(event) {
event.preventDefault();
var username = ReactDOM.findDOMNode(this.refs.textInput).value.trim();
Meteor.call("getTheThing", username, function(error, response){
console.log(response);
ReactDOM.findDOMNode(this.refs.result).html(response);
});
ReactDOM.findDOMNode(this.refs.textInput).value = "";
},
render(){
return(
<div className="row">
<div className="col-xs-12">
<div className="landing-container">
<form className="username" onSubmit={this.findTheThing} >
<input
type="text"
ref="textInput"
placeholder="what's your username?"
/>
</form>
</div>
<div ref="result">
</div>
</div>
</div>
);
}
});
this is under the different context, thus does not contain the refs there. Also, you cannot set html for the Dom Element. You need to change into Jquery element
var _this = this;
Meteor.call("getTheThing", username, function(error, response){
console.log(response);
$(ReactDOM.findDOMNode(_this.refs.result)).html(response);
});
Though i recommend you to set the response into the state and let the component re-rendered
For a complete React way
App = React.createClass({
getInitialState() {
return { result: "" };
},
shouldComponentUpdate (nextProps: any, nextState: any): boolean {
return (nextState['result'] !== this.state['result']);
},
findTheThing(event) {
event.preventDefault();
var username = ReactDOM.findDOMNode(this.refs.textInput).value.trim();
Meteor.call("getTheThing", username, function(error, response){
console.log(response);
_this.setState({ result: response });
});
ReactDOM.findDOMNode(this.refs.textInput).value = "";
},
render(){
return(
<div className="row">
<div className="col-xs-12">
<div className="landing-container">
<form className="username" onSubmit={this.findTheThing} >
<input
type="text"
ref="textInput"
placeholder="what's your username?"
/>
</form>
</div>
<div ref="result">{this.state['result']}</div>
</div>
</div>
</div>
);
}
});

Angular 2.0 and Modal Dialog

I am trying to find some examples on how to do a Confirmation modal dialog in Angular 2.0. I have been using Bootstrap dialog for Angular 1.0 and unable to find any examples in the web for Angular 2.0. I also checked angular 2.0 docs with no luck.
Is there a way to use the Bootstrap dialog with Angular 2.0?
Angular 2 and up
Bootstrap css (animation is preserved)
NO JQuery
NO bootstrap.js
Supports custom modal content (just like accepted answer)
Recently added support for multiple modals on top of each other.
`
#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();
}
}
}
To show the backdrop, you'll need something like this CSS:
.modal {
background: rgba(0,0,0,0.6);
}
The example now allows for multiple modals at the same time. (see the onContainerClicked() method).
For Bootstrap 4 css users, you need to make 1 minor change (because a css class name was updated from Bootstrap 3). This line:
[ngClass]="{'in': visibleAnimate}" should be changed to:
[ngClass]="{'show': visibleAnimate}"
To demonstrate, here is a plunkr
Here's a pretty decent example of how you can use the Bootstrap modal within an Angular2 app on GitHub.
The gist of it is that you can wrap the bootstrap html and jquery initialization in a component. I've created a reusable modal component that allows you to trigger an open using a template variable.
<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>
You just need to install the npm package and register the modal module in your app module:
import { Ng2Bs3ModalModule } from 'ng2-bs3-modal/ng2-bs3-modal';
#NgModule({
imports: [Ng2Bs3ModalModule]
})
export class MyAppModule {}
This is a simple approach that does not depend on jquery or any other library except Angular 2.
The component below (errorMessage.ts) can be used as a child view of any other component. It is simply a bootstrap modal that is always open or shown. It's visibility is governed by the ngIf statement.
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">×</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>
This is an example parent control (some non-relevant code has been omitted for brevity):
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...
Now available as a NPM package
angular-custom-modal
#Stephen Paul continuation...
Angular 2 and up Bootstrap css (animation is preserved)
NO JQuery
NO bootstrap.js
Supports custom modal content
Support for multiple modals on top of each
other.
Moduralized
Disable scroll when modal is open
Modal gets destroyed when navigating away.
Lazy content initialization, which gets ngOnDestroy(ed) when the modal is exited.
Parent scrolling disabled when modal is visible
Lazy content initialization
Why?
In some cases you might not want to modal to retain its status after having been closed, but rather restored to the initial state.
Original modal issue
Passing the content straightforward into the view actually generates initializes it even before the modal gets it. The modal doesn't have a way to kill such content even if using a *ngIf wrapper.
Solution
ng-template. ng-template doesn't render until ordered to do so.
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>
References
I have to say that it wouldn't have been possible without the excellent official and community documentation around the net. It might help some of you too to understand better how ng-template, *ngTemplateOutlet and #ContentChild work.
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
Full copy-paste solution
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 { }
I use ngx-bootstrap for my project.
You can find the demo here
The github is here
How to use:
Install ngx-bootstrap
Import to your module
// 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(){}
Simple static modal
<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">×</span>
</button>
</div>
<div class="modal-body">
This is static modal, backdrop click will not close it.
Click <b>×</b> to close modal.
</div>
</div>
</div>
</div>
Here is my full implementation of modal bootstrap angular2 component:
I assume that in your main index.html file (with <html> and <body> tags) at the bottom of <body> tag you have:
<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">×</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>
And example of usage in client Editor component:
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>
Ofcourse title, showClose, <mhead> and <mfoot> ar optional parameters/tags.
Check ASUI dialog which create at runtime. There is no need of hide and show logic. Simply service will create a component at runtime using AOT
ASUI NPM
try to use ng-window, it's allow developer to open and full control multiple windows in single page applications in simple way, No Jquery, No Bootstrap.
Avilable Configration
Maxmize window
Minimize window
Custom size,
Custom posation
the window is dragable
Block parent window or not
Center the window or not
Pass values to chield window
Pass values from chield window to parent window
Listening to closing chield window in parent window
Listen to resize event with your custom listener
Open with maximum size or not
Enable and disable window resizing
Enable and disable maximization
Enable and disable minimization
Angular 7 + NgBootstrap
A simple way of opening modal from main component and passing result back to it. is what I wanted. I created a step-by-step tutorial which includes creating a new project from scratch, installing ngbootstrap and creation of Modal. You can either clone it or follow the guide.
Hope this helps new to Angular.!
https://github.com/wkaczurba/modal-demo
Details:
modal-simple template (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">×</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>
The 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 of it (app.component.html) - simple way of dealing with return event:
<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 is executed once modal is closed:
#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;
}
}
Cheers