2012-02-16 22 views
5

He estado intentando durante semanas seguir un par de tutoriales sobre cómo crear un formulario dinámico que le permita agregar otro "ingrediente" al formulario. Aquí está el artículo que traté de seguir. http://www.joe-stevens.com/2011/07/24/asp-net-mvc-2-client-side-validation-for-dynamic-fields-added-with-ajax/Formulario dinámico MVC 3 usando un modelo de vista

Ahora mismo estoy trabajando en agregar varios ingredientes de receta usando el enlace de agregar, pero necesitaré tener el "ingrediente Nombre" y el "valor de receta" Cantidad que se puede agregar cuando se hace clic en el enlace. Mi problema es que cuando ejecuto la aplicación, el formulario de receta tiene un 0 en lugar de un cuadro de texto real. Cuando hago clic en Agregar nuevo ingrediente, puedo obtener un cuadro de texto para agregar, pero cuando escribo una cantidad y hago clic en Guardar, los datos del modelo no se pasan al controlador.

Simplemente no sé dónde empiezo por arreglar esto, no estoy seguro de si debería usar un modelo de vista o si estoy haciendo esto completamente mal. Aquí está mi diagrama de base de datos http://i44.tinypic.com/xp1tog.jpg.

Aquí es mi CreateView:

@model ViewModels.RecipeViewModel 
@using Helpers; 



<h2>CreateFullRecipe</h2> 

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script> 
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script> 

    <script type="text/javascript"> 
     $().ready(function() { 
      $("#add-recipeingredient").click(function() { 
       $.ajax({ 
        url: '@Url.Action("GetNewRecipeIngredient")', 
        success: function (data) { 
         $(".new-recipeingredients").append(data); 
         Sys.Mvc.FormContext._Application_Load(); 
        } 
       }); 
      }); 
     }); 
    </script> 

    @using (Html.BeginForm()) 
    { 
      @Html.ValidationSummary(true) 
    <fieldset> 
     <legend>Recipe</legend> 

     <div class="editor-label"> 
      @Html.LabelFor(model => model.Recipe.RecipeName) 
     </div> 
     <div class="editor-field"> 
      @Html.EditorFor(model => model.Recipe.RecipeName) 
      @Html.ValidationMessageFor(model => model.Recipe.RecipeName) 
     </div> 
    </fieldset> 


     <fieldset> 
      <legend>RecipeIngredients</legend> 
      <div class="new-recipeingredients"> 

       @Html.EditorFor(model => model.RecipeIngredients) 

      </div> 
      <div style="padding: 10px 0px 10px 0px"> 
       <a id="add-recipeingredient" href="javascript:void(0);">Add another</a> 
      </div> 
     </fieldset> 

     <div> 
      <input type="submit" value="CreateFullRecipe" /> 
     </div> 

    } 
<div> 
    @Html.ActionLink("Back to List", "Index") 
</div> 

Mi editortemplateview para recipeIngredient:

@model Models.RecipeIngredient 
@using Helpers; 

@using (Html.BeginAjaxContentValidation("form0")) 
    { 
     using (Html.BeginCollectionItem("RecipeIngedients")) 
     { 
    <div style="padding: 5px 0px 5px 0px"> 
     @Html.LabelFor(model => model.Amount) 
     @Html.EditorFor(model => model.Amount) 
     @Html.ValidationMessageFor(model => Model.Amount) 
    </div> 

     } 
    } 

mi regulador en relación métodos:

[HttpGet] 
    public ActionResult CreateFullRecipe() 
    { 
     var recipeViewModel = new RecipeViewModel(); 
     return View(recipeViewModel); 
    } 

    // 
    // POST: /Recipe/Create 

    [HttpPost] 
    public ActionResult CreateFullRecipe(RecipeViewModel recipeViewModel) 
    { 
     if (ModelState.IsValid) 
     { 
      db.Recipes.Add(recipeViewModel.Recipe); 
      db.SaveChanges(); 
      int recipeID = recipeViewModel.Recipe.RecipeID; 
      for (int n = 0; n < recipeViewModel.RecipeIngredients.Count(); n++) 
      { 
       db.Ingredients.Add(recipeViewModel.Ingredients[n]); 
       int ingredientID = recipeViewModel.Ingredients[n].IngredientID; 

       recipeViewModel.RecipeIngredients[n].RecipeID = recipeID; 
       recipeViewModel.RecipeIngredients[n].IngredientID = ingredientID; 
       db.RecipeIngredients.Add(recipeViewModel.RecipeIngredients[n]); 

       db.SaveChanges(); 
      } 

      return RedirectToAction("Index"); 
     } 

     return View(recipeViewModel); 
    } 

    public ActionResult GetNewIngredient() 
    { 
     return PartialView("~/Views/Shared/IngredientEditorRow.cshtml", new Ingredient()); 
    } 

    public ActionResult GetNewRecipeIngredient() 
    { 
     return PartialView("~/Views/Shared/_RecipeIngredientEditRow.cshtml", new RecipeIngredient()); 
    } 

