0

I am trying to dynamically add to a list property in my ViewModel using JavaScript. Whenever I submit my form, there are no items in the list in the post controller. I have tried to add to the list inside the JavaScript function using razor syntax like so:

@{
    Model.Contacts.Add(new Contact { ID = 1, FirstName = "Tester" })
}

Just to see if I could even get a item in the list. I've also done it at the top of the page to see if it was just because it was in JavaScript. However when I submitted the form the same thing happened, no items in the list. I don't know if I need to create an API in order to submit the data, but the Company property submits with data in it. I would like to be able to submit both properties without having to create an API. I don't know if there's a special razor syntax or class that I can use to achieve this. Please help! Thank you.

Create Company Page

ViewModel:

public class CompanyViewModel
    {
        public Company Company { get; set; }
        public List<Contact> Contacts { get; set; }

        public CompanyViewModel()
        {
            this.Contacts = new List<Contact>();
        }
    }

Controller:

        public IActionResult Create()
        {
            var vm = new CompanyViewModel();
            return View(vm);
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Create(CompanyViewModel companyView)
        {
            if (companyView.Company != null)
            {
                _context.Add(companyView.Company);
                if (companyView.Contacts != null)
                    _context.Contacts.AddRange(companyView.Contacts);
                await _context.SaveChangesAsync();
                return RedirectToAction(nameof(Index));
            }
            return View(companyView);
        }

View:

@model CheckbookRegister.Models.CompanyViewModel

@{
    ViewData["Title"] = "Create";
}

<h1>Create Company</h1>
<hr />
<form asp-action="Create">

    <!-- Omitted for brevity -->

    <div class="row justify-content-between">
        <h4 class="col mb-0 align-self-end">Contacts</h4>
        <div class="col-md-auto text-right mt-2">
            <a class="col btn btn-sm btn-outline-success px-4" id="add" href="#" onclick="addContact()">Add</a>
        </div>
    </div>
    <table class="table mt-2" id="contactsTable">
        <thead>
            <tr>
                <th><label asp-for="@Model.Contacts.First().FirstName" class="control-label"></label></th>
                <th><label asp-for="@Model.Contacts.First().LastName" class="control-label"></label></th>
                <th><label asp-for="@Model.Contacts.First().Email" class="control-label"></label></th>
                <th><label asp-for="@Model.Contacts.First().PhoneNumber" class="control-label"></label></th>
                <th><label asp-for="@Model.Contacts.First().WorkPhoneNumber" class="control-label"></label></th>
                <th></th>
            </tr>
        </thead>
        <tbody>
        </tbody>
    </table>
    <div class="form-group">
        <input type="submit" value="Create" class="btn btn-primary"/>
    </div>
</form>

@section Scripts{ 
    <script type="text/javascript">
        var count = 0;
        function addContact() {
            var table = document.querySelector("tbody");
            table.insertAdjacentHTML("beforeend", "<tr>" +
                "<td>" +
                "<input asp-for='Model.Contacts[" + count + "].FirstName' class='form-control'/>" +
                "<span asp-validation-for='Model.Contacts[" + count + "].FirstName' class='text-danger'></span >" +
                "</td>" +
                "<td>" +
                "<input asp-for='Model.Contacts[" + count + "].LastName' class='form-control'/>" +
                "<span asp-validation-for='Model.Contacts[" + count + "].LastName' class='text-danger'></span >" +
                "</td>" +
                "<td>" +
                "<input asp-for='Model.Contacts[" + count + "].Email' class='form-control'/>" +
                "<span asp-validation-for='Model.Contacts[" + count + "].Email' class='text-danger'></span >" +
                "</td>" +
                "<td>" +
                "<input asp-for='Model.Contacts[" + count + "].PhoneNumber' class='form-control'/>" +
                "<span asp-validation-for='Model.Contacts[" + count + "].PhoneNumber' class='text-danger'></span >" +
                "</td>" +
                "<td>" +
                "<input asp-for='Model.Contacts[" + count + "].WorkPhoneNumber' class='form-control'/>" +
                "<span asp-validation-for='Model.Contacts[" + count + "].WorkPhoneNumber' class='text-danger'></span >" +
                "</td>" +
                "<td>" +
                "<button type='button' class='btn btn-sm btn-outline-danger' onclick='deleteContact(this)'>Delete</button>" +
                "</td>" +
                "</tr>");
            count++;
        }
        function deleteContact(button) {
            button.closest("tr").remove();
        }
    </script>
}

1 Answers1

0

So to add contact one by one your view model should be contact and your form should look like this except instead of email password use your contact class properties.

<form asp-controller="Demo" asp-action="RegisterInput" method="post">
    Email:  <input asp-for="Email" /> <br />
    Password: <input asp-for="Password" /><br />
    <button type="submit">Register</button>
</form>

You controller should accept contact class as param. This will work for adding contact one by one.

For multiple contacts, use the same view model that you currently have with a list of contacts. Then use for each on that list In your view and then add the inputs for each contact property and it’s values.

When you have to add a new contact basically generate html for a new contact on click event of an add button via js.

Follow this question and you’ll be on the right track: How to add an item to a list in a ViewModel using Razor and .NET Core?

YankTHEcode
  • 634
  • 4
  • 8
  • It turns out its razor-pages. It generates the code for the webpage when you load it (I'm guessing) and then when I add a row through JavaScript, the asp attributes aren't being generated so the inputs don't have the correct IDs and attributes. I appreciate it, I wouldn't have been able to figure it out without that link. – LightBasileus Apr 30 '20 at 01:24
  • Yes that’s correct, So by JavaScript you don’t add the asp attributes. You add the generated html. Load the page, hit f12 for dev tools, copy the generated html and add that html via JavaScript event. – YankTHEcode Apr 30 '20 at 01:26