Signaturepad clear property not clearing in modal-bootstrap dialog box - html

I am working on signature pad dialogue box and for the dialogue box i am using bootstrap modal. In this activity when i click on complete activity a dialogbox should open asking yes or no on clicking yes a dialog box with signaturepad in modal body and clear button in modal footer.
the problem is when clicking on clear button from modal footer the clear method of signaturepad module is not working Any suggestions would be of great help
import { Component, OnInit, ViewChild, Directive } from '#angular/core';
import { NgbModalConfig, NgbModal } from '#ng-bootstrap/ng-bootstrap';
import {SignaturePad} from 'angular2-signaturepad/signature-pad';
import { ClickOutsideModule } from 'ng-click-outside';
#Component({
selector: 'app-modal',
templateUrl: './modal.component.html',
styleUrls: ['./modal.component.css']
})
export class ModalComponent {
#ViewChild('SignaturePad1', { static: true })signaturepad: SignaturePad;
public signaturepadoption = {
minWidth: 2,
penColor: 'rgb(255,0,0)',
backgroundColor: 'rgb(0,0,0)',
canvasWidth: 250,
canvasHeight: 300,
};
closeResult: string;
constructor(private modalService: NgbModal) {}
openSm(content) {
this.modalService.open(content, { centered: true });
}
SignaturepadPopUp(longContent) {
this.modalService.open(longContent, { scrollable: true, centered: true });
}
onClear() {
this.signaturepad.clear();
}
saveSignature() {
const base64 = this.signaturepad.toDataURL('image\png', 0.1);
console.log(base64);
const blob = this.base64toblob(base64);
console.log(blob);
}
base64toblob(base64) {
const bytestring = atob(base64.split(',')[1]);
const stringtype = base64.split(',')[0].split(':')[1].split(':')[0];
const size = bytestring.length;
const saveString: any[] = new Array(size);
for (let i = 0; i < bytestring.length; i++) {
saveString[i] = bytestring.charAt(i);
}
const ia = new Uint8Array(saveString);
return new Blob([ia], {type: stringtype});
}
}
<ng-template #content let-modal>
<div class="modal-header">
<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>Are you sure You want to complete Activity?</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" (click)="modal.close('Close click')">No</button>
<button type="button" class="btn btn-primary" (click)="SignaturepadPopUp(longContent)">Yes</button>
</div>
</ng-template>
<ng-template #longContent let-modal>
<div class="modal-header">
<button type="button" class="close" aria-label="Close" (click)="modal.dismiss('Cross click')">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="col-md-12">
<div class="m-signature-pad">
<div class="m-signature-pad-body">
<signature-pad #SignaturePad1 [options]="signaturepadoption"></signature-pad>
</div>
</div>
</div>
</div>
<button type="button" class="btn btn-primary" (click)="onClear()">clear</button>
</ng-template>
<button class="btn btn-secondary" (click)="openSm(content)">Complete Activity</button>

The reason this happens is because ng-template is not rendered yet and thus the signature pad will be undefined. A way I found to work around this is to create my signature pad in a separate component and then add that component to the ngbModal.
So in your example:
<ng-template #longContent let-modal>
<div class="modal-header">
<button type="button" class="close" aria-label="Close" (click)="modal.dismiss('Cross click')">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="col-md-12">
<div class="m-signature-pad">
<div class="m-signature-pad-body">
<!-- <signature-pad #SignaturePad1 [options]="signaturepadoption"></signature-pad> -->
<app-my-signature-pad-component></app-my-signature-pad-component> <!-- In this component you add the above commented out line and then do your functionality for the signature pad there. -->
</div>
</div>
</div>
</div>
<button type="button" class="btn btn-primary" (click)="onClear()">clear</button>
</ng-template>
I found that with this approach, you are able to use the ViewChild and don't get the undefined issue.
Hope this makes sense!

Related

Focus on timepicker instead of modal window