Mi Ver Modelo:

public class RecipeViewModel 
    { 
     public RecipeViewModel() 
     { 
      RecipeIngredients = new List<RecipeIngredient>() { new RecipeIngredient() }; 
      Ingredients = new List<Ingredient>() { new Ingredient() }; 
      Recipe = new Recipe(); 
     } 

     public Recipe Recipe { get; set; } 
     public IList<Ingredient> Ingredients { get; set; } 
     public IList<RecipeIngredient> RecipeIngredients { get; set; } 
    } 
} 

Si hay alguna otra información necesaria para ayudar a mi problema a cabo por favor hágamelo saber. Esto realmente me está volviendo loco así que espero cualquier ayuda que pueda obtener ¡Gracias!

También me gustaría mencionar que el método de publicación de controlador createfullrecipe es para una lista predefinida y funcionó cuando no estaba preocupado por darle al usuario la posibilidad de agregar otro ingrediente, sino que simplemente dejé el formulario para tener 2 ingredientes y mi vista tenía este código comentado para crearlos. Todo lo que realmente quiero hacer es obtener el modelo de vista para pasar los datos del formulario al controlador y puedo manejar los datos como lo hace mi método de controlador createrelrecipe ahora.

@* @for (int n = 0; n < Model.Ingredients.Count(); n++) 
    { 
     <div class="editor-label"> 
      @Html.LabelFor(model => model.Ingredients[n].IngredientName) 
     </div> 
       <div class="editor-field"> 
      @Html.EditorFor(model => model.Ingredients[n].IngredientName) 
      @Html.ValidationMessageFor(model => model.Ingredients[n].IngredientName) 
     </div> 

     <div class="editor-label"> 
      @Html.LabelFor(model => model.RecipeIngredients[n].Amount) 
     </div> 
       <div class="editor-field"> 
      @Html.EditorFor(model => model.RecipeIngredients[n].Amount) 
      @Html.ValidationMessageFor(model => model.RecipeIngredients[n].Amount) 
     </div> 
    }*@ 

Éstos son mis clases del modelo:

public class Recipe 
{ 
    public int RecipeID { get; set; } 
    public string RecipeName { get; set; } 
    public string Description { get; set; } 
    public int? PrepTime { get; set; } 
    public int? CookTime { get; set; } 
    public string ImageURL { get; set; } 

    public virtual IList<RecipeTag> RecipeTags { get; set; } 
    public virtual IList<Rating> Ratings { get; set; } 
    public virtual IList<RecipeStep> RecipeSteps { get; set; } 
    public virtual IList<RecipeIngredient> RecipeIngredients { get; set; } 

} 

public class RecipeIngredient 
{ 
    public int RecipeIngredientID { get; set; } 
    public string IngredientDesc { get; set; } 
    public string Amount { get; set; } 
    public int RecipeID { get; set; } 
    public int? IngredientID { get; set; } 

    public virtual Recipe Recipe { get; set; } 
    public virtual Ingredient Ingredient { get; set; } 
} 

public class Ingredient 
{ 

    public int IngredientID { get; set; } 
    public string IngredientName { get; set; } 

    public virtual ICollection<RecipeIngredient> RecipeIngredients { get; set; } 
} 
+0

Hablo sobre este tema en esta publicación del blog: http://www.jasoncavett.com/2011/03/using-unobtrive-jquery-validation.html – JasCav

+0

Ahora mismo no estoy seguro de si la validación es mi mayor problema. No puedo obtener la forma dinámica para enviar los datos a mi controlador. Ahora las cosas que no son ajax, por ejemplo, si escribo el nombre de la receta, eso existe en el modelo de vista que se pasó a mi controlador. – papayt

Respuesta

13

Hay un montón de problemas con su código. Prefiero ir paso a paso para ilustrar un ejemplo simplificado que pueda adaptar a sus necesidades.

Modelos:

public class RecipeViewModel 
{ 
    public Recipe Recipe { get; set; } 
    public IList<RecipeIngredient> RecipeIngredients { get; set; } 
} 

public class Recipe 
{ 
    public string RecipeName { get; set; } 
} 

