Passing data to a modal in Blazor - html

Is there some way to transfer multiple data from one page to a modal using Razor syntax? Example I have a table with several columns and rows. In one of the columns there is a button that you can use to edit the data. I want the data from this line to be transfered over into the modal so that I can edit it.

One possibility is to do everything in a single page: the grid and the dialog. (This dialog is certainly a div).
#page "/{Langue}/OrderList"
<div class="content">
<div class="container">
<Components.Grid
Id="grid-order-list"
ListViewRecords = "new List<int> { 20, 50, 100 }"/>
</div>
</div>
#if (LineDetails != null)
{
<!-- Modal Large -->
<div class="modal fade" id="large-modal">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><i class="fa fa-times"></i></button>
<h6 class="modal-title">#ModalTitle</h6>
</div>
<div class="modal-body text-center">
<div class="modal-body-inside" style="height: 85vh; overflow-y: auto; padding: 60px 50px 70px;">
<UserControls.LineDetail Source="LineDetails " />
</div>
</div>
</div>
</div>
</div>
<!-- /.modal -->
}
#code {
private MyNameSpace.LineDetailsClass LineDetails;
}
As you can see, as long as LineDetails is null, the user see only the table. When clicking on the details button, you have to populate LineDetails. So the modal will be shown. LineDetails should be binded to somme textboxes, ... When the user clicks on a button in the modal, you get the needed info in LineDetails and you reset it to null.

Suppose that your class name is Person, It is your Button code :
foreach(var item in Items)
{
...
<td><button type="button" #onclick="#Update(item)">Edit</button></td>
...
}
Now we have a model for the Selected Item like this :
#code{
Person SelectedItem {get;set;}
void Update(Person selectedItem)
{
SelectedItem = selectedItem;
}
Now you can access you SelectedItem everywhere include modals.

Guy, Henk and Ali all have the right idea. I'd like to add, though, that you can add #onclick to almost ANYTHING-- a div, a table row, etc.
The general pattern is to have a List<SomeClass> AllItems, then a single SomeClass SelectedItem, then a null check.
YourModalControl.razor
<div>Show something from SelectedItem: #SelectedItem.DisplayString</div>
<button #onclick="CloseMe">Close</button>
#code{
[Parameter]
public SomeClass SelectedItem {get; set;}
[Parameter]
public EventCallback<SomeClass> SelectedItemChanged{get; set;}
async Task CloseMe(){
SelectedItem = null;
SelectedItemChanged.InvokeAsync(SelectedItem);
}
}
ConsumingPage.razor
#if (SelectedItem is not null){
<YourModalDisplayControl #bind-SelectedItem="SelectedItem" />
}
#else foreach (var item in AllItems){
<div #onclick="()=> SelectedItem = item">#item.DisplayString</div>
}
#code {
List <SomeClass> AllItems {get; set;}
SomeClass SelectedItem {get; set;}
}

Related

razor-pages Delete functional doesn't work, how to delete?

