Adding ngbDatepicker in agGrid - angular8

I am trying to add ngbdatepicker in agGrid, but while adding the calender is coming inside the cell. I tried adding isPopUp as true but that is making the complete input oitside.
Here is the code I wrote:
{
headerName: 'Start Date',
field: 'paiStartDate',
width: 150,
editable: (params) => { return this.isEditiable(params); },
cellEditor: 'agDateInput',
},
this.components = { agDateInput: DatePickerComponent };
Here is my componenet html:
<div class="row">
<div class="col-md-12 col-lg-12">
<input data-input type="text" class="form-control" autocomplete="off"
[(ngModel)]="model" ngbDatepicker #d="ngbDatepicker" (click)="d.toggle()" placement="bottom-right"
(dateSelect) = "onDateSelect($event)"
size="13">
</div>
Here is the ts code:
export class DatePickerComponent implements OnInit, AgEditorComponent {
params: ICellEditorParams;
public selectedDate: Date = new Date();
model: NgbDateStruct;
#ViewChild('d') datePicker : ElementRef;
constructor() { }
ngOnInit() { }
getValue() {
return `${this.selectedDate.getDate()}/${this.selectedDate.getMonth() + 1}/${this.selectedDate.getFullYear()}`;
}
isCancelBeforeStart?(): boolean {
return false;
}
isCancelAfterEnd?(): boolean {
return false;
}
agInit(params: any): void {
this.params = params;
this.selectedDate = params.value;
}
onDateSelect(date:Date){
debugger;
this.selectedDate = date;
alert(this.selectedDate);
this.params.api.stopEditing();
}
isPopup(): boolean {
return false;
}
}
Please help as the calender here is opening inside of the input.

The issue here is that the popup element in rendering inside the cell. You will need to attach the popup element to the document body, to have it render as expected.
There is a blog post which addresses this which uses a different date picker component, but the concept remains the same for any date picker component: https://blog.ag-grid.com/using-third-party-datepickers-in-ag-grid/#appending-body
For your case, the easy way is to add [container]="'body'" to your input component. You can find this in the docs for component: https://ng-bootstrap.github.io/#/components/datepicker/api#NgbDate
<input data-input type="text" class="form-control" autocomplete="off"
[(ngModel)]="model" [container]="'body'" ngbDatepicker #d="ngbDatepicker" (click)="d.toggle()" placement="bottom-right"
(dateSelect) = "onDateSelect($event)"
size="13">

Related

v-on does not working why not receive $emit in custom component

I'm create a an component which represents my money field.
My target is on add element in list, set zero on money field to add next element in list...
But, my problem is that not working when send using $emit event to clear input to improve usability.
$emit works as described on image bellow
My money field:
<template>
<div class="input-group" #clear="clearInputField()">
<span>{{ title }}</span>
<input ref="displayMoney" type="text" v-model="displayMoney" #focus="isActive = true" #blur="isActive = false" />
</div>
</template>
<script>
export default {
props: {
title: String,
},
data() {
return {
money: 0,
isActive: false,
};
},
methods: {
clearInputField() {
console.log("Its work event");
this.money = 0;
this.displayMoney = "";
},
},
computed: {
displayMoney: {
get: function () {
if (this.isActive) {
return this.money;
} else {
return this.money.toLocaleString("pt-br", { style: "currency", currency: "BRL" });
}
},
set: function (modifiedMoney) {
let newMoney = parseFloat(modifiedMoney.replace(/[^\d.]/g, "."));
if (isNaN(newMoney) || newMoney.length == 0) {
newMoney = 0;
}
this.$emit("input", newMoney);
return (this.money = parseFloat(newMoney));
},
},
},
};
</script>
My principal component
<template>
<div class="wish-list">
<div class="row">
<div class="input-group">
<span>Digite sua meta: </span>
<input ref="descriptionWish" type="text" v-model="descriptionWish" />
</div>
<MoneyField title="Valor (R$): " v-model="valueWish" #keyup.native.enter="addWish" />
<button id="btnCalculate" #click="addWish()">Adicionar a lista de desejos</button>
</div>
<div class="list-items">
<ul>
<li v-for="wish in wishes" :key="wish">{{ wish }}</li>
</ul>
</div>
</div>
</template>
<script>
import MoneyField from "./Fields/MoneyField";
export default {
components: {
MoneyField,
},
data() {
return {
wishes: [],
valueWish: 0,
descriptionWish: "",
};
},
methods: {
addWish() {
if (!isNaN(this.valueWish) && this.valueWish > 0 && this.descriptionWish.length > 0) {
this.wishes.push(
`${this.descriptionWish} => ${this.valueWish.toLocaleString("pt-BR", { currency: "BRl", style: "currency" })}`
);
this.descriptionWish = "";
console.log("addWish");
this.valueWish = 0;
this.$emit("clear");
this.$refs.descriptionWish.focus();
}
this.valueWish = 0;
},
},
};
</script>
I still don't understand much about vueJS, but I believe it's something related to parent and child elements, but I've done numerous and I can't get my answer.
sorry for my bad english .
The emit sends an event from the child to the parent component not as you've done, to run a method from the child component you could add a ref in the component inside the parent one like :
<MoneyField title="Valor (R$): "
ref="moneyField" v-model="valueWish" #keyup.native.enter="addWish" />
then run this.$refs.moneyField.clearInputField() instead this.$emit("clear")

