ASP MVC Multiple Form

0

I have a model called Pregunta which contains a list of another model called Alternativa . I need that when creating a question, the user can select how many alternatives to add to that question and display a dynamic form according to the selected number. .

At first the form was simpler. The user created a question and then he had a maintainer of alternatives where to create an alternative he had to select the question, this was very cumbersome and impractical for the user, so I came up with this idea, without major results. I'm new to ASP MVC and I do not know how I could create a dynamic form to save two models.

    
asked by sioesi 04.06.2017 в 15:58
source

1 answer

2

The M that represents the Model in MVC can be used in different ways:

  • As a model of persistence. It would be the class that is defined in your context with the aim of saving in the BD
  • As a business model classes with methods that can then be called on your controller
  • As a representation model, it is a class that you define with the objective of being represented in your view, used to represent complex forms like the one you need.
  • In practice, the representation model is declared with the name ViewModel and it is a class that incorporates the attributes that you want depending on how complex your form is, to this class the rules of validation like the others. Let's take a simple example

    we have the Employee class

    public class Empleado
    {
        public int Id { get; set; }
        public string Nombre { get; set; }
        public string Apellido { get; set; }
        public int AreaId { get; set; }
        public virtual Area Area { get; set; }
    }
    

    and an Area class

    public class Area
    {
        public int Id { get; set; }
        public string Nombre { get; set; }
    
        public virtual ICollection<Empleado> Empleados { get; set; } 
    }
    

    and we want through a form to create an employee, an area and assign the employee the id of the created area. For this type of cases it is necessary to help from a ViewModel. In the root directory we create a folder called ViewModels and inside we add the class.

    public class EmpleadoAreaViewModel
    {
        public int Id { get; set; }
        [Required(ErrorMessage = "El campo Nombre es obligatorio")]
        public string Nombre { get; set; }
        [Required(ErrorMessage = "El campo Apellido es obligatorio")]
        public string Apellido { get; set; }
        [Required(ErrorMessage = "El campo Area es obligatorio")]
        public string NombreArea { get; set; }
    }
    

    If they are fixed to the employees and area classes, I did not apply them for validation because they are persistence classes I will only use them to save in the database, on the other hand, the model that I will use to build my form is EmployeeAreaViewModel which has validation.

    my form would look like this:

    @model WebApplication1.ViewModels.EmpleadoAreaViewModel
    
    @{
        ViewBag.Title = "Nuevo";
    }
    
    <h2>Nuevo</h2>
    
    
    @using (Html.BeginForm()) 
    {
        @Html.AntiForgeryToken()
    
        <div class="form-horizontal">
            <h4>EmpleadoAreaViewModel</h4>
            <hr />
            @Html.ValidationSummary(true)
    
            <div class="form-group">
                @Html.LabelFor(model => model.Nombre, new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.Nombre)
                    @Html.ValidationMessageFor(model => model.Nombre)
                </div>
            </div>
    
            <div class="form-group">
                @Html.LabelFor(model => model.Apellido, new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.Apellido)
                    @Html.ValidationMessageFor(model => model.Apellido)
                </div>
            </div>
    
            <div class="form-group">
                @Html.LabelFor(model => model.NombreArea, new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.NombreArea)
                    @Html.ValidationMessageFor(model => model.NombreArea)
                </div>
            </div>
    
            <div class="form-group">
                <div class="col-md-offset-2 col-md-10">
                    <input type="submit" value="Create" class="btn btn-default" />
                </div>
            </div>
        </div>
    }
    

    As you see, EmpleadoAreaViewModel is used as a model for my form.

    the interesting part comes in the controller, which would be passed the viewmodel as DataBinding example:

    [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Nuevo([Bind(Include = "Id,Nombre,Apellido, NombreArea")] EmpleadoAreaViewModel empleadoArea)
        {
            if (ModelState.IsValid)
            {
                var area = new Area()
                {
                    Nombre = empleadoArea.NombreArea
                };
                db.Areas.Add(area);
    
                var empleado = new Empleado()
                {
                    Nombre = empleadoArea.Nombre,
                    Apellido = empleadoArea.Apellido,
                    AreaId = area.Id
                };
                db.Empleados.Add(empleado);
                db.SaveChanges();
                return RedirectToAction("Index");
            }
    
            return View(empleadoArea);
        }
    

    Since you collected all the data in a single form and these belong to 2 different classes, you must separate the data and create them independently as shown in the controller code. in this case I did something rudimentary because you can use AutoMapper for this. In this way, a worker and an area are created at the same time. I hope it helps you.

    for the example that you ask me you can do it in this way:

    in your model:

     public class EmpleadoViewModel
     {
        public int Id { get; set; }
        public string Nombre { get; set; }
        public string Apellidos { get; set; }
     }
    

    in your view you use:

    @model IList<WebApplication1.ViewModels.EmpleadoViewModel>
    

    and you collect the data in this way:

    @using (Html.BeginForm("Nuevo", "Empleado", FormMethod.Post)) 
    {
    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
    
        @Html.ValidationSummary(true)
    
        <div class="form-group">
            <label>Area</label>
            <input type="text" id="area" name="area"/>
        </div>
    </div>
    
        for (int i = 0; i < 5; i++)
        { 
            <div class="form-group">
                <label>Nombre </label>
                <div class="col-md-10">
                    @Html.TextBoxFor(p => p[i].Nombre)
                </div>
            </div>
            <div class="form-group">
           <label>Apellidos </label>
            <div class="col-md-10">
                @Html.TextBoxFor(p => p[i].Apellidos)
            </div>
        </div>
        }  
    
    
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
     }
    

    You define the shekel until you reach the amount you want to insert in my case I set it to 5.

    in the controller:

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Nuevo( string area, List<EmpleadoViewModel>Empleados  )
        {
            if (ModelState.IsValid)
            {
                var Area = new Area()
                {
                    Nombre = area
                };
                db.Areas.Add(Area);
    
                foreach (var e in Empleados)
                {
                    var empleado = new Empleado()
                    {
                        Nombre = e.Nombre,
                        Apellido = e.Apellidos,
                        AreaId = Area.Id,
                    };
                    db.Empleados.Add(empleado);
                    db.SaveChanges();
                }
    
    
                return RedirectToAction("Index");
            }
    
            return View( );
        }
    

    This way should work for you. since you collect the name of an area and a list of workers in the post. In the end this kind of thing solves but I recommend that you use other ways like Angular for example that are much more flexible on the client side. I hope I help you

        
    answered by 05.06.2017 / 15:06
    source