My modal window is blocking my time picker on Angular
Component.ts
open() {
const amazingTimePicker = this.atp.open();
amazingTimePicker.afterClose().subscribe(time => {
console.log(time);
});
}
// Triggering the modal window
createApplication(content) {
this.modalService.open(content, {centered: true, size: 'lg'});
}
Modal html
<ng-template #create let-modal>
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">Job Application</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">
<form #createApplicationForm="ngForm" (ngSubmit)="createApplicationForm.form.valid && createForm(createApplicationForm)" >
<div class="form-group">
<div class="input-group">
<input class="form-control" id="preferredContactDate" name="preferredContactDate"
[(ngModel)]="newApplicationFormDateModel" ngbDatepicker #preferredContactDate="ngbDatepicker">
<div class="input-group-append">
//Open time picker here
<button class="btn btn-secondary" (click)="open()"
type="button"></button>
</div>
</div>
</div>
<div class="modal-footer">
<!-- Submit button -->
<input class="btn btn-dark" type="submit" value="Create" />
<button type="button" class="btn btn-dark" (click)="modal.dismiss('Cross click')">Cancel</button>
</div>
</form>
</div>
</ng-template>
However, when i do this, the time picker gets blocked by the modal.
Any ideas?
Stackbliz for timepicker - https://stackblitz.com/edit/amazing-timepicker-example
Referenced to: https://www.npmjs.com/package/amazing-time-picker
Modal: https://ng-bootstrap.github.io/#/components/modal/examples
Update based on answer:
<div class="time-picker">
<input atp-time-picker value="19:00"/>
</div>
CSS
.time-picker {
position:absolute;
z-index : 99999999;
}
.my-custom-class{
z-index: 900;
}
I also tried inline style as well
<input style= "z-index: 99999999;" atp-time-picker value="19:00"/>
We need to get the bootstrap's z-index dynamically and increment it with some arbitrary number and set to the time-picket something like below:
$(document).on('show.bs.modal', '.modal', function (event) {
const zIndex = 1045 + (10 * $('.modal:visible').length);
// this zIndex can be assigned to the time-picker
$(this).css('z-index', zIndex);
setTimeout(function () {
$('.modal-backdrop').not('.modal-stack').css('z-index', zIndex - 1).addClass('modal-stack');
}, 0);
});
you can specify a custom class for the modal to overwrite the z-index.
example:
in your js/ts:
this.modalService.open(content, {backdropClass: 'my-custom-class'});
css:
.my-custom-class{
z-index: 900;
}
Your issue is similar to the one mentioned here : https://github.com/owsolutions/amazing-time-picker/issues/129
The proposed solution, as think win win explained, was to increase the timepicker's z-index :
time-picker {
position:absolute;
z-index : 99999999;
}

How to Implement Drag and Drop for a bootstrap modal dialog.. So user can drag a file from the windows explorer

How to Implement Drag and Drop for a bootstrap modal dialog.. So user can drag a file from the windows explorer.
At Present there is an EDIT button and if Click on that Edit button a modal dialog will open and in that I ahve to implement DRag and DRop.So that user can drag a file from the windows explorer.
#Input() isUploadImage: boolean;
#Output() openImageUploadModal = new EventEmitter();
onUploadBtnClick(){
this.openImageUploadModal.emit('Open');
}
openImageUploadModal(content) {
this.modalService.open(content, { centered: true });
}
// fileChangeEvent(event: any): void {
// this.imageChangedEvent = event;
// }
imageCropped(event: ImageCroppedEvent) {
if (event.base64.indexOf('data:image/jpeg;base64,') > -1) {
this.croppedImage = event.base64.split('data:image/jpeg;base64,')[1];
} else {
this.croppedImage = event.base64.split('data:image/png;base64,')[1];
}
}
imageLoaded() {
this.cropperReady = true;
}
loadImageFailed() {
}
saveCroppedImage() {
this.imagePath = this.croppedImage;
this.myprofile.Photo = this.editPhoto === this.croppedImage ? this.editPhoto : this.croppedImage;
console.log('this.createNewProfile: ', this.createNewProfile);
this.advisorbranding.saveUpdateBrand(this.myprofile, this.createNewProfile).
subscribe(() => {
console.log('Profile Image updated..');
}, (err) => {
console.log('save Api failed, err: ', err);
});
}
deletPhoto() {
this.editPhoto = ProfileImageData.defaultImage;
// this.croppedImage = this.editPhoto;
// this.saveCroppedImage();
}
<div class="outer-div-for-the-imgae-icon">
<app-image [imagesrc]="imagePath" [isUploadImage]="true" (openImageUploadModal)="openImageUploadModal(content)" style="width : 38%; margin-top: 30px;"
class="d-none d-sm-block" alt="..." ></app-image>
</div>
<div class="upload-icon" *ngIf="isUploadImage" (click)="onUploadBtnClick()" >
<i class="fa fa-pencil fa-lg img-upload-icon" aria-hidden="true"> EDIT</i>
</div>
<input #inputFile id="filereader" type="file" (change)="onFileChange($event)" style="visibility: hidden;" />
<ng-template #content let-modal >
<div class="modal-header">
<h4 class="modal-title">Edit Photo</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" id="image-upload-modal">
<image-cropper
[imageBase64]="'data:image/png;base64,' + editPhoto"
[maintainAspectRatio]="true"
[aspectRatio]="4 / 3"
[resizeToWidth]="128"
[roundCropper]="false"
format="png"
outputType="both"
(imageCropped)="imageCropped($event)"
(imageLoaded)="imageLoaded()"
(loadImageFailed)="loadImageFailed()"
style="max-height: 33vh"
[style.display]="cropperReady ? null : 'none'"
></image-cropper>
<h6 style="color: white;font-size: 10px;text-align: center; position: relative;
top: 10px;">Drag a reposition photo</h6>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light button" (click)="deletPhoto();">DELETE PHOTO</button>
<button type="button" class="btn btn-light buttonbg" (click)="inputFile.click();">UPLOAD NEW</button>
<button type="button" class="btn btn-light" (click)="modal.close('Close click'); saveCroppedImage();">SAVE PHOTO</button>
</div>
</ng-template>