Vue Vuelidate to validate unique value based on data from server

I am trying to create a form with vuelidate. In one field I would like to check if the name is taken or not. I have some async methods to get names and ids from the server and assigning them to arrays, and I have a custom validator that checks if the name exists, either by checking the includes in the array, or by checking a computed value that already checks the array.
Neither of the methods seems to work however. If I check the array, its seems to be empty since it always returns false (even tho the array has values according to the vue tools in the browser). If I check the the computed value, I get an error with undefined.
So my question is, what is the simplest why to validate whether a value exists, and why isn't my current code wokring?
<template>
<div>
<form class="needs-validation" #submit.prevent="submitForm" method="post">
<div class="form-group row">
<label class="col-sm-2 col-form-label">Name:</label>
<div class="col-sm-10">
<input
type="text"
class="form-control"
:class="{ 'is-invalid': $v.form.name.$error }"
id="name"
placeholder="enter name"
v-model="form.name">
<span
class="text-danger"
v-if="!$v.form.name.required && $v.form.name.$dirty">name is required</span>
<span
class="text-danger"
v-if="!$v.form.name.isUnique && $v.form.name.$dirty">name not unique</span>
</div>
</div>
</form>
</div>
</template>
<script>
import { required } from 'vuelidate/lib/validators'
const isUnique = (value, vm) => {
if (value === '') return true
if (vm.names) return !vm.names.includes(value)
return true
}
export default {
data() {
return {
form: {
name: ""
}
ids: [],
names: []
}
}
validations: {
form: {
name: {
required,
isUnique
}
}
}
async created() {
try {
const response = await this.$http.get('/get_data/?fields=id,name')
var array_id = []
var array_name = []
for (var data of response.data) {
array_id.push(data['id'])
array_name.push(data['name'])
}
this.ids = array_id
this.names = array_name
}
}
}
<script>
Seem like you miss the right way to write down methods
form: {
name: {
required,
isUnique : this.isUnique
}
}
},
methods: {
isUnique = (value, vm) => {
if (value === '') return true
if (vm.names) return !vm.names.includes(value)
return true
}
}

Vue parent component not re-rendering when computed properties are changing

