Dynamically Create Form Angular2 - forms

I have a table that contains form fields along with data type/length/etc. What I need to be able to do is generically generate a form from the data in my database. Then on form submit, serialize the form to JSON. I am relatively new to Angular2, so any advice on best practice would also be beneficial.
Essentially, something like this where all input's are generated on the fly:
<form #form="ngForm" (ngSubmit)="SaveRow(form)" novalidate>
<div class="modal-body form-horizontal">
<div class="form-group row" *ngFor="let column of GetColumns(true)">
<div class="col-lg-4 col-md-4 col-xs-12 text-right text-left-xs text-left-sm">
<label attr.for="{{column.Name}}" class="control-label">{{column.Name}}<span *ngIf="!column.Nullable">*</span>:</label>
</div>
<div class="col-lg-8 col-md-8 col-xs-12">
<input id="{{column.Name}}" name="{{column.Name}}" class="form-control" />
</div>
</div>
</div>
<div class="modal-footer">
<div class="text-left">
<button type="button" class="btn btn-danger" *ngIf="IsExisting()" (click)="DeleteRow()">Delete</button>
<span class="pull-right text-right">
<button class="btn btn-default" id="btnCancel" type="button" (click)="CancelAdd()">Cancel</button>
<input type="submit" class="btn btn-primary" value="Add Row" *ngIf="!IsExisting()" />
<input type="submit" class="btn btn-primary" value="Update Row" *ngIf="IsExisting()" />
</span>
</div>
</div>
</form>
In my .ts, I have this:
SaveRow(form) {
if (form.valid) {
var data = new FormData(form);
console.log("FORM: ");
console.log(form);
console.log("DATA: ");
console.log(data);
}
}
But I don't believe the input value pairs are showing in the form object that is being submitted.

Related

Why is the first row in an ASP.NET Core MVC table un-editable?

By far the weirdest problem encountered to date: I am populating a table using #foreach (var item in Model) and every row has an edit and delete button.
The edit button triggers a modal where the user can make changes and click the Save button to save any changes. It works perfectly on every row except the first row.
Let's say I have 2 records in the table with IDs 1 & 2. I can edit 2 but not 1 where 1 is on the first row of the table. If I delete 1 leaving only 2 (now obviously at the top), I can't edit that so it is not related to the data in the item but somehow related to the fact that it is the first item being loaded into the table.
The view is returning with an enormous URL which includes a __RequestVerificationToken and there is no POST action recorded in the network.
This is the code in the Index.cshtml which calls the modal:
<td style="text-align: center">
<a asp-action="Edit" data-bs-toggle="modal" data-bs-target=" #("#editNode-" + item.Id)">
<i class="fas fa-edit" ></i>
</a>
#await Html.PartialAsync("_EditNodePartialView", item)
</td>
This is the _EditNodePartialView markup and code:
#model UnidAdmin.Models.BundleNodeViewModel
<div class="modal fade" id="editNode-#Model.Id">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" style="color:darkorange">Edit Node #Model.Id Bundle #Model.BundleId</h5>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close" style="background-color:transparent; color:aquamarine; border-style:none">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<form asp-controller="Nodes" asp-action="Edit" asp-route-id="#Model.Id" asp-route-src="bndlnd" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="row pb-3">
<div class="col form-group text-start">
<label asp-for="Name" class="control-label text-start" style="color:darkorange">Node Name</label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="col form-group text-start">
<label asp-for="Comment" class="control-label text-start" style="color:darkorange"></label>
<input asp-for="Comment" class="form-control" />
<span asp-validation-for="Comment" class="text-danger"></span>
</div>
</div>
<div class="row pb-3">
<div class="col form-group form-check text-center">
<label class="form-check-label text-start" style="color:darkorange">
<input class="form-check-input" asp-for="IsTest" /> #Html.DisplayNameFor(model => model.IsTest)
</label>
</div>
<div class="col form-group form-check text-center">
<label class="form-check-label text-start" style="color:darkorange">
<input class="form-check-input" asp-for="IsLocked" /> #Html.DisplayNameFor(model => model.IsLocked)
</label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary" onclick="displayBusyIndicator()" data-bs-dismiss="modal">Save</button>
</div>
</form>
</div>
</div>
</div>
</div>
And this is the controller edit action method:
public async Task<IActionResult> Edit(int id, [FromForm]Node editnode, string src)
{
// Lots of code here //
return RedirectToAction(nameof(Index));
}
As I said, it hits the controller for every row except the first row, whatever the record.
Has anyone ever encountered anything like this and if so what was your solution?

