0

I am developing an web application (Food blog) in ASP.NET MVC where I want to allow the user to type in a Recipe. A recipe does of course contains a lot of ingredients. I have the following classes:

 public class Recipe
{
    public string Name { get; set; }
    public int ID { get; set; }
    public string Auhtor { get; set; }
    public string Category { get; set; }
    public string Text { get; set; }
    public List<Ingredient> Ingredients { get; set; }
    public byte[] Picture { get; set; }
}

public class Ingredient
{
    public int ID { get; set; }
    public double Amount { get; set; }
    public string Unit { get; set; }
    public string Name { get; set; }
}

And in html i would like to make a page where the user can type in a recipe with a lot of ingredients. The create-view so far looks like this:

@using (Html.BeginForm()) 
{
@Html.AntiForgeryToken()

<div class="form-horizontal">
    <h4>Recipe</h4>
    <hr />
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
    <div class="form-group">
        @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Category, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.Category, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.Category, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Text, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.Text, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.Text, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group" id="Ingredient">
        @Html.LabelFor(model => model.Ingredients, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10" id="IngredientDiv">
            <label>Ingredient</label>
        </div>


    </div>
    <div class="AddEl">
        <p><a>Tilføj endnu en ingredients</a></p>
    </div>
    <div class="RemoveEl">
        <p><a>Fjern en ingredients</a></p>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Picture, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.Picture, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.Picture, "", new { @class = "text-danger" })
        </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>

    <script type="text/javascript" src="/Scripts/jquery-1.10.2.js"></script>
    <script>
    //Ajax to navigate between days
        $(document)
        .ready(function () {

            var counter = 1;
            $('.AddEl').click(function () {
                var el = $('#IngredientDiv').clone().attr('id', 'element_' + ++counter).appendTo('#Ingredient');
            });

            $('.RemoveEl').click(function () {
                var el = $(this).parents('.elem');
                if (counter > 1) {
                    el.remove();
                    counter--;
                }
            });

            });
    </script>
</div>

}

How can I link the Ingredients to this view? AS you can see I have already written the code to dynamically add and remove elements of the ingredient-div.

Thanks for your help!

  • I think this will lead you into right direction: https://www.google.pl/search?num=20&newwindow=1&safe=off&espv=2&q=asp.net+mvc+multiselectlist+example&oq=asp.net+mvc+multiselectlist+&gs_l=serp.3.0.0i19k1j0i22i30i19k1j0i22i10i30i19k1j0i22i30i19k1l7.58659.63687.0.64887.12.10.0.2.2.0.188.1195.2j8.10.0....0...1c.1.64.serp..0.12.1199...0j0i22i30k1.d2rxQ_ouvLc – Sebastian Xawery Wiśniowiecki Jan 15 '17 at 17:51
  • Refer [this answer](http://stackoverflow.com/questions/28019793/submit-same-partial-view-called-multiple-times-data-to-controller/28081308#28081308) for some options to dynamically add collection items –  Jan 16 '17 at 05:12

2 Answers2

0

Not sure how you want to show List<Ingredient> in your view but you can have List<Ingredient> by having view.bag in your controller:

 ViewBag.Ingredients= new SelectList(db.GetIngredient(), "Value", "Text");

and in your view you could have :

@Html.DropDownListFor(model => model.Ingredients, new SelectList(ViewBag.Ingredients, "Value", "Text")

Probably you need more that one @Html.DropDownListFor and you can keep the first DropDownListFor visibale and the rest invisible. Then as soon as user adds one Ingredient you can make the next DropDownListFor visible to let user add another Ingredient.

Hadee
  • 1,392
  • 1
  • 14
  • 25
  • Thanks the answer. But I think I have been misunderstood, I don't want to show ingredients to the user. I want the user to create new Ingredients to the Recipe. The user should be able to type in the name, amount and unit of the Ingredient. – SImonThrane Jan 15 '17 at 20:16
  • So use partial view for every Ingredient instead of `DropDownListFor` and use the same visible-invisible method. – Hadee Jan 15 '17 at 20:19
0

First of all you need to make user there is relationship between tables. Add new attribute in Recipe Class:

public int IngredientsID;

Then need to encapsulate both of your entity classes in a View Model. You can accomplish same thing with view bag but using view model is the best practice. Create view model like this:

public class FoodViewModel {

  public Recipe Recipe {get; set;}
  public IEnumerable<Ingredient> Ingredients {get; set;}

}

Retrieve the list of Ingredients from context and supply it to your view model and pass your view model to your view .cshtml

public ActionResult New()
{
  var _list = _context.Ingredients.ToList();
  var viewModel = new FoodViewMode 
  {
    Ingredients = _list
  };
  return View(viewModel);
}

Now, strongly type your view .cshtml with FoodViewModel.

@model Models.FoodViewModel

You will need to make some changes in your view .cshtml since your view model contains two entity models. You will need to use fully qualified name here. e.g.

@Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })

Will turn into:

@Html.LabelFor(model => model.Receipe.Name, htmlAttributes: new { @class = "control-label col-md-2" })

Instead of "model.Name", we are using "model.Receipe.Name".

Now to get drop down list you can do:

@Html.DropDownListFor(x => x.Recipe.IngredientsID, new SelectList(Model.Ingredients, "ID", "Name"));

I hope it will solve your problem.

Hussain Rauf
  • 278
  • 2
  • 15