public class RecipeIngredient 
{ 
    public int Amount { get; set; } 

    [Required] 
    public string IngredientDesc { get; set; } 
} 

controlador:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     var recipeViewModel = new RecipeViewModel(); 
     return View(recipeViewModel); 
    } 

    [HttpPost] 
    public ActionResult Index(RecipeViewModel recipeViewModel) 
    { 
     if (!ModelState.IsValid) 
     { 
      // there wre validation errors => redisplay the view 
      return View(recipeViewModel); 
     } 

     // TODO: the model is valid => you could pass it to your 
     // service layer for processing 

     return RedirectToAction("Index"); 
    } 

    public ActionResult GetNewRecipeIngredient() 
    { 
     return PartialView("~/Views/Shared/EditorTemplates/RecipeIngredient.cshtml", new RecipeIngredient()); 
    } 
} 

Ver (~/Views/Home/Index.cshtml):

@model RecipeViewModel 

<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script> 
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script> 
<script type="text/javascript"> 
    $(function() { 
     $('#add-recipeingredient').click(function() { 
      $.ajax({ 
       url: '@Url.Action("GetNewRecipeIngredient")', 
       type: 'POST', 
       success: function (data) { 
        $('.new-recipeingredients').append(data); 
       } 
      }); 
      return false; 
     }); 
    }); 
</script> 

@using (Html.BeginForm()) 
{ 
    @Html.ValidationSummary(true) 

    <div> 
     @Html.LabelFor(model => model.Recipe.RecipeName) 
     @Html.EditorFor(model => model.Recipe.RecipeName) 
     @Html.ValidationMessageFor(model => model.Recipe.RecipeName) 
    </div> 

    <fieldset> 
     <legend>RecipeIngredients</legend> 
     <div class="new-recipeingredients"> 
      @Html.EditorFor(model => model.RecipeIngredients) 
     </div> 
     <div style="padding: 10px 0px 10px 0px"> 
      <a id="add-recipeingredient" href="javascript:void(0);">Add another</a> 
     </div> 
    </fieldset> 

    <div> 
     <input type="submit" value="CreateFullRecipe" /> 
    </div> 
} 

editor de plantillas (~/Views/Shared/EditorTemplates/RecipeIngredient.cshtml):

@model RecipeIngredient 

@using (Html.BeginCollectionItem("RecipeIngredients")) 
{ 
    <div> 
     @Html.LabelFor(model => model.Amount) 
     @Html.EditorFor(model => model.Amount) 
     @Html.ValidationMessageFor(model => model.Amount) 
    </div> 

    <div> 
     @Html.LabelFor(model => model.IngredientDesc) 
     @Html.EditorFor(model => model.IngredientDesc) 
     @Html.ValidationMessageFor(model => model.IngredientDesc) 
    </div> 
} 
+0

Gracias por ayudar, realmente lo aprecio. Actualicé mi publicación para incluir mis modelos ya existentes que pueden ayudarme con las respuestas. También podría usar algo de ayuda para determinar si debo combinar las tablas normalizadas Ingrediente y receta en una tabla/modelo para simplificar las cosas. También actualicé mi js y vistas con su enfoque más limpio, pero el método de publicación del controlador todavía no tiene mis datos de formulario en el pasado en viewModel. ¿Supongo que tiene algo que ver con la configuración de mis modelos? – papayt

+0

@papayt, ¿has probado mi código? Como dije, hay muchos problemas con los suyos. Por ejemplo, tiene 'using (Html.BeginCollectionItem (" RecipeIngedients "))' mientras que el correcto es 'using (Html.BeginCollectionItem (" RecipeIngredients "))' simplemente porque su propiedad se llama 'RecipeIngredients' y no' RecipeIngedients'. Otro problema es con el nombre y la ubicación de su plantilla de editor. Entonces, ¿qué recomendaría que usara mi código como base para las extensiones? –

+0

¡Oh, wow, nunca me di cuenta de que tenía un error tipográfico con (Html.BeginCollectionItem ("RecipeIngedients")), gracias! Moví mi plantilla de editor renombrada a la carpeta que recomendabas también. Y ... ¡Impresionante! Acabo de probar mi porción de receta dinámica de mi código con la capacidad de agregar otro ingrediente de receta, y funciona. Los datos se pasan a mi controlador. :) ¡Ahora puedo continuar trabajando en limpiar mi código y descubrir cómo integrar el modelo de ingredientes a mi forma dinámica y luego manejar los datos en mi controlador! Muchas gracias, Darin. – papayt

Cuestiones relacionadas