I'm currently learning RazorPages in codeacademy.com.
I did everything that was shown in the video Tutorial, and unfortunately is doesn't work:
The task for the project:
"Data Delete
The current project has a button on the Index page list that deletes the current Continent or Country. The button will be modified to call a discrete Delete.cshtml page. This page will display the current record for review and provide a Delete button. Once the deletion occurs, the user is redirected back to the list so they get visual feedback of a successful task.
The code and markup are easily copied from the existing Detail.cshtml page. After copying that page, we add a delete button and copy the necessary statements from the OnPostAsync() method in the Index.cshtml.cs page."
The Delete page was created. The problem is:
When I press button Delete on the Delete page I have redirection to this link in browser:
https://localhost/Continents/Delete/SA?Continent.ID=SA
Actually no Delete happends
No redirection
What mistakes maybe here?
The code Delete.cshtml:
#page "{id}"
#model DeleteModel
#{
ViewData["Title"] = "Continent Delete";
}
<div class="jumbotron p-3">
<div class="d-flex align-items-center">
<h1 class="display-4 flex-grow-1">
Continent Delete
</h1>
<a class="btn btn-primary btn-sm" asp-page="./Index">
Back to List
</a>
</div>
</div>
[enter image description here](https://i.stack.imgur.com/tFnrX.jpg)
<div class="d-flex">
<div class="p-2 bg-primary text-white text-right" style="flex:0 0 15%">
#Html.DisplayNameFor(model => model.Continent.ID)
</div>
<div class="p-2 border-top border-right border-bottom border-primary" style="flex:1 0 auto">
#Html.DisplayFor(model => model.Continent.ID)
</div>
</div>
<div class="d-flex">
<div class="p-2 bg-primary text-white text-right" style="flex:0 0 15%">
#Html.DisplayNameFor(model => model.Continent.Name)
</div>
<div class="p-2 border-right border-bottom border-primary" style="flex:1 0 auto">
#Html.DisplayFor(model => model.Continent.Name)
</div>
</div>
<form metod="post" class="d-flex flex-row-reverse mt-3">
<input type="hidden" asp-for="Continent.ID"/>
<input type="submit" value="Delete" class="btn btn-danger btn-sm"/>
</form>
Delete.cshtml.cs:
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorCountry.Models;
using RazorCountry.Data;
namespace RazorCountry.Pages.Continents
{
public class DeleteModel : PageModel
{
private readonly CountryContext _context;
public DeleteModel(CountryContext context)
{
_context = context;
}
public Continent Continent { get; set; }
public async Task<IActionResult> OnGetAsync(string id)
{
Continent = await _context.Continents
.Include(c => c.Countries)
.AsNoTracking()
.FirstOrDefaultAsync(m => m.ID == id);
if (Continent == null)
{
return NotFound();
}
return Page();
}
public async Task<IActionResult> OnPostAsync(string id)
{
if (id == null)
{
return NotFound();
}
// Find the continent
Continent Continent = await _context.Continents.FindAsync(id);
//Delete the continent
if (Continent != null)
{
_context.Continents.Remove(Continent);
}
//Persist Changes
await _context.SaveChangesAsync();
//Redirect to the user
return RedirectToPage("./Index");
}
}
}
Model Continent.cs:
using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
namespace RazorCountry.Models
{
public class Continent
{
[Required, StringLength(2, MinimumLength = 2), Display(Name = "Code")]
[RegularExpression(#"[A-Z]+", ErrorMessage = "Only upper case characters are allowed.")]
public string ID { get; set; }
[Required]
public string Name { get; set; }
public ICollection<Country> Countries { get; set; }
}
}
Try to understand how RazorPages functional works, try to fix mistake in a correct way
The reason that no error occurs is because your OnPostAsync method is not being hit. You have mis-spelled the method attribute in your form (you have metod) so submitting it generates the default GET request and your OnGetAsync handler is executed instead.
Once you have corrected that error, you still have an unresolved issue.
Your OnPostAsync handler expects a parameter named id. The hidden field tag helper in your form generates a parameter with a name of Continent.ID. Consequently the value will not be bound to the id parameter. The simplest solution is to do away with the tag helper in the form a the bottom of your Delete page and replace it with a plain HTML input with a name attribute:
<form method="post" class="d-flex flex-row-reverse mt-3">
<input type="hidden" name="id" value="#Continent.ID"/>
<input type="submit" value="Delete" class="btn btn-danger btn-sm"/>
</form>
You can read more about model binding in general here: https://www.learnrazorpages.com/razor-pages/model-binding
Thanks to #MikeBrind finally, I changed the code
<form method="post" class="d-flex flex-row-reverse mt-3">
<input type="hidden" name="id" value="#Model.Continent.ID"/>
<input type="submit" value="Delete" class="btn btn-danger btn-sm"/>
</form>
And it works!

Angular 13 - How to open form without button and the button click

My angular component has a tree and several nodes. When I double click on a node the click event runs a web api and retrieves data for an id that will be used to create a dynamic form using npm package: #rxweb/reactive-dynamic-forms. Once the data request is 'completed' a button appears and when clicked it opens the form with appropriate fields for the id selected. I would like to eliminate the need for this secondary button click. I've tried several suggestions but just cannot get anything to work.
I'm using Infragistics controls and bootstrap for the form.
html:
<div class="column-layout my-pane-layout">
<div *ngIf = "isShowFormButton" >
<button #open igxButton="raised" igxRipple="white" (click)="form.open()">Run</button>
<igx-dialog #form [closeOnOutsideSelect]="true" >
<igx-dialog-title>
<div class="dialog-container">
<igx-icon>vpn_key</igx-icon>
<div class="dialog-title">Form</div>
</div>
</igx-dialog-title>
<form class="input-group-form" [formGroup]="dynamicForm.formGroup" (ngSubmit)="onSubmit()">
<div class="container">
<div class="controls" viewMode="horizontal" [rxwebDynamicForm]="dynamicForm" [uiBindings]="uiBindings">
</div>
<button igxButton="raised" type="submit" igxRipple class="button" [disabled]="!dynamicForm.formGroup.valid">
<igx-icon>
directions_run
</igx-icon>
<span>Submit</span>
</button>
</div>
</form>
<div igxDialogActions>
<!-- <button igxButton (click)="form.close()">CANCEL</button> -->
<button igxButton (click)="form.close()">Submit</button>
</div>
</igx-dialog>
</div>
<h6 class="h6">
Levels
</h6>
<igx-tree #tree class="tree" selection="None" >
<igx-tree-node *ngFor="let level1 of myData" [data]="level1">
{{ level1.Name }}
<igx-tree-node *ngFor="let level2 of level1.levels" [data]="level2">
{{ level2.Name }}
<igx-tree-node *ngFor="let level3 of level2.levelplus" [data]="level3" (dblclick)="onDoubleClick($event,level3)">
{{level3.Name }}
</igx-tree-node>
</igx-tree-node>
</igx-tree-node>
</igx-tree>
</div>
XYZ.component.ts:
export class XYZComponent implements OnInit {
#ViewChild('form') dialog: IgxDialogComponent;
myData: any[];
public tree: IgxTreeComponent;
public selectedNode;
public ID: number = 2;
isShowRunButton: boolean = false;
public dynamicForm!: DynamicFormBuildConfig;
public dynamicFormConfiguration!: DynamicFormConfiguration;
constructor(private dynamicFormBuilder:RxDynamicFormBuilder){}
ngOnInit() {
populate tree with data here ...
}
public onDoubleClick(event,node) {
console.log(node);
event.stopPropagation();
this.runParameters(node.Id);
}
public runParameters(Id) {
this.aSer.getApi(Id).subscribe({next:(data: any[]) => {this.myData = data;},
error: err => {console.log(err); },
complete: () => {
this.dynamicForm =
this.dynamicFormBuilder.formGroup(this.myData,this.dynamicFormConfiguration);
this.isShowFormButton = true;
//this.dialog.open();
}
});
}
public onSubmit() {
console.log(this.dynamicForm.formGroup);
this.isShowFormButton= false;
//this.dialog.open();
}
}
If I uncomment out the 'this.dialog.open()' the code throws the following error:
TypeError: Cannot read properties of undefined (reading 'open')
Many postings say that I need to use a #ViewChild but it seems that it cannot find that reference : #ViewChild('form') dialog: IgxDialogComponent;
Any help would be much appreciated. Code works fine with the 'Run' button click but I want to eliminate that extra step.

Modal ajax.form validation ASP.NET MVC, error message not showing, modal not closing after succesful submit

i'm new to the ASP.net and i get easilly confused when jquery and Ajax get in the middle of a code.
I have a popup bootstrap Modal that show when i click on a button, the Modal contains an Ajax.form that allows me to create projects, i'm using HTML.validation to check if my form is filled correctly. I have two main problems :
When I enter valid informations in my form and i submit the form, the project is created succesfully but the Modal doesn't close automaticlly.
When i enter non-valid informations when i submit no message error apear, nonetheless when I close the modal and open it again, the errors apear.
I need your help to :
Close the modal once the submit form is valid.
Have the error message show in my modal form.
*This is a part of my main view :
enter code here
<!--validation script -->
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
<script src="~/Scripts/jquery.validate.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.js"></script>
<!-- Button trigger modal -->
<div>
<div>
<a class="btn btn-red ms-auto my-auto h-50"
href="#Url.Action("createProject", "ProjectSelection")" title="Nouveau projet"
data-bs-toggle="modal" data-bs-target="#Modal_NewProject"
ajax-target-id="Body_NewProject" data-bs-loader="Loader_NewProject">
<i class="feather-16" data-feather="plus"></i>
Créer projet
</a>
</div>
</div>
<br />
<!-- Modal View -->
<div class="modal fade" id="Modal_NewProject" tabindex="-1"
aria-labelledby="Label_NewProject" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="Label_NewProject">
Créer un Projet</h5>
<button type="button" class="btn-close"
data-bs-dismiss="modal" aria-label="Close"></button>
</div>
#using (Ajax.BeginForm("createProjectPost",
"ProjectSelection", new AjaxOptions { HttpMethod = "POST",
UpdateTargetId = "Body_NewProject" }, new { id = "projectForm" }))
{
<div id="Body_NewProject">
<div class="spinner-border" role="status"
id="Loader_NewProject">
<span class="visually-hidden">Loading...</span>
</div>
<!-- partial view "createProject" -->
</div>
}
</div>
</div>
</div>
<!---->
*And this is my partial view that containts the elements of the form
<div class="modal-body" id="frmProject">
<div class="input-group mb-3" id="">
#Html.DropDownListFor(m => m.Project.Domain,
new SelectList(Model.Domains, "IdDomain", "Name"),"Selectionner un domaine",
new { #class = "w-100", #id = "DomainSelection" })
#Html.ValidationMessageFor(m => m.Project.Domain, null,
new { style = "color: red;" })
</div>
<div class="input-group mb-3 mb-3 " id="teamSelection">
#Html.DropDownListFor(m => m.Project.Teams,
new SelectList(Model.Teams.Select(teamElement => teamElement.Name).ToList()),
"Selectionner une équipe", new { #class = "w-100" })
#Html.ValidationMessageFor(m => m.Project.Teams, null,
new { style = "color: red;" })
</div>
<div class="form-floating mb-3">
<input class="form-control " data-val-required="Le champ Projet est requis."
id="Project.Name" name="Project.Name" type="text" value="">
<label for="Project.Name" class="">Nom du projet</label>
#Html.ValidationMessageFor(m => m.Project.Name, null,
new { style = "color: red;" })
</div>
</div>
<div class="modal-footer mb-0">
<div class="panel-footer">
<button class="btn btn-secondary" data-bs-dismiss="modal"
type="button">Annuler</button>
<button type="submit" form="projectForm"
class="btn btn-red">Valider</button>
<div class="col-xs-10" id="lblstatus"></div>
</div>
</div>
*This is my Controller code
public ActionResult createProject()
{
//initialization code
return PartialView();
}
[HttpPost]
[ValidateAntiForgeryToken]
[HandleError]
public ActionResult createProjectPost(Project project)
{
#region Variable verification
if (!ModelState.IsValid)
{
Session["Error"] = true;
if (project.Domain == null)
{
Session["DomainError"] = true;
}
if (project.Teams == null)
{
Session["TeamError"] = true;
}
if (project.Name == null)
{
Session["NameError"] = true;
}
ViewData["project"] = "create";
//return View("ProjectSelectionPage");
return PartialView(project);
}
#endregion
#region Initialisation
//initilization code
#endregion
#region Check possible copy of the project
if (projectDB.Exist(project.Name))
{
//Check that this project doesn't exist in the database
//Create a session variable that will trigger an error message
Session["Error"] = true;
Session["NameCopy"] = true;
ViewData["project"] = "create";
return PartialView(project);
}
#endregion
#region Project to database and generate name
//Add the project to the database
#endregion
return PartialView();
}
It's been several days since i'm searching for an answer, i either missed one or didn't use it correctly.
enter image description here
Thank you

