Home > Enterprise >  Edit only some fields
Edit only some fields

Time:11-30

First steps in Razor Pages with VS2022. Simple CRUD SQL based.

Everything OK with the "main" edit view. I can edit and change all using also the PageRemote.

I created a second EditNote page to change only one field but i'm unable to reach the goal.

My files:

Models\Customer.cs

namespace Test.Model
{
    public class Customer
    {
        public int CustomerID { get; set; }

        [BindProperty(SupportsGet = true)]
        [PageRemote(PageHandler = "CheckCode", HttpMethod = "get", ErrorMessage = "Code already exist")]
        public int Code { get; set; }

        [Required(ErrorMessage ="Mandatory")]
        [MaxLength(100)]
        public string Description { get; set; }

        [Display(Name = "Notes")]
        [MaxLength(300)]
        public string? Note { get; set; }

Pages\Customers\EditNote.cshtml

<form method="post">
            <div asp-validation-summary="ModelOnly" ></div>
            <input type="hidden" asp-for="Customer.CustomerID" />
            <h1> @Model.Customer.Code</h1>
            <div >
                <label asp-for="Customer.Note" ></label>
                <input asp-for="Customer.Note"  />
                <span asp-validation-for="Customer.Note" ></span>
            </div>

Pages\Customers\EditNote.cshtml.cs

public class EditModel : PageModel
    {
        private readonly Test.Data.TestContext _context;

        public EditModel(Test.Data.TestContext context)
        {
            _context = context;
        }

        [BindProperty]
        public Customer Customer { get; set; }

        public async Task<IActionResult> OnGetAsync(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            Customer = await _context.Customer.FirstOrDefaultAsync(m => m.CustomerID == id);

            if (Customer == null)
            {
                return NotFound();
            }
            return Page();
        }

        // To protect from overposting attacks, enable the specific properties you want to bind to.
        // For more details, see https://aka.ms/RazorPagesCRUD.
        public async Task<IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            _context.Attach(Customer).State = EntityState.Modified;

            try
            {
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!CustomerExists(Customer.CustomerID))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }

            return RedirectToPage("./Index");
        }

        private bool CustomerExists(int id)
        {
            return _context.Customer.Any(e => e.CustomerID == id);
        }

        //Only for test
      public JsonResult OnGetCheckCode(Customer Customer) { return new JsonResult(true); }
    }
}

Now, when i edit the record with this EditNote page, i see only Code as label and Notes as field (as expected) but when i change something in Note and try to Save, Model is Invalid e "looking inside" i see that the reasons is that Description is empty but mandatory as defined in the model. For sure i would avoid to send hidden value in the user page.

What i'm doing wrong and how i can fix this?

CodePudding user response:

In the EditModel page, you need to create a model that's better aligned with the form you're designing. That model would be a subset of the Customer model.

Like this:

public class CustomerNote
{
    public int CustomerID { get; set; }


    [Display(Name = "Notes")]
    [MaxLength(300)]
    public string? Note { get; set; }
}

In OnGetAsync, build the model using a Projection (Select):

public async Task<IActionResult> OnGetAsync(int? id)
{
    if (id == null)
    {
        return this.NotFound();
    }

    this.Customer = await this._context.Customer
        .Select(m => new CustomerNote
        {
            CustomerID = m.CustomerID,
            Note = m.Note
        })
        .FirstOrDefaultAsync(m => m.CustomerID == id);

    if (this.Customer == null)
    {
        return this.NotFound();
    }

    return this.Page();
}

Finally, in OnPostAsync, load the Customer entity by Id and update its properties with the CustomerNote model.

Something like this:

public async Task<IActionResult> OnPostAsync()
{
    if (!this.ModelState.IsValid)
    {
        return this.Page();
    }

    var customer = await this._context.Customer.SingleAsync(m => m.CustomerID == this.Customer.CustomerID);

    customer.Note = this.Customer.Note;

    try
    {
        await this._context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!this.CustomerExists(Customer.CustomerID))
        {
            return this.NotFound();
        }
        else
        {
            throw;
        }
    }

    return this.RedirectToPage("./Index");
}
  • Related