How to hide bootstrap modal form after submitting values, using Angular2 in vs2017

I want to know, how to hide below shown Bootstrap modal form, after submitting the value to the service. I have tried with commented code, but didn't help me. Is there any alternatives.?
settings.component.ts
import { Component, OnInit} from '#angular/core';
import { CategoryVM } from '../view-models/category';
import { AppDataService } from '../services/app-data.service';
import { NgForm } from '#angular/forms';
import { FormControl, FormGroup, Validators } from '#angular/forms';
import { Location } from '#angular/common';
//declare var $: any;
#Component({
selector: 'app-settings',
templateUrl: './settings.component.html',
styleUrls: ['./settings.component.css']
})
export class SettingsComponent implements OnInit {
categories: CategoryVM[] = [];
form: FormGroup;
errorMessage: string;
//visible: boolean;
//private visibleAnimate = false;
// public visible = true;
constructor(private dataService: AppDataService, private location: Location) {
dataService.getCountries().subscribe((data) => this.categories = data);
}
ngOnInit() {
this.dataService.vm = { ParentId: 0, Name: "" };
// this.visible = true;
}
onBack() {
this.errorMessage = null;
this.location.back();
}
onCancel() {
this.onBack();
}
onSubmit(form: NgForm) {
this.dataService.createCategory(form.value)
.subscribe(data => {
alert("Value Added Successfully");
//$("#myModal").hide();
//$("#myModal").modal("hide");
// this.visible = false;
this.categories.push(data);
//document.getElementById("openModalButton").click();
});
}
}
Please focus in OnSubmit() event of form in above and Below is the template
settings.component.html
<button type="button" class="btn btn-info btn-lg" data-toggle="modal" data-target="#myModal">start here</button>
<!--<button id="openModalButton" [hidden]="true" type="button" class="btn btn-info btn-lg" data-toggle="modal" data-target="#myModal">start here</button>-->
<div id="myModal" class="modal fade" role="dialog">
<!--<div id="myModal" class="modal fade" role="dialog" *ngIf="visible">-->
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Login</h4>
</div>
<div class="modal-body">
<form class="cat-form" #categoryForm="ngForm" (ngSubmit)="onSubmit(categoryForm)">
<!--<form class="cat-form" #categoryForm="ngForm" (ngSubmit)="onSubmit(categoryForm);visible=false;">-->
<label>Name</label>
<div class="form-group">
<input class="form-control" name="Name" placeholder="Name" #Name="ngModel" [(ngModel)]="dataService.vm.Name">
</div>
<div class="form-row">
<div class="form-group col-md-8">
<button type="submit" class="btn btn-lg btn-block btn-primary">Create</button>
</div>
<div class="form-group col-md-4">
<button type="button" class="btn btn-lg btn-block" (click)="onCancel()" data-dismiss="modal">Cancel</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
If I use commented line of code Modal-form will hide, but opacity remains as shown in this image
Your commented code is a jQuery code, so I assume you don't use an Angular Framework (like ng-bootstrap for example).
You should have a look and integrate one of the abstraction of Bootstrap.
Use jQuery in your component means you manipulate directly the dom and this is really not the good way to do.
https://ng-bootstrap.github.io/
https://github.com/valor-software/ngx-bootstrap

Angular2 Bootstrap modal user inputs + image