I have a User-Select component that wraps a v-select. This components job is to fetch list of users as user types and allow the user to select one or more users.
Here is the code for this component.
<template>
<div>
<v-select
id="recipients"
name="recipients"
:options="options"
label="name"
multiple
#search="onSearch"
v-model="selectedVal"
/>
</div>
</template>
<script>
import vSelect from 'vue-select'
import axios from 'axios'
import _ from 'lodash'
export default {
name: 'UserSelect',
components: {
'v-select': vSelect
},
props: {
value: {
type: Array
}
},
data() {
return {
options: []
}
},
computed: {
selectedVal: {
get() {
return this.value
},
set(val) {
//this.value = val
this.$emit('input', val)
}
}
},
methods: {
onSearch(search, loading) {
loading(true)
this.search(loading, search, this)
},
setSelected: function(val) {
this.$emit('input', val)
},
search: _.debounce((loading, search, vm) => {
axios
.post('searchPeople', { search }, { useCredentails: true })
.then(res => {
vm.options = res.data
loading(false)
})
}, 350)
}
}
</script>
<style lang="scss" scoped>
#import url('https://unpkg.com/vue-select#latest/dist/vue-select.css');
</style>
As you can see I have a v-model linked to a computed property , which emits input event. Also my property name is value. Hence, I expect the parent component,that is using this UserEvent component to be able to v-model.
In the parent component , i have a computed property to which I have v-modelled the selected value. Here is the code.
<template>
<div>
<b-modal id="editMessage" :title="title" :static="true">
<form id="newMessageForm" class="row">
<div class="col-md-12">
<div class="form-group row">
<label for="to" class="col-sm-3 col-form-label">To:</label>
<user-select
class="col-sm-7"
style="padding-left: 0px; padding-right: 0px"
v-model="editedMessage.recipients"
/>
</div>
<div class="form-group row">
<label for="subject" class="col-sm-3 col-form-label"
>Subject:</label
>
<input
id="subject"
name="subject"
type="text"
class="form-control col-sm-7"
:value="editedMessage.messageSubject"
/>
</div>
<div class="form-group row">
<label for="date" class="col-sm-3 col-form-label"
>Schedule for later :
</label>
<input
type="checkbox"
class="form-control col-sm-7"
v-model="scheduleForLater"
id="scheduleCheckBox"
/>
</div>
<div class="form-group row" v-if="scheduleForLater">
<label for="date" class="col-sm-3 col-form-label"
>Scheduled Date:</label
>
<datetime
v-model="editedMessage.sentDate"
type="datetime"
class="col-sm-17"
input-class="form-control col-sm-15"
input-id="date"
/>
</div>
<div class="form-group row">
<label for="body" class="col-sm-3 col-form-label">Message:</label>
<textarea
id="body"
name="body"
type="text"
rows="10"
class="form-control col-sm-7"
:value="editedMessage.messageBody"
></textarea>
</div>
</div>
</form>
<template v-slot:modal-footer="{ hide }">
<!-- Emulate built in modal footer ok and cancel button actions -->
<b-button size="sm" variant="light" #click="hide()">
Cancel
</b-button>
<b-button
size="sm"
variant="secondary"
#click="
sendMessage(true)
hide()
"
>
Save Draft
</b-button>
<b-button
size="sm"
variant="primary"
#click="
sendMessage(false)
hide()
"
>
Send
</b-button>
</template>
</b-modal>
</div>
</template>
<script>
import { mapState } from 'vuex'
import UserSelect from '#/components/UserSelect.vue'
import axios from 'axios'
export default {
name: 'NewMessage',
components: {
'user-select': UserSelect
},
data() {
return {
options: [],
scheduleForLater: false
}
},
mounted() {},
computed: {
...mapState({
openMessage: state => state.message.openMessage,
messageAction: state => state.message.messageAction
}),
editedMessage: {
get() {
if (this.messageAction === 'new') {
return this.newMessage()
} else if (this.messageAction === 'reply') {
let openMessageClone = Object.assign({}, this.openMessage)
// make sender as the recipient.
return Object.assign(openMessageClone, {
messageSubject: 'RE: ' + this.openMessage.messageSubject,
recipients: [
{
name: this.openMessage.sender.name,
id: this.openMessage.sender.id
}
]
})
} else {
let openMessageClone = Object.assign({}, this.openMessage)
return Object.assign(openMessageClone, {
messageSubject: 'FW: ' + this.openMessage.messageSubject
})
}
},
set(val) {
this.$emit('input', val)
}
},
title() {
if (this.messageAction === 'new') {
return 'New'
} else if (this.messageAction === 'reply') {
return 'Reply'
} else {
return 'Forward'
}
}
},
methods: {
newMessage() {
return {
messageBody: '',
messageSubject: '',
recipients: [],
sender: {}
}
},
sendMessage(saveOrUpdateDraft) {
var url = ''
var message = {
recipients: this.editedMessage.recipients.map(x => x.id),
subject: this.editedMessage.messageSubject,
body: this.editedMessage.messageBody,
sentDate: this.scheduleForLater ? this.editedMessage.sentDate : null,
id: ['editDraft', 'viewScheduled'].includes(this.messageAction)
? this.editedMessage.messageId
: null
}
// id indiciates message id of draft message if one was opened.
if (saveOrUpdateDraft) {
// if no changes have been made to an opened draft, or the draft is completely empty for a new or existing draft , just go back.
if (message.id) {
url = `updateDraft`
} else {
url = 'saveNewDraft'
}
} else {
if (message.id) {
url = `sendSavedMessage`
} else {
url = 'sendMessage'
}
}
axios
.post(`eventdirect/${url}`, message, {
withCredentials: true
})
.then(response => {
if (url.includes('Draft') && this.messageAction === 'viewScheduled') {
this.$store.dispatch('sent/moveToDraft', response.data)
} else if (url.includes('Draft')) {
this.$store.dispatch('drafts/updateDraft', response.data)
} else {
// else part is sending a message or scheduling a draft.
if (this.messageAction === 'editDraft') {
this.$store.dispatch('drafts/deleteDraft', response.data)
}
// if we are sending an existing scheduled messsage , just update the sent vuex store , so that the message moves from scheduled to sent bucket.
if (this.messageAction === 'viewScheduled') {
this.$store.dispatch('sent/updateMessage', response.data)
} else {
this.$store.dispatch('sent/addSentItem', response.data)
}
}
})
.catch(() => {
// TODO , add a qtip here to notify user , this message should be sent later.
// messages in draft store with target , should be posted to the target
this.$store.dispatch('drafts/updateDraft', {
...message,
target: url
})
})
}
}
}
</script>
Now i can see in the vue dev tools the computed values in this NewMessage component gets changed. However this component does not re-render and the selected values are not passed down to UserSelect component until I toggle , schedule for later checkbox , that causes the components data to change and this triggers the Vue component to suddenly start showing the selected values.
Whats going on here. There is something about Vue's reactivity that I am not able to understand here.
Thanks in anticipation. You can try it here, or click on the edit sandbox button above to view and edit the code.
To try it, click on the Vue Message link , then hit reply , then type ‘Test’ and then select ‘Test User’ from the drop down. The selected user wont show until you click the checkbox - Schedule later.
PS: Within the component , UserSelect, In the setter of the computed property selectedVal , if I manually set the value of property value (by simply uncommenting line 39 - which is commented right now) , everything works fine. However , I get a warning that property should not be directly set. Since I am emitting the input event , parent component should change its v-model and re-render , thereby causing child component to re-render. Please correct me , if my understanding is wrong. Problem once again is that the parent component’s v-model changes , but it doesn’t re-render.