Aspnet.Core MVC, how to bind a list of a group of inputs?

I am using aspnetcore mvc, dotnet version 6. I am trying to get inputs in a view. Code below i am trying to get buyer users and delivery users in a list. But i can't bind them in a list of model from controller.
Here is my codes:
public async Task<IActionResult> SendMainFlow(List<IFormFile> files, string[] DeliveryUsers, List<BuyerUsers> BuyersModel)
{
return BadRequest();
}
From the view:
<form class="col-12 col-md-6" method="POST" action="/WorkManagement/SendMainFlow" enctype="multipart/form-data">
<div class="">
<label>
Dosyalar:
</label>
<input type="file"
class=" col-12"
name="files"
multiple/>
</div>
<hr class="row " />
<div class="row m-1">
<label class="col-12 text-primary">
Satın alacak kişiler:
</label>
<div id="BuyerInputArea" class="col-lg-12">
<div class="inputBuyerRow first-input">
<div class="input-group mb-3">
<input type="text" name="BuyerUserName" class="form-control m-input col" placeholder="İsim" autocomplete="off">
<input type="text" name="BuyerUserLastName" class="form-control m-input col" placeholder="Soyisim" autocomplete="off">
<input type="text" name="BuyerUserMail" class="form-control m-input col" placeholder="E-Posta" autocomplete="off">
<div class="input-group-append">
<button id="removeBuyer" type="button" class="btn btn-danger">Kaldır</button>
</div>
</div>
</div>
<button id="addBuyer" type="button" class="btn btn-info">Kişi Ekle</button>
</div>
</div>
<hr class="row " />
<div class="row m-1">
<label class="col-12 text-primary">
Dağıtılacak kişiler:
</label>
<div id="DeliveryInputArea" class="col-lg-12">
<div id="DeliverySignerRow">
<div class="input-group mb-3">
<input type="text" name="DeliveryUserMail" class="form-control m-input col" placeholder="Mail" autocomplete="off">
<div class="input-group-append">
<button id="removeRow" type="button" class="btn btn-danger">Kaldır</button>
</div>
</div>
</div>
<div id="newRow"></div>
<button id="addDealer" type="button" class="btn btn-info">Kişi Ekle</button>
</div>
</div>
<div class="row m-2">
<button class="col-12 btn btn-info" type="submit">
İŞLEM BAŞLAT
</button>
</div>
</form>
I can get for one user of any type here. I mean a buyer or a delivry user. But i want to get a list of user. And also my code tries to add dynamicaly a #inputBuyerRow in #BuyerUserArea.
Don't confuse with code. Code is simple. I want to post my inputs with form tag. In Controller side, I want to take any type of users into a list. I did not show models because i think it is not neccessary. The main problem is how can i get #inputBuyerRow inputs in BuyerModel like a list of objects? #addBuyer button add more #inputBuyerRow element in code. There will be more users.
How can i do that. Must I do i input group or anything else? I did not find any example.
My constraints are:
I can't use Ajax Jquery or anything else like them. I must use form tag.
I must use list in controller side.
Edit: In controller, i tried to get inputs with an string array and model to find out how view send to me. So don't confuse also with this code. I was just trying. Nothing special.
Generally, in an MVC application, when submits the form, in the action method, it will get the data via the html element’s name attribute.
You can access form fields by its name from view to controller
In View
To transfer the string array, the elements should use the same name attribute. like this: name="DeliveryUserMail"
<div id="DeliveryInputArea" class="col-lg-12">
<div id="DeliverySignerRow">
<div class="input-group mb-3">
<input type="text" name="DeliveryUserMail" class="form-control m-input col" placeholder="Mail" autocomplete="off">
<input type="text" name="DeliveryUserMail" class="form-control m-input col" placeholder="Mail" autocomplete="off">
<div class="input-group-append">
<button id="removeRow" type="button" class="btn btn-danger">Kaldır</button>
</div>
</div>
</div>
To send the list of model, we should based on the list index to set the name attribute, like this: BuyersModel[0].BuyerUserName
<div class="input-group mb-3">
<input type="text" name="BuyersModel[0].BuyerUserName" class="form-control m-input col" placeholder="İsim" autocomplete="off">
<input type="text" name="BuyersModel[0].BuyerUserLastName" class="form-control m-input col" placeholder="Soyisim" autocomplete="off">
<input type="text" name="BuyersModel[0].BuyerUserMail" class="form-control m-input col" placeholder="E-Posta" autocomplete="off">
</div >
<div class="input-group mb-3">
<input type="text" name="BuyersModel[1].BuyerUserName" class="form-control m-input col" placeholder="İsim" autocomplete="off">
<input type="text" name="BuyersModel[1].BuyerUserLastName" class="form-control m-input col" placeholder="Soyisim" autocomplete="off">
<input type="text" name="BuyersModel[1].BuyerUserMail" class="form-control m-input col" placeholder="E-Posta" autocomplete="off">
</div >
In Controller
[HttpPost]
public ActionResult Create2(string[] DeliveryUserMail, List<BuyerUsers> BuyersModel)
{
//Access string, list here
}
The result is like this:

How to set a Razor Html.BeginForm within another Html.BeginForm

Description
I want to have two buttons to edit and delete an identity role. The edit button works but if I want to delete a role the site is reloading but nothing happens.
The post function will not be called. Is there another way to have a post form in another post form?
Code
<div class="row mb-3">
<div class="col-12">
<div class="card">
<div class="card-body">
<h4 class="card-title">Rollennamen bearbeiten</h4>
#using(Html.BeginForm("EditRole", "Administration", FormMethod.Post)) {
<div class="form-group row">
<label asp-for="EditRole.RoleName" class="col-sm-12 col-md-3"></label>
<div class="col-sm-12 col-md-9">
<input asp-for="EditRole.Id" type="hidden" value="#roles.Id" />
<input asp-for="EditRole.RoleName" class="form-control" value="#roles.Name" />
<span asp-validation-for="EditRole.RoleName" class="text-danger"></span>
</div>
</div>
<div class="d-flex flex-row-reverse">
<button type="submit" class="btn btn-success">Rolle bearbeiten</button>
#using(Html.BeginForm("DeleteRole", "Administration", FormMethod.Post)) {
<input name="id" type="hidden" value="#roles.Id" />
<button type="submit" class="btn btn-danger mr-2">Rolle löschen</button>
}
</div>
}
</div>
</div>
</div>
</div>
You could handle multiple submit in one form use asp-action like
#using (Html.BeginForm(FormMethod.Post))
{
<div class="d-flex flex-row-reverse">
<input type="submit" value="Save" class="btn btn-success" asp-controller="Administration" asp-action="EditRole" />
<input type="submit" value="Delete" class="btn btn-danger" asp-controller="Administration" asp-action="DeleteRole" />
</div>
}

How to access to RESTController through a controller?