I am using a bootstrap model to create and update groups. on the backend side, there are no issues. Below I have my ts and HTML code I used. the modal works fine, but I don't know how to return any values from my form to my ts file so i can use it in an API call.
also for an image I need formdata
in short:
What's the issue: Returning user inputs(+image) in angular 2
!edit! the error i get is:
_co.save is not a function
html:
<app-modal #modal>
<div class="app-modal-header">
header
</div>
<div class="app-modal-body">
<form #modalform="ngForm" (ngSubmit)="save(modalform.value)" >
First name: <input type="text" name="FirstName" ngModel><br>
Last name: <input type="text" name="LastName" ngModel><br>
image: <input type="file" name="image" ngModel><br>
</form>
</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" (click)="modal.hide()">Save changes</button>
</div>
</app-modal>
TS:
#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}" style=" background: rgba(0,0,0,0.6);">
<div class="modal-dialog" style="padding-top: 25%;">
<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 save(): void{
}
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();
}
}
}
fixed it by placing the save function in the other component

OnChange Typescript input

I want to be able to trigger an on change when a file is selected from a input(file). I want the triggered event to set a textbox to be the name of the file.
I am using HTML5, Typescript and Angular2. I can't figure out or find an example of exactly how to produce the behavior I am after.
see my code below:
component.ts
import { Component } from '#angular/core';
import { Http } from '#angular/http';
import { Headers, RequestOptions } from '#angular/http';
#Component({
selector: 'testConnection',
// ignore error on require
template: require('./testConnection.component.html')
})
export class TestConnectionComponent {
public http: Http;
public requestData: RequestData;
public constructor(http: Http) {
this.http = http;
(<HTMLInputElement>document.getElementById('fileInput')).onchange = (ev: Event) => {
var fileInput = (<HTMLInputElement>ev.srcElement).files[0];
var fileTextbox = (<HTMLInputElement>document.getElementById('fileTextbox'));
fileTextbox.value = fileInput.name;
}
}
public testButtonClick() {
// Iniatialise Request object
let request: RequestData;
request = { "CountryCode": "", "SiteIDList": "" };
// Get site(s)
var siteIdList = (<HTMLInputElement>document.getElementById('siteIDInput')).value;
// Get selected country
var countryCode = (<HTMLInputElement>document.getElementById('countryDropdown')).value;
// Veryify contents is just site ids.
// TODO
request.CountryCode = countryCode;
request.SiteIDList = siteIdList;
// Set Http POST options
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
// Call Api with test connection data
this.http
.post('/api/TestConnection/TestConnection', JSON.stringify(request), options)
.subscribe(data => {
// alert request ok
alert('ok');
}, error => {
// Log error
console.log(error.json());
});
}
}
interface RequestData {
SiteIDList: string;
CountryCode: string;
}
component.html
<h2>Test Site Connection</h2>
<p>This will allow you to check the connectivity of a set of sites by either individually or uploading a CSV file of Site IDs.</p>
<br />
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Manual Test</h3>
</div>
<div class="panel-body">
<p>
Select the country and the sites you want to test.
</p>
<ul>
<li>Multiple sites can be selected using commas (,).</li>
<li>you can see results in the Site Connection Results tab</li>
</ul>
<br />
<!--Replace with lookup to enabled countries-->
<div class="form-group col-lg-4">
<div class="col-lg-6">
<select class="form-control" id="countryDropdown">
<option>Select Country</option>
<option>US</option>
<option>SG</option>
<option>NL</option>
</select>
</div>
</div>
<div>
<div class="col-lg-4">
<input type="text" class="form-control" placeholder="SiteID(s)" id="siteIDInput" />
</div>
<button class="btn btn-primary" (click)="testButtonClick()">Test</button>
</div>
</div>
</div>
<div class="panel panel-success">
<div class="panel-heading">
<h3 class="panel-title">Upload file</h3>
</div>
<div class="panel-body">
<div>
<p>Upload a CSV file of sites to test all at once.</p>
<br />
<div class="col-lg-4">
<input type="text" class="col-lg-4 form-control" id="fileTextbox" disabled/>
</div>
<label class="btn btn-primary">
Browse <input type="file" id="fileInput" style="display:none;" onchange="{ setFileName() }"/>
</label>
<button class="btn btn-primary" (click)="searchButtonClick()">Test</button>
</div>
</div>
</div>
<div class="modal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Modal title</h4>
</div>
<div class="modal-body">
<p>One fine body…</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
Try using (change) event binding
<input type="file" id="fileInput" style="display:none;" (change)="setFileName()"/>
If you need to retrieve the file name before uploading it you can do it this way :
#Component({
selector: 'my-app',
template: `
<div>
<input type="file" (change)="onChange($event)"/>
</div>
<p>Filename : {{filename}}</p>
`,
providers: []
})
export class AppComponent {
filename: string;
constructor() { }
onChange(event) {
this.filename = event.srcElement.files[0].name;
}
}
Here is a working plunker