I have a main page with a table that when a row is clicked on, it uses #Output to send out that row's data (I've already confirmed the data is being sent properly by using it in another place in the project). I then have a Bootstrap 4 modal that pops up when I click the button on the left below where it says "Data Point Information". What I need to do is take the data from the row that was clicked on, and populate the form inside the modal with it.
Main Page:
Modal:
HTML for the modal:
<div class="modal fade" id="myModal2" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog bodyWidth">
<div class="modal-content wide">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Update Data Point</h4>
</div>
<div class="modal-body">
<form class="form-inline" [formGroup]="updateForm" (ngSubmit)="submitForm(updateForm.value)">
<div class="row">
<div class="form-group" [ngClass]="{'has-error':!updateForm.controls['dataPoint'].valid && updateForm.controls['dataPoint'].touched}">
<label>Data Point:</label>
<input class="form-control special" type="text" [formControl]="updateForm.controls['dataPoint']">
</div>
<div class="form-group move" [ngClass]="{'has-error':!updateForm.controls['ICCP'].valid && updateForm.controls['ICCP'].touched}">
<label >ICCP:</label>
<input type="text" class="form-control special" [formControl]="updateForm.controls['ICCP']">
</div>
<div class="form-group" [ngClass]="{'has-error':!updateForm.controls['startDate'].valid && updateForm.controls['startDate'].touched}">
<label>Start Date:</label>
<input [value]="getDate('start')" class="form-control special" type="text" [formControl]="updateForm.controls['startDate']" style="margin-right: 4px;">
</div>
<div style="display:inline-block">
<ngb-datepicker id="special" *ngIf="startCheck;" [(ngModel)]="startDate" (ngModelChange)="showDatePick(0)" [ngModelOptions]="{standalone: true}"></ngb-datepicker>
</div>
<button type="button" class="btn icon-calendar closest" (click)="showDatePick(0)"></button>
<div class="form-group" [ngClass]="{'has-error':!updateForm.controls['endDate'].valid && updateForm.controls['endDate'].touched}">
<label >End Date:</label>
<input [value]="getDate('end')" class="form-control special" type="text" [formControl]="updateForm.controls['endDate']">
</div>
<div style="display:inline-block">
<ngb-datepicker id="special" *ngIf="endCheck;" [(ngModel)]="endDate" (ngModelChange)="showDatePick(1)" [ngModelOptions]="{standalone: true}"></ngb-datepicker>
</div>
<button type="button" class="btn icon-calendar closer" (click)="showDatePick(1)"></button>
</div>
</form>
</div>
<div class="modal-footer">
*All Fields Are Required. End Date must be after Start Date
<button type="submit" class="btn" [disabled]="!updateForm.valid" data-dismiss="modal">Update</button>
<button type="button" (click)="resetForm()" class="btn" data-dismiss="modal">Cancel</button>
</div>
</div>
</div>
</div>
Typescript for the modal:
#Component({
selector: 'update-validation',
styleUrls: ['../app.component.css'],
templateUrl: 'update.component.html',
providers: [DatePipe]
})
export class UpdateComponent {
#Input() receivedRow:DataTable;
public dt: NgbDateStruct;
public dt2: NgbDateStruct;
public startCheck: boolean = false;
public endCheck: boolean = false;
updateForm : FormGroup;
constructor(fb: FormBuilder, private datePipe: DatePipe){
this.updateForm = fb.group({
'dataPoint' : [DPS[0].tDataPoint, Validators.required],
'ICCP' : [DPS[0].tICCP, Validators.required],
'startDate' : [DPS[0].tStartDate, Validators.required],
'endDate' : [DPS[0].tEndDate, Validators.required]
}, {validator: this.endDateAfterOrEqualValidator})
}
resetForm(){
location.reload();
//this.updateForm.reset();
}
submitForm(value: any){
console.log(value);
}
public getDate(dateName: string) {
let workingDateName = dateName + 'Date';
let timestamp = this[workingDateName] != null ? new Date(this[workingDateName].year, this[workingDateName].month-1, this[workingDateName].day).getTime() : new Date().getTime();
this.updateForm.controls[dateName + 'Date'].setValue(this.datePipe.transform(timestamp, 'MM/dd/yyyy'));
}
public showDatePick(selector):void {
if(selector === 0) {
this.startCheck = !this.startCheck
} else {
this.endCheck = !this.endCheck;
}
}
endDateAfterOrEqualValidator(formGroup): any {
var startDateTimestamp, endDateTimestamp;
for(var controlName in formGroup.controls) {
if (controlName.indexOf("startDate") !== -1) {
startDateTimestamp = Date.parse(formGroup.controls[controlName].value);
}
if (controlName.indexOf("endDate") !== -1) {
endDateTimestamp = Date.parse(formGroup.controls[controlName].value);
}
}
return (endDateTimestamp < startDateTimestamp) ? { endDateLessThanStartDate: true } : null;
}
}
HTML from the main page that places modal there using it's selector (toSend is of type DataTable which is the data from the row I am sending from the main page's Typescript):
<update-validation [receivedRow]='toSend'></update-validation>
Since I'm using #Output and #Input, I'm not sure why receivedRow in my Typescript is undefined.
The reason is that when your component of modal initialized, there were not any receivedRow. You should control it with *ngIf directive and ngOnChange method like that;
//xyz is just any field on your parent component
//in html
<div *ngIf="xyz">
<update-validation [receivedRow]="xyz"></update-validation>
</div>
//in component of modal
ngOnChanges(){
if(receivedRow){
//do whatever you want
}
}
Related
This is the index file code:
public IList<Employee> Employee { get; set; }
public async Task OnGetAsync()
{
Employee = await _context.Employee.ToListAsync();
}
public JsonResult EmployeeList()
{
var data = _context.Employee.ToList();
return new JsonResult(data);
}
[HttpPost]
public JsonResult AddEmployee(Employee e)
{
var emp = new Employee()
{
Name = e.Name,
Age = e.Age,
Email = e.Email
};
_context.Employee.Add(emp);
_context.SaveChanges();
return new JsonResult("Success!!!");
}
Button to open Modal:
<button class="btn btn-info mb-3" id="btn1">Add Employee</button>
The Modal:
<!-- The Modal -->
<div class="modal Add-Emp">
<div class="modal-dialog">
<div class="modal-content">
<!-- Modal Header -->
<div class="modal-header">
<h4 class="modal-title">Add Employee</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<!-- Modal body -->
<div class="modal-body">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label>Name</label>
<input type="text" placeholder="Enter Name" class="form-control" id="Name" autocomplete="off"/>
</div>
<div class="form-group">
<label>Age</label>
<input type="text" placeholder="Enter Age" class="form-control" id="Age" autocomplete="off"/>
</div>
<div class="form-group">
<label>Email</label>
<input type="text" placeholder="Enter Email" class="form-control" id="Email" autocomplete="off"/>
</div>
</form>
</div>
<!-- Modal footer -->
<div class="modal-footer">
<button class="btn btn-primary" onclick="AddEmployee();">Save</button> I
<button class="btn btn-danger btn-default" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
The Js Code:
$("#btn1").click(function () {
$(".Add-Emp").modal("show")
})
function AddEmployee() { debugger
var objData = { Name: $("#Name").val(), Age: $("#Age").val(), Email: $("#Email").val() }
$.ajax({
url: "Pages/Employees/Index/AddEmployee",
type: "Post",
data: objData,
contentType: "application/xxx-www-form-url-encoded; charset=utf-8",
dataType: "json",
success: function () { alert("Data Saved"); },
error: function () { alert("Error!!!"); }
})
}
Modal opens on click But data does not get posted on clicking the save button it displays alert "Error!!!" defined in failure of ajax requestㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ
1.You maybe not familiar with Razor Pages, Razor pages uses OnGet and OnPost to deal with the Http Get and Post request. If you need another Get or Post method in current PageModel, you need define the method name like: OnGetHandlerName or OnPostHandlerName.
2.If your .cshtml.cs file located like: Pages/Employees/Index.cshtml.cs, the request url should be:/Employees/Index. If you set the handler in your PageModel, the request url should be:/Employees/Index?handler=xxx.
3.For how to use Ajax in Razor Pages, Razor Pages enable anti-forgery token validation by default, so you need add this token to header in ajax.
If you use form in Razor Pages, it will default generate an input with token. If not, you need add #Html.AntiForgeryToken() manually.
A whole working demo you could follow:
Page(Pages/Employees/Index.cshtml):
#page
#model IndexModel
<button class="btn btn-info mb-3" id="btn1">Add Employee</button>
<div class="modal Add-Emp">
<div class="modal-dialog">
<div class="modal-content">
<!-- Modal Header -->
<div class="modal-header">
<h4 class="modal-title">Add Employee</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<!-- Modal body -->
<div class="modal-body">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label>Name</label>
<input type="text" placeholder="Enter Name" class="form-control" id="Name" autocomplete="off" />
</div>
<div class="form-group">
<label>Age</label>
<input type="text" placeholder="Enter Age" class="form-control" id="Age" autocomplete="off" />
</div>
<div class="form-group">
<label>Email</label>
<input type="text" placeholder="Enter Email" class="form-control" id="Email" autocomplete="off" />
</div>
</form>
</div>
<!-- Modal footer -->
<div class="modal-footer">
<button class="btn btn-primary" onclick="AddEmployee();">Save</button> I
<button class="btn btn-danger btn-default" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
#section Scripts
{
<script>
$("#btn1").click(function () {
$(".Add-Emp").modal("show")
})
function AddEmployee() {
debugger
var objData = { Name: $("#Name").val(), Age: $("#Age").val(), Email: $("#Email").val() }
$.ajax({
url: "/Employees/Index?handler=AddEmployee",
type: "Post",
data: JSON.stringify(objData), //change here...
contentType: "application/json; charset=utf-8", //change here...
headers: {
RequestVerificationToken:
$('input:hidden[name="__RequestVerificationToken"]').val()
}, //add this....
dataType: "json",
success: function () { alert("Data Saved"); },
error: function () { alert("Error!!!"); }
})
}
</script>
}
Pages/Employees/Index.cshtml.cs:
public class IndexModel : PageModel
{
//...
public IList<Employee> Employee { get; set; }
public async Task OnGetAsync()
{
Employee = await _context.Employee.ToListAsync();
}
public JsonResult OnGetEmployeeList()
{
var data = _context.Employee.ToList();
return new JsonResult(data);
}
public JsonResult OnPostAddEmployee([FromBody]Employee e)
{
var emp = new Employee()
{
Name = e.Name,
Age = e.Age,
Email = e.Email
};
return new JsonResult("Success!!!");
}
}
I am trying to create a form in a NgbModal, I can open an initialize the form however when I press submit button, nothing happens.
Here is HTML code;
<ng-template #content let-c="close" let-d="dismiss">
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">Give your feedback</h4>
</div>
<form [formGroup]="addForm" (ngSubmit)="onSubmit()">
<div class="modal-body">
<div class="form-group">
<label>Title</label>
<input type="text" formControlName="title" class="form-control" [ngClass]="{ 'is-invalid': submitted && addForm.controls.title.errors }" />
<div *ngIf="submitted && addForm.controls.title.errors" class="invalid-feedback">
<div *ngIf=" addForm.controls.title.errors">* Title is required</div>
</div>
</div>
<div class="form-group">
<label>Comment</label>
<textarea type="text" rows="4" cols="50" formControlName="text" class="form-control" [ngClass]="{ 'is-invalid': submitted && addForm.controls.text.errors }"></textarea>
<div *ngIf="submitted && addForm.controls.text.errors" class="invalid-feedback">
<div *ngIf=" addForm.controls.text.errors">* Comment is required</div>
</div>
</div>
<div class="form-group">
<label>Rate</label><br>
<ngb-rating formControlName="rate" max="5" [starTemplate]="rate">
</ngb-rating>
</div>
</div>
<div class="modal-footer">
<button style="margin-left: 5px" type="submit" class="btn btn-success pull-right">Save</button>
<button type="button" class="btn btn-outline-danger pull-right" (click)="c('cancelled')">Cancel</button>
</div>
</form>
</ng-template>
<ng-template #rate let-fill="fill" let-index="index">
<span class="star" [class.filled]="fill === 100">★</span>
</ng-template>
<ng-template #rate let-fill="fill" let-index="index">
<span class="star" [class.filled]="fill === 100">★</span>
</ng-template>
<button *ngIf="authService.currentUserValue" type="button" style="height: 50px" (click)="open(content)" class="btn btn-outline-primary pull-right" data-toggle="modal">
give your feedback
</button>
My open button works fine and also I can close modal, but somehow save is not working. Additionally my onSubmit method is like;
onSubmit() {
this.submitted = true;
const data = {
productId:this.currentProduct.productId,
userId: this.authService.currentUserValue.userId,
title: this.addForm.controls.title.value,
text: this.addForm.controls.text.value,
rating: this.addForm.controls.rating.value,
};
this.loading = true;
this.commentService.addComment(data).subscribe(
data => {
this.success = true;
this.router.navigate(['/']);
},
error => {
this.error = error;
this.loading = false;
}
)
}
No error is thrown or no action happens, clicking is not working. How can I fix this?
Your component doesn't know which modal to close. You need to pass the NgbModal reference to the submission function.
<form [formGroup]="addForm" (ngSubmit)="onSubmit(content)">
'content' refers to the template reference of the modal.
onSubmit(modal: NgbModal) {
modal.dismiss(); // Add wherever you need
}
And just as a heads up, if you...
<form [formGroup]="addForm" (ngSubmit)="onSubmit()" #f="ngForm"> /* Last attribute added */
and then create add a ViewChild before the constructor...
#ViewChild('f') ngForm: NgForm;
you'll be able to access ngForm's submission status by this.ngForm.submitted rather then setting them yourself manually. Angular docs for NgForm
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
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
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