Как отправить форму несколько раз (asp.net стержневая бритва)

#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();
     }
 

После «Сохранения изменений» мне нужно было повторно загрузить данные просмотра для выпадающего списка «Подрядчик». Тогда это был просто вопрос очистки полей формы перед возвратом страницы.