vue: changes not triggered #input

Below is vue script - the concern method is called notLegalToShip which checks when age < 3.
export default {
template,
props: ['child', 'l'],
created() {
this.name = this.child.name.slice();
this.date_of_birth = this.child.date_of_birth.slice();
},
data() {
return {
edit: false,
today: moment().format('DD/MM/YYYY'),
childUnder3: false
};
},
computed: {
age() {
var today = new Date();
var birthDate = new Date(this.child.date_of_birth);
var age = today.getFullYear() - birthDate.getFullYear();
var m = today.getMonth() - birthDate.getMonth();
if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
age--;
}
return age;
}
},
methods: Object.assign(
mapActions(['updateChild']),
{
notLegalToShip() {
if(this.age < 3){
this.childUnder3 = true;
}
this.childUnder3 = false;
},
showForm() {
this.edit = true;
},
hideForm() {
this.edit = false;
},
submitForm() {
this.hideForm();
this.updateChild({
child: this.child,
name: this.name,
dateOfBirth: this.date_of_birth,
childUnder3 : this.childUnder3
});
}
}
)
}
Here's the snippet of my template. The input as below.
I want the notLegalToShip method to be triggered when I click arrow changing the year. A warning will appear when childUnder3 is "true". I've tried #change, #input on my input but my method is not triggered at all:
<div>
{{childUnder3}}
{{age}}
<div class="callout danger" v-if="childUnder3">
<h2>Sorry</h2>
<p>Child is under 3!</p>
</div>
<div v-if="!edit">
<a #click.prevent="showForm()" href="#" class="more-link edit-details edit-child">
<i class="fa fa-pencil" aria-hidden="true"></i>{{ l.child.edit_details }}
</a>
</div>
<form v-show="edit" #submit.prevent="submitForm()">
<div class="input-wrap">
<label for="account__child__date-of-birth__date">{{ l.child.date_of_birth }}</label>
<input id="account__child__date-of-birth__date" type="date" name="date_of_birth" v-on:input="notLegalToShip" v-model="date_of_birth" v-validate="'required'">
<p class="error-message" v-show="errors.has('date_of_birth')">{{ l.child.date_of_birth_invalid }}</p>
</div>
</form>
</div>
Any help checking my code above would be appreciated!
You have a couple of problems...
Initialise the name and date_of_birth properties in the data() initialiser so Vue can react to them. You can even initialise them from your child prop there...
data() {
return {
edit: false,
today: moment().format('DD/MM/YYYY'),
name: this.child.name // no need to use slice, strings are immutable
date_of_birth: this.child.date_of_birth
}
}
Use this.date_of_birth inside your age computed property instead of this.child.date_of_birth. This way, it will react to changes made via your v-model="date_of_birth" input element.
Make childUnder3 a computed property, it will be easier that way
childUnder3() {
return this.age < 3
}
Alternately, ditch this and just use v-if="age < 3"
With the above, you no longer need any #input or #change event listeners.