How to target specific div with Blazor components?

I have a top-row div a follows:
<div class="top-row px-3">
<b>App:<i>Title</i></b>
<!-- wait for it ... -->
<div class="menu">
Menu Bar Here
</div>
</div>
I am going to have several MenuBar components that will swap out in the div class menu with a button click. How do I target that div with a Blazor component?
Update
I think I found a solution by Chris Sainty.
Edit
To clarify what I intend to accomplish:
I have 2 components:
<MenuBar1 />
<MenuBar2 />
Both contain different html to construct a simple menu bar. I have navigational links that, when clicked, will raise the onClick event.
How, when the link is clicked, can I swap out the MenuBar components?
Blazor doesn't use Javascript strategy.
To do that you have to mix HTML with code.
<div class="top-row px-3">
<b>App:<i>Title</i></b>
<!-- wait for it ... -->
<div class="menu">
#if (Version == "v1")
{
<p>version 1</p>
}
else if (Version == "v2")
{
<p>version 2</p>
}
</div>
</div>
For dynamic menu add a file in shared folder.
The file name = the class name
For example MenuButton.razor
#inject NavigationManager navManager
<button #onclick="(e)=>navManager.NavigateTo(route)">#(label)</button>
#code {
[Parameter]
public string label { get; set; }
[Parameter]
public string route { get; set; }
}
To consume this componant
<div class="top-row px-3">
<b>App:<i>Title</i></b>
<!-- wait for it ... -->
<div class="menu">
<MenuButton label="Choice 1" route="/route1" />
<MenuButton label="Choice 2" route="/route2" />
</div>
</div>

