0

I am junior (or less than junior) in IT. I have a problem with passing data from view to controller... What I want to achieve: When user click:

<button type="submit" class="btn btn-primary">Dodaj kategorię</button>

I want pass whole object "Category" to controller (also with List Subcategory). Second button with id="addSubCategory" will add a field to enter the next subcategory, but I want to send everything after clicking the type = submit button. How can I pass all subcategories name to list and send one post method?


That is my View:

@model AplikacjaFryzjer_v2.Models.Category
@{
    ViewData["Title"] = "Dodaj nową kategorię";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h1>Dodaj nową kategorię</h1>


<form method="post">
    <div class="row">
        <div class="col-md-6">
            <div asp-validation-summary="All" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Name"></label>
                <input asp-for="Name" />
                <span asp-validation-for="Name" class="text-danger"></span>
            </div>
            <button type="submit" class="btn btn-primary">Dodaj kategorię</button>
        </div>
        <div class="col-md-6 offset-6">
            <div asp-validation-summary="All" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Subcategories"></label>
                <input asp-for="Subcategories" />
                <span asp-validation-for="Subcategories" class="text-danger"></span>
            </div>
            <button class="btn btn-primary" id="addSubCategory" value="table">Dodaj podkategorię</button>
        </div>
    </div>
</form>

My Action CreateCategory in controller:

        [HttpPost]
    public IActionResult CreateCategory(Category category)
    {
        _categoriesRepository.AddCategory(category);
        return RedirectToAction("ManageCategories");
    }

And my object (model):

    public class Category
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<Subcategory> Subcategories {get;set;}
}

1 Answer 1

1

For submitting complex models, you need to ensure that the name attribute of these controls bound to the Subcategory class fields are displayed in the form of a collection index.

And trigger the addSubCategory click event in js to add Subcategory control and data.

Since you added model validation, I suggest you use ViewBag.Subcategories to save the Subcategories data that has been added to the current page to prevent data loss after clicking the validation.

And you only need to add an asp-validation-summary in your form. Since these fields belong to a model and are in a form, their error information will be counted in the asp-validation-summary div.

Here is a complete example:

   public class Category
    {
        public int Id { get; set; }
        [Required] 
        public string Name { get; set; }
        public List<Subcategory> Subcategories { get; set; }
    }

    public class Subcategory
    { 
        [Required]
        [DisplayName("Subcategory.Name")]
        public string Name { get; set; }
    }

Controller:

public IActionResult CreateCategory()
        {
            ViewBag.Subcategories = new List<Subcategory>() { };
            return View();
        }

        [HttpPost]
        public IActionResult CreateCategory(Category category)
        {
            if (!ModelState.IsValid)
            {
                // store Subcategories data which has been added
                ViewBag.Subcategories = category.Subcategories == null ? new List<Subcategory>() { } : category.Subcategories;
                return View("CreateCategory");

            }
             _categoriesRepository.AddCategory(category);
            return RedirectToAction("ManageCategories");
        }

View:

@model AplikacjaFryzjer_v2.Models.Category
@{
    ViewData["Title"] = "Dodaj nową kategorię";
    Layout = "~/Views/Shared/_Layout.cshtml";

    var SubcategoriesData = (IList<AplikacjaFryzjer_v2.Models.Subcategory>)ViewBag.Subcategories;

}

<h1>Dodaj nową kategorię</h1>
<form method="post">
    <div class="row">
        <div class="col-md-6">
            <div class="form-group">
                <label asp-for="Name"></label>
                <input asp-for="Name" />
                <span asp-validation-for="Name" class="text-danger"></span>
            </div>
            <button type="submit" class="btn btn-primary">Dodaj kategorię</button>
        </div>
        <div class="col-md-6 offset-6">
            @for (int i = 0; i < SubcategoriesData.Count(); i++)
            {
                <div class="form-group">
                    <label>Name@(i)</label>
                    <input asp-for="Subcategories[i].Name" value="@SubcategoriesData[i].Name" />
                    <span asp-validation-for="Subcategories[i].Name" class="text-danger"></span>
                </div>
            }
            <button class="btn btn-primary" onclick="RemoveSubcategory(this)" id="removeSubcategory">remove</button>
            <button class="btn btn-primary" id="addSubCategory" value="table">Dodaj podkategorię</button>
        </div> 
        <div asp-validation-summary="All" class="text-danger"></div>
    </div>

</form>
@section Scripts
{
    <script>

     var i = @SubcategoriesData.Count()-1;
    $(document).ready(function () {
        if (@SubcategoriesData.Count() <= 0) {
            $("#removeSubcategory").hide();
        }

        $("#addSubCategory").click(function (e) {
            e.preventDefault();
            i++;
            var name = '<label>Name' + i + '</label><input name = "Subcategories[' + i + '].Name" type="text"/>'; 
            $("#removeSubcategory").before('<div class="form-group">' + name  + '</div>');
            $("#removeSubcategory").show();
        });


    });
    function RemoveSubcategory(btn) {
        event.preventDefault();
        $(btn).prev("div").remove();
        i--;
        if (i == @SubcategoriesData.Count() -1) {
            $("#removeSubcategory").hide();
        }
    }
    </script>
}

Here is test result:

enter image description here

Sign up to request clarification or add additional context in comments.

6 Comments

Ok, I will test that. But i have one question: I have my Category.cs and Subcategory.cs in Models folder. Do you think when I want to added for example "[Required] [DisplayName("Subcategory.Name")]" I need to create new classes in my ViewModels folder? with atributes?
@Krispekowy, In fact, these attributes are only used to demonstrate the verification information. The specific verification requirements are based on your needs. If you want the field in the database to be subject to the same restrictions, then you do not need to create a new viewmodel. If you just used to restrict user view input without affecting the database, then you can create a new viewmodel.
thx for information. Last question if I can - where I can change text validation showing on the screen?
@Krispekowy,do you mean to display different error messages when validation? If so, you can change it like : [Required(ErrorMessage ="Please enter your name!")]
I have added button "remove" to <div class="form-group"> and added JS: $("#container").on('click', '#removeSubcategory', function (e) { $(this).parent('div').remove(); }); But when i clicked button - page is reloading (post method is sending?) and checking validate. Why my button "remove" sending post?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.