This is a bit hard to explain without showing the full concept, but I will try. I have table of Employees in Record.razor.cs
- this.PersonellData
. I am adding new Employee into table by this method:
private void AddNew()
{
this.PersonellData.Add(new Personell
{
Id = i 1,
Name = "John " i,
From = DateTime.Today new TimeSpan(8, 30, 0),
Category = this.selectedCategoryValue,
});
this.DiaryRecord.Employees = new List<Personell>(this.PersonellData);
i ;
}
However after adding employee I would like to change category and (From) time in UI. I am able to do it in UI, but data is not changing in List<model>
itself. I set breakpoint at
private async Task OnCreateNewDiaryRecord()
{
if (true)
{
this.DiaryRecordModel = new DiaryRecord
{
Id = this.DiaryRecordModel.Id,
Title = this.DiaryRecordModel.Title,
Description = this.DiaryRecordModel.Description,
Employees = this.DiaryRecordModel.Employees,
Date = this.SelectedDate,
};
await OnInitializedAsync();
}
isDialogVisible = false;
}
in Index.razor.cs there are no changes I have done in UI to each employee in the list. Any suggestions how to get it working? Should I add methods like OnChange for each UI item, but how to proceed forward with updating actual list?
Here is DiaryRecord.cs:
public class DiaryRecord
{
public Guid Id { get; set; }
public string Title { get; set; }
public ICollection<Personell> Employees { get; set; }
}
Here is UI part of list items
<Table DataSource="this.PersonellData" RowClassName="@(_=>"editable-row")" Bordered [email protected]>
<Column Title="From" TData="DateTime">
<TimePicker TValue="DateTime?" @bind-Value="@context.From" OnChange="this.OnDateValueChanged" />
</Column>
<Column Title="Category" DataIndex="@nameof(context.Category)" TData="string">
<Select DataSource="@this.CategoryList"
@bind-Value="@this.selectedCategoryValue"
LabelName="@nameof(Category.CategorySymbol)"
ValueName="@nameof(Category.CategorySymbol)"
DefaultActiveFirstItem="false"
EnableSearch
OnSelectedItemChanged="this.OnSelectedCategoryChangedHandler">
</Select>
</Column>
</Table>
I have tried with OnChange="this.OnDateValueChanged"
, but don't know how to proceed forward.
CodePudding user response:
Don't call OnInitializedAsync() from your own code. And when you do it will not trigger a UI update.
//await OnInitializedAsync();
await InvokeAsync(StateHasChanged); // Invoke probably not needed. Just in case.
CodePudding user response:
I've seen your project. There are plenty of errors of code and design. I'm going to display below the code that somehow works. Copy and test it.
Index.razor
@page "/"
@using AntDesign
<h1>Hello, world!</h1>
Welcome to your new app.
<br />
<br />
<Space>
<SpaceItem>
<Button Type="button" OnClick="@(()=>{ this.isDialogVisible = true; })">
Add Record
</Button>
</SpaceItem>
</Space>
<Space>
<Button Type="button" OnClick="Success">
Success
</Button>
</Space>
<Record DiaryRecord="DiaryRecordModel"></Record>
<Modal Title="Create new record"
Style="width:50%"
Visible="@this.isDialogVisible"
Footer="null"
Draggable="@(true)"
OnCancel="(e)=>{this.isDialogVisible = false;}">
<Form Model="this.DiaryRecordModel"
OnFinish="(e) => this.OnCreateNewDiaryRecord()">
<FormItem>
<Record DiaryRecord=this.DiaryRecordModel />
</FormItem>
<FormItem WrapperColOffset="8" WrapperColSpan="16">
<Button Type="@ButtonType.Primary" HtmlType="submit">
Submit
</Button>
<Button OnClick="(e)=>{this.isDialogVisible = false;}">Cancel</Button>
</FormItem>
</Form>
</Modal>
Index.razor.cs
using AntDesign;
using BlazorAppAntDemo.Models;
using Microsoft.AspNetCore.Components;
using System;
using System.Threading.Tasks;
namespace BlazorAppAntDemo.Pages
{
public partial class Index
{
[Inject]
public MessageService Message { get; set; }
private DiaryRecord DiaryRecordModel { get; set; } = new DiaryRecord();
private bool isDialogVisible;
private DateTime SelectedDate { get; set; }
public Index()
{
this.DiaryRecordModel = new DiaryRecord();
this.DiaryRecordModel.Date = DateTime.Now;
}
protected override void OnInitialized()
{
}
private async Task OnCreateNewDiaryRecord()
{
if (true)
{
this.DiaryRecordModel = new DiaryRecord
{
Id = this.DiaryRecordModel.Id,
Title = this.DiaryRecordModel.Title,
Description = this.DiaryRecordModel.Description,
Employees = this.DiaryRecordModel.Employees,
Date = this.SelectedDate,
};
// await OnInitializedAsync();
await Task.Yield();
}
isDialogVisible = false;
}
private async Task Success()
{
await this.Message.Success("This is a success message");
}
}
}
record.razor
@page "/record"
@using BlazorAppAntDemo.Models
<Template>
<Collapse DefaultActiveKey="@(new[] { "1" })"
OnChange="this.Callback"
ExpandIconPosition="@this.ExpandIconPosition"
ExpandIcon="caret-right">
<Panel Header="Basic information" Key="1">
<Form Model="DiaryRecord">
<FormItem Label="Record title" NoStyle>
<Input @bind-Value="@this.DiaryRecord.Title" />
</FormItem>
<FormItem Label="Description" NoStyle>
<Input @bind-Value="@this.DiaryRecord.Description" />
</FormItem>
<FormItem Label="Date" NoStyle>
<DatePicker @bind-Value="@this.DiaryRecord.Date" ShowTime="@true" OnChange="this.OnDateSelected" />
</FormItem>
</Form>
</Panel>
<Panel Header="Personell" Key="2">
<ChildContent>
<Button OnClick="this.AddNew" Type="button" Style="margin-bottom:16px">
Add person
</Button>
<Table DataSource="this.PersonellData" RowClassName="@(_=>"editable-row")" Bordered [email protected]>
<Column Title="Id" DataIndex="@nameof(context.Id)" TData="int"></Column>
<Column Title="Name" DataIndex="@nameof(context.Name)" TData="string"></Column>
<Column Title="From" TData="DateTime">
<TimePicker TValue="DateTime?" @bind-Value="@context.From" OnChange="this.OnDateValueChanged" />
</Column>
<Column Title="Category" DataIndex="@nameof(context.Category)" TData="string">
<Select DataSource="@this.CategoryList"
@bind-Value="@this.selectedCategoryValue"
LabelName="@nameof(Category.CategorySymbol)"
ValueName="@nameof(Category.CategorySymbol)"
DefaultActiveFirstItem="false"
EnableSearch
OnSelectedItemChanged="this.OnSelectedCategoryChangedHandler">
</Select>
</Column>
<ActionColumn Title="Action">
<Popconfirm Title="Sure to delete?"
OnConfirm="()=> this.Delete(context.Id)"
OkText="Yes"
CancelText="No">
<Button Danger>Delete</Button>
</Popconfirm>
</ActionColumn>
</Table>
</ChildContent>
</Panel>
<Panel Header="Attachments" Key="3">
<ChildContent>
<span >
<label for="upload">
<div >
<div tabindex="0" style="position:relative;">
<InputFile OnChange="@this.OnFileSelection" multiple id="upload" hidden accept=".png,.jpg,.jpeg,.gif" />
<div >
@if (this.ImgUrls.Any())
{
@foreach (var url in this.ImgUrls)
{
<div>
<img src="@url" alt="avatar" style="width: 100%" />
</div>
}
}
else
{
<div>
<Icon Spin="this.loading" Type="@(this.loading?"Loading":"plus")"></Icon>
<div className="ant-upload-text">Upload</div>
</div>
}
</div>
</div>
</div>
</label>
</span>
</ChildContent>
</Panel>
<Panel Header="Another one 1" Key="4">
<ChildContent>
<h3>Hola</h3>
</ChildContent>
</Panel>
<Panel Header="Another one 2" Key="5">
<ChildContent>
<h3>Hola 2</h3>
</ChildContent>
</Panel>
<Panel Header="Another one 3" Key="6">
<ChildContent>
<h3>Hola 3</h3>
</ChildContent>
</Panel>
</Collapse>
</Template>
@code {
}
record.razor.cs
using AntDesign;
using BlazorAppAntDemo.Models;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.JSInterop;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace BlazorAppAntDemo.Pages
{
public partial class Record
{
[Inject] private MessageService Message { get; set; }
[Inject] private NotificationService Notice { get; set; }
private string ExpandIconPosition { get; set; }
private int i = 1;
private List<Category> CategoryList { get; set; }
private string selectedCategoryValue;
private IQueryable<Personell> PersonellData { get; set; }
private List<string> ImgUrls { get; set; }
private List<FileData> FileData { get; set; }
private string imageUrl;
private int maxFileSize;
private byte[] profilePictureByteArray;
private bool loading;
[Parameter] public DiaryRecord DiaryRecord { get; set; }
public Record()
{
this.ExpandIconPosition = "left";
this.PersonellData = new List<Personell>().AsQueryable();
this.CategoryList = new List<Category>();
this.ImgUrls = new List<string>();
this.FileData = new List<FileData>();
this.maxFileSize = 400000;
}
protected override void OnInitialized()
{
this.CategoryList.Add(new Category { CategoryName = "CategoryA", CategorySymbol = "A" });
this.CategoryList.Add(new Category { CategoryName = "CategoryB", CategorySymbol = "B" });
this.CategoryList.Add(new Category { CategoryName = "CategoryC", CategorySymbol = "C" });
this.CategoryList.Add(new Category { CategoryName = "CategoryD", CategorySymbol = "D" });
}
private void AddNew()
{
this.PersonellData.Append(new Personell
{
Id = i 1,
Name = "John " i,
From = DateTime.Today new TimeSpan(7, 30, 0),
Category = this.selectedCategoryValue,
});
this.DiaryRecord.Employees = new List<Personell>(this.PersonellData);
i ;
}
private void Delete(int id)
{
this.PersonellData = this.PersonellData.Where(d => d.Id != id);
}
private void OnSelectedCategoryChangedHandler(Category value)
{
this.selectedCategoryValue = value.CategoryName;
}
private void OnDateValueChanged()
{
}
private void OnDateSelected(DateTimeChangedEventArgs args)
{
this.DiaryRecord.Date = args.Date;
}
private void Callback(string[] keys)
{
}
private async Task OnFileSelection(InputFileChangeEventArgs e)
{
foreach (IBrowserFile file in e.GetMultipleFiles(this.maxFileSize))
{
if (file.Size < this.maxFileSize)
{
IBrowserFile imgFile = file;
this.profilePictureByteArray = new byte[imgFile.Size];
await imgFile.OpenReadStream().ReadAsync(profilePictureByteArray);
string imageType = imgFile.ContentType;
this.imageUrl = $"data:{imageType};base64,{Convert.ToBase64String(profilePictureByteArray)}";
this.ImgUrls.Add(imageUrl);
this.FileData.Add(new FileData
{
Data = profilePictureByteArray,
FileType = imageType,
Size = imgFile.Size
});
}
else
{
await Message.Error("File is too large!", 5);
await this.Notice.Open(new NotificationConfig()
{
Message = "title",
Duration = 0,
Description = "File is too large!"
});
}
}
}
}
}
You should also add <AntContainer />
, perhaps at the top of the App component (App.razor)
Note: I ran your code in Net5.0 in which you must tell the compiler that a given type is nullable individually. As I didn't want to waste my time, I removed the nullability. If you have some issues related to this let me know. My code works, but is not complete