I am using Spring.
The method in my RESTController is this,
http://localhost:8080/delivery-api/training/submit. It is able to save hard code values into database.
This is part of my html form, it can be open up using this URL: http://localhost:8080/delivery-web/training/apply.
<form th:object="${applyForm}" class="form-horizontal" role="form" method="post" action="http://localhost:8080/delivery-api/training/submit" >
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right"
for="form-field-1" > Country </label>
<div class="col-sm-9">
<input type="text" id="form-field-1" placeholder="Country"
class="col-xs-10 col-sm-7" th:field="*{country}" />
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right"
for="form-field-1"> Fee </label>
<div class="col-sm-9">
<input type="text" id="form-field-1" th:field="*{Fee}" class="col-xs-10 col-sm-7" />
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right"
for="form-field-1"> Start Date </label>
<div class="col-sm-9">
<input type="date" id="form-field-1" th:field="*{startDate}"
class="col-xs-10 col-sm-7" />
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right"
for="form-field-1">End Date </label>
<div class="col-sm-9">
<input type="date" id="form-field-1" th:field="*{endDate}"
class="col-xs-10 col-sm-7" />
</div>
</div>
<br> <br>
<button class="btn btn-info" type="submit">
<i class="ace-icon fa fa-check bigger-110"></i> Submit
</button>
</div>
</div>
</form>
When I click on submit, it can be directed to http://localhost:8080/delivery-api/training/submit and insert the hard coded values into database, but it did not direct to my application-form.html page after that.
My controller
#PostMapping(value = "/apply")
public String apply(#Valid #ModelAttribute("applyForm") DeliveryApplicationForm applyForm, BindingResult errors, Model model) {
model.addAttribute("applyForm", applyForm);
return VIEW_PATH + "application-form";
}
I would like to render html page and also pass data from my form to RESTController method through a controller after I click on the submit button in my html page.
May I know how I can do it?

Angular error:Form submission canceled because the form is not connected

What I am trying to do is -
I am trying to add a form to the existing form but the data not getting stored
what the error coming up -
in the console its showing form connection is missing.. how can I connect it with following code I have?
The code behind the click is something like this:
<button type="submit" class="btn btn-default" routerLink="../viewemployee" [disabled]="empForm.invalid">Add Employee</button>
please refer the link below for the code.. need help to move on from this to solve other tasks.
If it is required to post the code here as well, I will do.Please answer and respond.
Thanx in advance.
How to connect the form in angular routing
createemployee.component.html
<h2>Add Employee:</h2>
<form class="form-horizontal" #empForm="ngForm">
<div class="form-group">
<label class="control-label col-sm-2" for="name">Name:</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="name" minlength="4" maxlength="10" pattern="^[A-Za-z0-9]*[A-Za-z0-9][A-Za-z0-9]\S*$" [(ngModel)]="model.name" placeholder="Enter Your Name"
#name="ngModel" required/>
<div *ngIf="name.invalid && (name.dirty || name.touched)" class="alert alert-danger">
<div *ngIf="name.errors.required">
Name is required.
</div>
<div *ngIf="name.errors.pattern">
No Spaces
</div>
<div *ngIf="name.errors.minlength">
Name must be at least 4 characters long.
</div>
</div>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="position">Position:</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="position" minlength="4" maxlength="10" pattern="^[a-z]*$" [(ngModel)]="model.position" placeholder="Enter your position"
#position="ngModel" required />
<div *ngIf="position.invalid && (position.dirty || position.touched)" class="alert alert-danger">
<div *ngIf="position.errors.required">
Position is required.
</div>
<div *ngIf="position.errors.pattern">
Only Alphabets are must be entered
</div>
<div *ngIf="position.errors.minlength">
Position must be at least 4 characters long.
</div>
</div>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="salary">Salary:</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="salary" pattern="[0-9]*"
minlength="5" maxlength="7" [(ngModel)]="model.salary" placeholder="Enter Salary" #salary="ngModel" required />
<div *ngIf="salary.invalid && (salary.dirty || salary.touched)" class="alert alert-danger">
<div *ngIf="salary.errors.required">
Salary is required.
</div>
<div *ngIf="salary.errors.minlength">
Salary must be in 5 numbers.
</div>
<div *ngIf="salary.errors.maxlength">
Salary must not be exceeded morethan 7 numbers.
</div>
<div *ngIf="salary.errors?.pattern">Only numebers should be typed
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default" routerLink="../viewemployee" [disabled]="empForm.invalid">Add Employee</button>
<button type="button" class="btn btn-default" routerLink="../home">Cancel</button>
</div>
</div>
</form>
You could change your component as follows:
Add event handler to the form:
<form (ngSubmit)="continue()">
Handle the routing in code:
continue() {
...
this.router.navigateByUrl("../viewemployee");
}
You need to inject the router:
constructor(private router: Router) {}