Home > Blockchain >  C# MVC View - How Do I Display A 3 Choice Enum As A Checkbox to Select Between The First 2 Choices?
C# MVC View - How Do I Display A 3 Choice Enum As A Checkbox to Select Between The First 2 Choices?

Time:06-09

This is an odd problem. I'm making a .Net MVC app that contains a Bitcoin wallet. The problem is that I changed an "IsTestNet" boolean in my "Profile" Model to a 3 choice enum to include "MainNet," "TestNet," and "RegTest" options for the Bitcoin network. I am writing tests for the app so I had to add a "RegTest" network to do testing. The end user using the app should never interact with the RegTest network option so I only need the View to interact with the MainNet and TestNet options for the Bitcoin Network.

The profile creation view looks like this:
enter image description here

This is what the code for the view looks like (Notice I haven't swapped "IsTestNet" for "NetworkMod"):

@model Profile

@{
    ViewData["Title"] = "Profiles";
    bool isEdit = Model != null && Model.Id != Guid.Empty;
}

<h2>
    @(isEdit ? $"Edit profile - {Model.Name}" : "Create profile")
</h2>

<div asp-validation-summary="All" ></div>

<form asp-action="Save">
    @if (isEdit)
    {
        <input type="hidden" asp-for="Id" />
    }

    <div >
        <label asp-for="Name">Profile name</label>
        <input  asp-for="Name" />
    </div>

    <div >
        <input  asp-for="IsTestNet">
        <label  asp-for="IsTestNet">Is TestNet</label>
    </div>

    <button type="submit" >Save</button>
</form>

This is the relevant code for the Profile Controller (Notice I haven't swapped "IsTestNet" for "NetworkMod"):

[HttpPost]
public IActionResult Save(Profile profile)
{
    if (!ModelState.IsValid)
    {
        return View(nameof(Create));
    }

    const string profileExistsError = "A profile with this name already exists. Choose a new name.";

    var userId = _manager.GetUserId(User);

    Func<bool> containsProfileName = () => _db.Profiles.Any(p => p.UserId == userId && p.Name == profile.Name);

    using (var transaction = _db.Database.BeginTransaction())
    {
        if (profile.Id != Guid.Empty)
        {
            var prof = _db.Profiles
                .FirstOrDefault(p => p.UserId == userId && p.Id == profile.Id);

            if (profile is null)
            {
                return NotFound();
            }

            // double check that we don't have any profiles with this name first
            if (prof.Name != profile.Name && containsProfileName())
            {
                ModelState.AddModelError("Name", profileExistsError);
                return View(nameof(Create), profile);
            }

            prof.Name = profile.Name;
            prof.IsTestNet = profile.IsTestNet;

            _db.Profiles.Update(prof);
        }
        else
        {
            // double check that we don't have any profiles with this name first
            if (containsProfileName())
            {
                ModelState.AddModelError("Name", profileExistsError);
                return View(nameof(Create), profile);
            }

            var address = new Address
            {
                ProfileId = profile.Id,
                Send = BitcoinHelper.CreatePrivateKey(profile.IsTestNet)
            };

            var picnicKeys = BitcoinHelper.GeneratePicnicKeys();

            profile.UserId = userId;
            profile.PublicKey = picnicKeys.PublicKey;
            profile.PrivateKey = picnicKeys.PrivateKey;

            profile.Addresses = new[] { address };

            _db.Profiles.Add(profile);
        }

        _db.SaveChanges();
        transaction.Commit();
    }

    return RedirectToAction("Index");
}

This is the NEW Profile Model (Notice there is no "IsTestNet" bool because I replaced it with "NetworkMod")

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using amaranth.Models.ViewModels;
using Microsoft.AspNetCore.Identity;

namespace amaranth.Models
{
    public class Profile
    {
        public Guid Id { get; set; }
        public string UserId { get; set; }
        [Required]
        public string Name { get; set; }
        public NetworkMod NetworkMod { get; set; }
        public string PrivateKey { get; set; }
        public string PublicKey { get; set; }

        public virtual IdentityUser User { get; set; }
        public virtual IEnumerable<Record> Records { get; set; }
        public virtual IEnumerable<Address> Addresses { get; set; }

        public Address GetCurrentAddress() => Addresses?.FirstOrDefault(a => a.Receive is null);
    }
}

And this is the NetworkMod Model as referenced in the Profile Model:

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace amaranth.Models.ViewModels
{
    public enum NetworkMod {
        [Display(Name = "MainNet")]
        MainNet,
        [Display(Name = "TestNet")]
        TestNet,
        [Display(Name = "RegTest")]
        RegTest
    }
}

So ordinarily, I would change the checkbox for "Is TestNet" to a dropdown, but the user should never need to select "RegTest" so it's still just 2 options for the end user which is adequately defined by a checkbox. So how do I modify the view to make it pick between enum options 1 and 2 as a checkbox?

CodePudding user response:

So how do I modify the view to make it pick between enum options 1 and 2 as a checkbox?

One checkbox can only bind one value,so you need to use two checkboxes,here is a demo:

<div >
        <input type="checkbox" value="MainNet" name="NetworkMod" />
        <label>MainNet</label>
    </div>
    <div >
        <input type="checkbox" value="TestNet" name="NetworkMod" />
        <label>TestNet</label>
    </div>

js:

@section Scripts{ 
    <script>
        $('input[name="NetworkMod"]').on('change', function () {
            if ($(this).prop("checked")) {
                $('input[name="NetworkMod"]').not(this).prop('checked', false);
            }
            
        });
    </script>
}
  • Related