Функция выполняется, и я не знаю почему
Я новичок в Blazor, и у меня проблема, которую я не понимаю.
Я написал простое тестовое приложение, в котором я могу создавать контакты, статьи и счета. Это работает. В счете-фактуре я могу создавать позиции счета-фактуры, открыв модальное окно и выбрав некоторые статьи, которые затем получат новые позиции счета-фактуры.
Теперь у меня две проблемы / вопросы:
- Когда я удаляю последний элемент строки счета-фактуры, он работает, но когда я удаляю не последний элемент, функция
SaveInvoice
выполняется. - Если я помещу код модального окна внутрь
<Editform>
- помечает функциюSaveInvoice
также выполняется. Если я поставлю модальный за пределы<Editform>
теги он работает так, как ожидалось, но я хочу, чтобы он был внутри формы.
Почему этот код выполняется без явного вызова? Я предполагаю, что есть какой-то неявный вызов, но я не понимаю, откуда он.
Вы можете мне помочь или намекнуть? Или вам нужна дополнительная информация?
Код для вызова бланка счета:
@page "/invoice/edit/{rechnungID:int}"
@inject NavigationManager navMan
@inject IJSRuntime js
@inject IInvoiceRepository invoiceRepository
@inject IArticleRepository articleRepository
<h3>Rechnung bearbeiten</h3>
<FormInvoice ButtonText="Aktualisieren" Artikel="@Artikel" Rechnung="@Rechnung" Positionen="@Positionen" OnValidSubmit="@SaveInvoice" EditMode="true" OnCancel="@Cancel" OnRemoveItem="@RemoveItem" />
@code {
[Parameter] public int rechnungID { get; set; }
Rechnung Rechnung = new Rechnung();
List<Rechnungsposition> Positionen { get; set; } = new List<Rechnungsposition>();
List<Artikel> Artikel { get; set; } = new List<Artikel>();
protected async override Task OnInitializedAsync()
{
Rechnung = await invoiceRepository.GetInvoiceByID(rechnungID);
Positionen = Rechnung.Positionen;
Artikel = await articleRepository.GetArticles();
}
async Task SaveInvoice() // This gets executed and i dont know why
{
await invoiceRepository.UpdateInvoice(Rechnung);
await js.InvokeVoidAsync("alert", $"Erfolgreich aktualisiert!");
navMan.NavigateTo("invoice");
}
void Cancel() => navMan.NavigateTo("invoice");
private void RemoveItem(Rechnungsposition pos)
{
Positionen.Remove(pos);
}
}
Код формы счета-фактуры:
@inject IModalService Modal
@inject IArticleRepository articleRepository
@inject IInvoiceRepository invoiceRepository
@inject IInvoiceLineItemRepository itemsRepository
<EditForm Model="@Rechnung" OnValidSubmit="@OnValidSubmit">
<DataAnnotationsValidator />
<div class="form-group row">
<label class="col-sm-1 col-form-label" for="inputReNr">Rechnungsnr:</label>
<div class="col-sm-2">
@if (EditMode)
{
<InputText id="inputReNr" class="form-control-plaintext" @bind-Value="@Rechnung.RechnungsNr" readonly />
}
else
{
<InputText id="inputReNr" class="form-control" @bind-Value="@Rechnung.RechnungsNr" />
@*<ValidationMessage For="@(() => Rechnung.RechnungsNr)" />*@
}
</div>
<label class="col-sm-1 col-form-label" for="inputReDatum">Datum:</label>
<div class="col-sm-2">
<InputDate id="inputReDatum" class="form-control" @bind-Value="@Rechnung.RechnungsDatum" />
<ValidationMessage For="@(() => Rechnung.RechnungsDatum)" />
</div>
</div>
<div class="form-group row">
<label class="col-sm-1 col-form-label" for="inputAdresse">Adresse:</label>
<div class="col-sm-5">
<InputTextArea id="inputAdresse" class="form-control" @bind-Value="@Rechnung.Adresse" />
<ValidationMessage For="@(() => Rechnung.Adresse)" />
</div>
</div>
<SelectedInvoiceLineItems Positionen="@Positionen" OnRemoveItem=@RemoveItem />
<div class="form-group row">
<label>Nettosumme</label>
<label>@Rechnung.NettoSumme</label>
</div>
<div class="form-group row">
<label>zzgl USt</label>
<label>@Rechnung.UStSumme</label>
</div>
<div class="form-group row">
<label>Bruttosumme</label>
<label>@Rechnung.BruttoSumme</label>
</div>
</EditForm>
@*When the modal is here the SaveInvoice-function is not exceuted, but when i place it inside <EditForm> it gets executed*@
@if (EditMode)
{
<button @onclick="ShowModal" class="bg-gray-100 hover:bg-blue-200 text-gray-800 font-semibold py-2 px-4 border border-gray-400 rounded shadow">Neue Position</button>
}
<div class="form-group row">
<button class="btn btn-success mr-2" @onclick="@OnValidSubmit">
@ButtonText
</button>
<button class="btn btn-secondary" @onclick="@OnCancel">Abbrechen</button>
</div>
@code {
int RechnungID { get; set; }
[Parameter] public Kontakt Kontakt { get; set; }
[Parameter] public Rechnung Rechnung { get; set; }
[Parameter] public List<Artikel> Artikel { get; set; } = new List<Artikel>();
[Parameter] public List<Rechnungsposition> Positionen { get; set; } = new List<Rechnungsposition>();
[Parameter] public string ButtonText { get; set; } = "Speichern";
[Parameter] public EventCallback OnValidSubmit { get; set; }
[Parameter] public EventCallback OnCancel { get; set; }
[Parameter] public EventCallback<Rechnungsposition> OnRemoveItem { get; set; }
[Parameter] public bool EditMode { get; set; }
protected override void OnInitialized()
{
if (!EditMode)
{
Rechnung = new Rechnung();
}
else
{
RechnungID = Rechnung.ID;
}
}
protected override void OnParametersSet()
{
if (!EditMode)
{
Rechnung.Adresse = Kontakt.Name;
Rechnung.KontaktID = Kontakt.ID;
Rechnung.IstBezahlt = false;
}
}
async Task ShowModal()
{
var parameters = new ModalParameters();
parameters.Add(nameof(SelectArticle.Artikel), Artikel);
parameters.Add(nameof(SelectArticle.RechnungID), Rechnung.ID);
parameters.Add(nameof(SelectArticle.Positionen), Positionen);
var options = new ModalOptions()
{
DisableBackgroundCancel = true,
HideCloseButton = true
};
var messageForm = Modal.Show<SelectArticle>("Artikel auswählen", parameters, options);
var result = await messageForm.Result;
if (result.Cancelled)
{
//Console.WriteLine("Modal was cancelled");
}
else
{
//Console.WriteLine($"Anzahl Positionen nach Modal: {Positionen.Count}");
}
}
private async Task RemoveItem(Rechnungsposition pos)
{
await OnRemoveItem.InvokeAsync(pos);
}
}
Код, который представляет позиции счета-фактуры и возможность удаления:
<div>
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>Bezeichnung</th>
<th>Anzahl</th>
<th>Stückpreis</th>
<th>Gesamtpreis</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var pos in Positionen)
{
<tr>
<td>@pos.ID</td>
<td>@pos.Bezeichnung</td>
<td>@pos.Anzahl</td>
<td>@pos.Stueckpreis</td>
<td>@pos.Gesamtpreis</td>
<td>
<a class="btn btn-success" href="/invoicelineitem/edit/@pos.ID">Bearbeiten</a>
<button class="btn btn-danger" @onclick="@(() => RemoveItem(pos))">Löschen</button>
</td>
</tr>
}
</tbody>
</table>
</div>
@code {
[Parameter] public List<Rechnungsposition> Positionen { get; set; } = new List<Rechnungsposition>();
[Parameter] public EventCallback<Rechnungsposition> OnRemoveItem { get; set; }
private async Task RemoveItem(Rechnungsposition pos)
{
await OnRemoveItem.InvokeAsync(pos);
}
}
Код модального окна:
@if (Artikel == null)
{
<text>Lade Daten...</text>
}
else if (Artikel.Count == 0)
{
<text>Keine Daten gefunden.</text>
}
else
{
<table class="table table-sm table-hover table-bordered">
<thead>
<tr>
<th scope="col"></th>
<th scope="col">Bezeichnung</th>
<th scope="col">Einheit</th>
<th scope="col">Stückkosten</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
@foreach (Artikel art in Artikel)
{
<tr>
<td scope="row"><Input type="checkbox" @onchange="eventArgs => { ArtikelClicked(art, eventArgs.Value); }" /></td>
<td scope="row">@art.Bezeichnung</td>
<td scope="row">@art.Einheit</td>
<td scope="row">@art.Stueckkosten</td>
</tr>
}
</tbody>
</table>
<button @onclick="@Anlegen" class="btn btn-primary">Anlegen</button>
<button @onclick="@Cancel" class="btn btn-secondary">Abbrechen</button>
}
@code
{
[CascadingParameter] BlazoredModalInstance BlazoredModal { get; set; }
[Parameter] public List<Artikel> Artikel { get; set; }
[Parameter] public int RechnungID { get; set; }
private List<Artikel> ArtikelAuswahl = new List<Artikel>();
[Parameter] public List<Rechnungsposition> Positionen { get; set; }
void ArtikelClicked(Artikel artikel, object checkedValue)
{
if ((bool)checkedValue)
{
if (!ArtikelAuswahl.Contains(artikel))
{
ArtikelAuswahl.Add(artikel);
}
}
else
{
if (ArtikelAuswahl.Contains(artikel))
{
ArtikelAuswahl.Remove(artikel);
}
}
}
void Anlegen()
{
Rechnungsposition position;
for (int i = 0; i < ArtikelAuswahl.Count; i++)
{
position = new Rechnungsposition();
position.ID = 0;
position.RechnungID = RechnungID;
position.ArtikelID = ArtikelAuswahl[i].ID;
position.Anzahl = 1;
position.Beschreibung = ArtikelAuswahl[i].Beschreibung;
position.Bezeichnung = ArtikelAuswahl[i].Bezeichnung;
position.Einheit = ArtikelAuswahl[i].Einheit;
position.Stueckpreis = ArtikelAuswahl[i].Stueckkosten;
position.Gesamtpreis = ArtikelAuswahl[i].Stueckkosten;
Positionen.Add(position);
}
BlazoredModal.Close(ModalResult.Ok(true));
}
void Cancel()
{
Console.WriteLine("Cancel");
BlazoredModal.Cancel();
}
}
1 ответ
Сделайте тип кнопки простой "кнопкой", по умолчанию обычно используется "отправить".
<button type="button" @onclick="ShowModal" ...>Neue Position</button>
Из w3schools
Совет: всегда указывайте атрибут типа для элемента. Различные браузеры могут использовать разные типы по умолчанию для элемента.