#forms #asp.net-core #razor-pages
#формы #asp.net-ядро #razor-страницы
Вопрос:
Я пытаюсь создать форму, которая может быть отправлена несколько раз с разной информацией, сохраняя при этом общее значение в одном поле.
У меня есть представление списка из таблицы SQL в ASP.NET Core Razor — это список строительных проектов. Для каждой строки в списке у меня есть ссылка, которая ведет на страницу шаблона «создать», где пользователи могут создать запись ставки для проекта, которая хранится в другой таблице. Номер проекта присваивается значению маршрута (asp-route-Number = «номер проекта из предыдущего списка«) и заполняет скрытое поле в форме «создать новую заявку».
Используя код по умолчанию для страницы razor, все работает отлично. Вы нажимаете отправить и возвращаетесь к списку проектов.
Что я хочу сделать, так это иметь другую опцию в форме «создать новую ставку», которая позволит вам сохранить и ввести другую ставку для того же проекта. Я создал еще одну кнопку и обработчик для этого, но я застрял на ее фактической реализации. Если я использую return Page(), форма публикует и страница возвращается с неповрежденными данными маршрута, но текстовые поля по-прежнему содержат предыдущие данные, а выпадающий список пуст. Если я использую return RedirectToPage (CreateNewBid, данные маршрута), форма публикует, но данные маршрута, похоже, не передаются и создает ошибку с нулевым значением.
Это ссылка из списка проектов (внутри таблицы foreach), которая приведет вас к форме «Создать заявку» и работает нормально.
<a asp-page="CreateBid" asp-route-Number="@item.ProjectNumber" asp-route-opwid="@item.Id">New Bid</a>
Форма создания заявки содержит следующее для отправки и создания другой записи
int num = int.Parse(Request.Query["Number"]);
int idnum = int.Parse(Request.Query["opwid"]);
<input type="submit" value="Save and enter another"
asp-page-handler="Another" asp-route-opwid="@idnum"
asp-route-Number="@num" class="btn btn-primary"/>
И обработчик:
public async Task<IActionResult> OnPostAnotherAsync(int Number, int opwid)
{
if (!ModelState.IsValid)
{
return Page();
}
_context.OpwBids.Add(OpwBids);
await _context.SaveChangesAsync();
return Page();
//return RedirectToPage("./CreateBid", (Number == num, opwid == idnum));
}
Я также попробовал несколько действий в параметрах маршрута (в отличие от использования переменных) в разделе «Перенаправление на страницу», и, похоже, ничего не работает.
Есть ли более простой способ, или я просто что-то упускаю?
Это файл cshtml:
@page
@model Authorization_AD.Pages.GenSvc.BidEntry.CreateBidModel
@{
ViewData["Title"] = "CreateBid";
}
@{ int num = int.Parse(Request.Query["Number"]);
int idnum = int.Parse(Request.Query["opwid"]);
}
<h1>Create Bid</h1>
<h4>OPW number @num</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<input asp-for="OpwBids.OpwProject" value="@idnum" hidden class="form-control" />
</div>
<div class="form-group">
<label asp-for="OpwBids.OpeningDate" class="control-label"></label>
<input asp-for="OpwBids.OpeningDate" class="form-control" />
<span asp-validation-for="OpwBids.OpeningDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="OpwBids.Contractor" class="control-label"></label>
<select asp-for="OpwBids.Contractor" class="form-control" asp-items="ViewBag.Contractor">
<option disabled selected>--- SELECT ---</option>
</select>
</div>
<div class="form-group">
<label asp-for="OpwBids.BidAmount" class="control-label"></label>
<input asp-for="OpwBids.BidAmount" class="form-control" />
<span asp-validation-for="OpwBids.BidAmount" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save and enter another"
asp-page-handler="Another" asp-route-opwid="@idnum"
asp-route-Number="@num" class="btn btn-primary"/>
<input type="submit" value="Save and return to list" asp-page-handler="Done" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Это файл C #:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Authorization_AD.Models;
namespace Authorization_AD.Pages.GenSvc.BidEntry
{
public class CreateBidModel : PageModel
{
private readonly Authorization_AD.Models.OPWContext _context;
public CreateBidModel(Authorization_AD.Models.OPWContext context)
{
_context = context;
}
public IActionResult OnGet()
{
ViewData["Contractor"] = new SelectList(_context.Contractors, "Id", "ContractorName");
ViewData["OpwProject"] = new SelectList(_context.MainProjectsListing, "Id", "ProjectNumber");
return Page();
}
[BindProperty]
public OpwBids OpwBids { get; set; }
public async Task<IActionResult> OnPostDoneAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.OpwBids.Add(OpwBids);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
public async Task<IActionResult> OnPostAnotherAsync(int Number, int opwid)
{
if (!ModelState.IsValid)
{
return Page();
}
_context.OpwBids.Add(OpwBids);
await _context.SaveChangesAsync();
return Page();
//return RedirectToPage("./CreateBid", (Number == OpwBids.OpwProjectNavigation.ProjectNumber, opwid == OpwBids.OpwProject));
}
}
}
Комментарии:
1. Можете ли вы рассказать о своих конкретных потребностях? Чего вам нужно достичь? Создать несколько идентификаторов OPWBID на странице создания?
2. Если вы можете, вы можете опубликовать код своей страницы создания.
3. То, что я хочу, это форма с двумя кнопками внизу. Один из них — «Сохранить и выйти», другой — «Сохранить и создать другой», который создает запись БД, перезагружает ту же форму и запоминает номер проекта, который предварительно заполнен в скрытом поле.
Ответ №1:
Вы можете добавить свойство на свою страницу, которое будет использоваться для привязки значения нажатой кнопки.
public class CreateBidModel : PageModel {
//...
//Add this property to your page.
[BindProperty]
public string Button {get;set;}
public void OnGet(int number,string opwid){
//Set the number and opwid to the target properties
}
public Task<IActionResult> OnPostAsync(){
if (!ModelState.IsValid)
{
return Page();
}
_context.OpwBids.Add(OpwBids);
await _context.SaveChangesAsync();
if(Button == "finish"){
return RedirectToPage("./Index");
}
else {
return RedirectToPage("./CreateBid", (Number == OpwBids.OpwProjectNavigation.ProjectNumber, opwid == OpwBids.OpwProject));
}
}
}
В представление вам нужно добавить две кнопки с одинаковыми именами, и это значение будет сопоставлено свойству Button .
<form method="post">
... Other content goes here
<button name="@Html.NameFor(m => m.Button)" value="another">Create another</button>
<button name="@Html.NameFor(m => m.Button)" value="finish">Finish</button>
</form>
Значение нажатой кнопки будет преобразовано в свойство Button модели страницы. На основе значения вы можете решить, как дальше обрабатывать ответ на запрос (завершить / создать другой в вашем случае).
Ответ №2:
Спасибо всем за помощь. Я заставил его делать то, что я хочу, добавив следующее в задачу «OnPostAnotherAsync»:
public async Task<IActionResult> OnPostAnotherAsync(int Number, int opwid)
{
if (!ModelState.IsValid)
{
return Page();
}
_context.OpwBids.Add(OpwBids);
await _context.SaveChangesAsync();
ViewData["Contractor"] = new SelectList(_context.Contractors, "Id", "ContractorName");
ModelState.SetModelValue("OpwBids.BidAmount", new ValueProviderResult(string.Empty, CultureInfo.InvariantCulture));
ModelState.SetModelValue("OpwBids.Contractor", new ValueProviderResult(string.Empty, CultureInfo.InvariantCulture));
return Page();
}
После «Сохранения изменений» мне нужно было повторно загрузить данные просмотра для выпадающего списка «Подрядчик». Тогда это был просто вопрос очистки полей формы перед возвратом страницы.