Angular2 Service which create, show and manage it's inner Component? How to implement js alert()?

I tried to find a way for having and manage an angular2 Component in a Service but with no success:
I need to create:
AlertService{
alertConfirm(msg): Promise;
}
alertConfirm will prompt an Confirmation window with 2 buttons (Ok, Cancel) and will return users' choise as a Promise.
In General, the idea is to implement the famous JavaScript alert() method
but with a designed UI window and with also a cancel button.
The method will return a Promise with a response of user's choice: "OK" or "Cancel".
I tried to find a way for holding an "anonymous" component, AlertComponent, in AlertService:
AlertComponent{
showMsgConfirm(msg): Promise;
}
The Promise will be set with a response when user close prompt window or click "OK" or "Cancel".
The question:
How to make "AlertService" to have an inner "AlertComponent" which can be managed by it's "alertOK" method?
I mean, I didn't find a way for "alertConfirm" to call "showMsgConfirm" method and to return it's Promise as a response.
for example, calling from main app component:
this.alertService.alertConfirm("Save changes?").then(res => {
if(res.ok){console.log("Can be saved");
}, err=> { });
Any ideas for this?
Thanks,
Update:2 different ideas for solution, but with no sucess to manage the AlertComponent:
import { Injectable, ViewContainerRef, ReflectiveInjector, ComponentFactoryResolver, ComponentRef } from '#angular/core';
import { AlertComponent } from './../components/modales/AlertComponent/AlertComponent.component';
#Injectable()
export class AlertService {
constructor(private componentFactoryResolver: ComponentFactoryResolver) { }
public createAlertComp(vCref: ViewContainerRef): ComponentRef<any> {
let factory = this.componentFactoryResolver.resolveComponentFactory(AlertComponent);
/*
//Option 1:
// vCref is needed cause of that injector..
let injector = ReflectiveInjector.fromResolvedProviders([], vCref.parentInjector);
// create component without adding it directly to the DOM
let comp = factory.create(injector);
// add inputs first !! otherwise component/template crashes ..
comp.instance.model = modelInput;
// all inputs set? add it to the DOM ..
vCref.insert(comp.hostView);
return comp;
*/
//Option 2:
var componentRef: ComponentRef<AlertComponent> = vCref.createComponent(factory);
return null;
}
}
And the answer is... :
The Service:
_counter is used for each modal to have a unique name.
comp.instance.close is a property of inner component for subscribing for EventEmitter.
.
import { Injectable, ViewContainerRef, ReflectiveInjector, ComponentFactoryResolver, ComponentRef, EventEmitter } from '#angular/core';
import { CtmAlertComponent } from './ctmAlert/ctmAlert.component';
#Injectable()
export class AlertCtmService {
private _vcr: ViewContainerRef;
private _counter: number = 0;
constructor(private componentFactoryResolver: ComponentFactoryResolver, public viewRef: ViewContainerRef) {
console.log("AlertCtmService.constructor:");
//TODO: Consider appending to this.viewRef: "#alertCtmServiceContainer" as a Dom elemnt perent container which will hold all AlertModals:
// Maybe by:
// this.viewRef.element.nativeElement.insertAdjacentHTML('beforeend', '<div class="alertCtmServiceContainer"></div>');
this._vcr = this.viewRef;
}
public alertOK(alertMsg: string): EventEmitter<any> {
return this.createEventEmitterComponent("CtmAlertComponent", alertMsg, false);
}
public alertConfirm(alertMsg: string): EventEmitter<any> {
return this.createEventEmitterComponent("CtmAlertComponent", alertMsg, true);
}
private createEventEmitterComponent(componentName: string, alertMsg: string, isConfirm: boolean): EventEmitter<any> {
console.log("AlertCtmService.createEventEmitterComponent:");
switch (componentName) {
case "CtmAlertComponent":
default:
var _component = CtmAlertComponent;
break;
}
let factory = this.componentFactoryResolver.resolveComponentFactory(_component);
// vCref is needed cause of that injector..
let injector = ReflectiveInjector.fromResolvedProviders([], this._vcr.parentInjector);
// create component without adding it directly to the DOM
let comp = factory.create(injector);
// add inputs first !! otherwise component/template crashes ..
comp.instance.close.subscribe(resp => {
console.log("AlertCtmService.createEventEmitterComponent: comp.instance.close.subscribe: resp=" + resp.ok);
comp.destroy();
})
comp.instance.alertBodyMsg = alertMsg;
comp.instance.isConfirm = isConfirm;
comp.instance.nameId = "Modal" +(++this._counter).toString();
// all inputs set? add it to the DOM ..
this._vcr.insert(comp.hostView);
//return null;
return comp.instance.close;
}
public init(vCref: ViewContainerRef): ViewContainerRef {
this._vcr = vCref;
return this._vcr;
}
}
Inner Component:
Using Bootstrap for handling display of Modal in UI: modal('show') \ modal('hide').
.
import { Component, AfterViewInit, Input, ViewChild, ElementRef, Renderer, NgZone, EventEmitter} from '#angular/core';
#Component({
selector: 'ctm-alert',
styles: [``],
templateUrl: '/app/shared/alertCtm/ctmAlert/CtmAlert.component.html',
styleUrls: ['./app/shared/alertCtm/ctmAlert/CtmAlert.component.css'],
providers: []
})
export class CtmAlertComponent implements AfterViewInit {
public ModalIsVisible: boolean;
//private static subscriptions: Object = {};
//enums = Enums;
close = new EventEmitter();
public nameId = "";
private isOk = false;
alertBodyMsg: string = "";
isConfirm = false;
constructor() {
console.log("CtmAlertComponent.constructor:");
}
ngAfterViewInit() {
this.showModal();
var attrId = this.getIdAttr();
$('#' + attrId).on('hidden.bs.modal', function () {
debugger;
console.log('CtmAlertComponent: #licenseModal_XXX.on(hidden.bs.modal)');
this.submitStatus();
}.bind(this) );
}
showModal() {
this.ModalIsVisible = true;
var attrId = '#' +this.getIdAttr();
$(attrId).modal('show');
}
hideModal() {
this.ModalIsVisible = false;
var attrId = '#' + this.getIdAttr();
$(attrId).modal('hide');
}
getIdAttr(): string {
return "ctmAlertModal_" + this.nameId;
}
submitStatus() {
var resp = { ok: (this.isOk == true) };
this.close.emit(resp);
}
submitOk() {
this.isOk = true;
this.hideModal();
}
submitCancel() {
this.isOk = false;
this.hideModal();
}
}
App's Declaration:
unfortunately, we must declare the anonymus component in our main-app module.
We must add a declaration of entryComponents: [CtmAlertComponent],
.
import { CtmAlertComponent } from './shared/alertCtm/ctmAlert/ctmAlert.component';
#NgModule({
imports: [
BrowserModule,
HttpModule,
AppRoutingModule,
...
],
declarations: [
CtmAlertComponent,
AppComponent,
...
],
entryComponents: [CtmAlertComponent],
providers: [
...
],
bootstrap: [AppComponent],
})
export class AppModule { }
enableProdMode();
Modal UI:
this html template is based on bootstrap's UI:
.
<div class="ctmAlertModal modal fade in" [id]="getIdAttr()" role="dialog">
<div class="modal-dialog modal-lg" [ngClass]="{'modal-lg-6': true }">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header" style="">
<div class="pull-right" style="position: relative;">
<span class="fa fa-times-circle" aria-hidden="true" style="color: #949494"></span>
</div>
</div>
<div class="modal-body">
<div class="modal-body-msg">
{{alertBodyMsg}}
</div>
<div class="modal-body-buttons">
<div style="margin: 0 auto;" [style.width]="(isConfirm)? '165px' : '70px' ">
<button type="button" *ngIf="isConfirm" class="btn-submit pull-left btn-cancel" [ngClass]="{'disabled': false }" [disabled]="false" (click)="submitCancel()">
<!--<img alt="End-Training" class="centering-me2" src="../../../contents/training_state_stop_white.svg">-->
Cancel
</button>
<button type="button" class="btn-submit pull-right" [ngClass]="{'disabled': false }" [disabled]="false" (click)="submitOk()">
<!--<img alt="Resume-Training" src="../../../contents/training_state_play_white.svg">-->
OK
</button>
</div>
</div>
</div>
</div>
</div>
</div>
.
Usage::
for example:
.
this.alertCtmService.alertOK("Save changes???").subscribe(function (resp) {
console.log("alertCtmService.alertOK.subscribe: resp=" + resp.ok);
this.saveData();
}.bind(this) );
**
An example I built : https://plnkr.co/qc1ZM6
**
sources:
building-angular-2-components-on-the-fly-a-dialog-box-example
angular2-ngmodule