Show or Hide Prev and next buttons based on first div and last div in angular2

I have a requirement where i want to hide or show prev and next buttons based on div tag. Basically i am creating div tags for each value of list using ngfor loop in angular2.
List I have used
appUlist:string[] = ["Calculus-1","Geometry-1","Algebra-1","Trignometry-1","Statstics-1","Arithmetic-1"]
Now i am creating a div tag for each value in the list using ngFor in html. Since there are more than 5 values in the list, i have used next and prev button so that i can see other div tags as soon as i click on next button. This part works pretty well. but i want hide prev button if i am showing the first div tag and hide next button if there are no further div tags.
Please advice me on this
Below i have posted both html and ts code
export class AppComponent{
#ViewChild('panel', { read: ElementRef }) public panel: ElementRef<any>;
public selectedDiv;
public u;
title = 'app';
name:string = 'Creating new screen for student';
public appUlist:string[] = ["Calculus-1","Geometry-1","Algebra-1","Trignometry-1","Statstics-1","Arithmetic-1"]
}
//scrolls back when clicked on prev
public onPreviousSearchPosition(): void {
this.panel.nativeElement.scrollLeft -= 20
}
//scrolls forward when clicked on next button
public onNextSearchPosition(): void {
this.panel.nativeElement.scrollBy(20,0);
}
My html code
<div #panel class="row" style="width:700px;height:300px;overflow-x: scroll;overflow: hidden;" >
<div class="col-lg-1">
<i class="fa fa-angle-double-left" style="font-size:36px;color:#1092B0" id="left" (click)="onPreviousSearchPosition()"></i>
</div>
<div class="col-lg-1 cardhover" *ngFor="let u of appUlist">
<h1>test</h1>
</div>
<div class="col-lg-1">
<i class="fa fa-angle-double-left" style="font-size:36px;color:#1092B0" id="right" (click)="onNextSearchPosition()"></i>
</div>
</div>
Below image represents the output of mycode
You can put a variable to 0 in your appComponent and increment/decrement it each time you click prev and next. If this variable is == 0 you don't show prev button, if it is equal to your list lenght - 3 you don't show the next button :
export class AppComponent{
#ViewChild('panel', { read: ElementRef }) public panel: ElementRef<any>;
public selectedDiv;
public u;
public index = 0;
title = 'app';
name:string = 'Creating new screen for student';
public appUlist:string[] = ["Calculus-1","Geometry-1","Algebra-1","Trignometry-1","Statstics-1","Arithmetic-1"]
}
//scrolls back when clicked on prev
public onPreviousSearchPosition(): void {
this.panel.nativeElement.scrollLeft -= 20
this.index--;
}
//scrolls forward when clicked on next button
public onNextSearchPosition(): void {
this.panel.nativeElement.scrollBy(20,0);
this.index++;
}
and
<div #panel class="row" style="width:700px;height:300px;overflow-x: scroll;overflow: hidden;" >
<div class="col-lg-1">
<i *ngIf="idx != 0" class="fa fa-angle-double-left" style="font-size:36px;color:#1092B0" id="left" (click)="onPreviousSearchPosition()"></i>
</div>
<div class="col-lg-1 cardhover" *ngFor="let u of appUlist">
<h1>test</h1>
</div>
<div class="col-lg-1">
<i *ngIf="idx < list.lenght - 3" class="fa fa-angle-double-left" style="font-size:36px;color:#1092B0" id="right" (click)="onNextSearchPosition()"></i>
</div>
</div>