0

I have a problem which I'm unable to solve so any help would be appreciated. I have a view in which I'm dynamically adding textboxes (depending of a value chosen in dropdownlist).

Basically, I'm entering data for the product which depending of the category it belongs to has specific attributes added to it. For example, if the product is soft dring it could have following attributes: type of packaging, flavor, volume, etc. while some other product like cell phone may have attributes like: weight, RAM, CPU clock, CPU type, etc.

This is how the database looks like:

Tables in the database

Dynamically creating controls isn't a problem and it is done with this code:

<script type="text/javascript">
    $(document).ready(function () {          

        $("#ProductCategoryId").change(function () {
            if ($("#ProductCategoryId").val() != "") {
                var options = {};
                options.url = "http://localhost:59649/Product/GetProductCategoryAttributes";
                options.type = "POST";
                options.data = JSON.stringify({ id: $("#ProductCategoryId").val() });
                options.dataType = "json";
                options.contentType = "application/json";
                options.success = function (productCategoryAttributes) {
                    $("#atributtes").empty();
                    for (var i = 0; i < productCategoryAttributes.length; i++) {
                        $("#atributi").append("<div class='editor-label'><label>" + productCategoryAttributes[i].Name + "</label></div>")
                        .append("<div class='editor-field'><input class='text-box single-line' id='" + productCategoryAttributes[i].Name + "' name='" + productCategoryAttributes[i].Name + "' type='text'>");
                    }
                };
                options.error = function () { alert("Error retrieving data!"); };
                $.ajax(options);
            }
            else {
                $("#atributtes").empty();
            }
        });
    });
</script>

Method in controller that retrieves ProductAttributeCategory names depending of ProductCategoryId selected:

    public JsonResult GetProductCategoryAttributes(int id)
    {
        var productCategoryAttributes = db.ProductCategoryAttribute
            .Where(p => p.ProductCategoryId == id)
            .Select(p => new { Name = p.Name, p.DisplayOrder })
            .OrderBy(p => p.DisplayOrder)
            .ToList();

        return Json(productCategoryAttributes, JsonRequestBehavior.AllowGet);
    }

Controller code for POST:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(Product product)
    {
        if (ModelState.IsValid)
        {
            db.Product.Add(product);
            db.SaveChanges();

            var productCategoryAttributes = db.ProductCategoryAttribute
                .Where(p => p.ProductCategoryId == product.ProductCategoryId)
                .OrderBy(p => p.DisplayOrder);

            foreach (ProductCategoryAttribute productCategoryAttribute in productCategoryAttributes)
            {
                //Find HTML element that matches productCategoryAttribute.Name
                ProductProductCategoryAttribute productCategoryAttributeValue = new ProductProductCategoryAttribute();
                productCategoryAttributeValue.ProductId = product.ProductId;
                //productCategoryAttributeValue.ProductCategoryAttributeId = Find HTML element that matches ProductCategoryAttributeID and pass its id here
                //productCategoryAttributeValue.Value = Find HTML element that matches ProductCategoryAttributeID and pass its value here

                db.ProductProductCategoryAttribute.Add(productCategoryAttributeValue);
                db.SaveChanges();

            }               
            return RedirectToAction("Index");
        }

        ViewBag.LanguageId = new SelectList(db.Language, "LanguageId", "Name", product.LanguageId);
        ViewBag.ProductCategoryId = new SelectList(db.ProductCategory, "ProductCategoryId", "Name", product.ProductCategoryId);
        return View(product);
    }

Product model:

    public partial class Product
{
    public Product()
    {
        this.ProductPhoto = new HashSet<ProductPhoto>();
        this.ProductProductCategoryAttribute = new HashSet<ProductProductCategoryAttribute>();
    }

    public int ProductId { get; set; }
    public int LanguageId { get; set; }
    public int ProductCategoryId { get; set; }
    public string Name { get; set; }
    public string EAN { get; set; }
    public string Description { get; set; }

    public virtual Language Language { get; set; }
    public virtual ProductCategory ProductCategory { get; set; }
    public virtual ICollection<ProductPhoto> ProductPhoto { get; set; }
    public virtual ICollection<ProductProductCategoryAttribute> ProductProductCategoryAttribute { get; set; }
}

ProductCategory model:

    public partial class ProductCategory
{
    public ProductCategory()
    {
        this.Product = new HashSet<Product>();
        this.ProductCategoryAttribute = new HashSet<ProductCategoryAttribute>();
    }

    public int ProductCategoryId { get; set; }
    public int LanguageId { get; set; }
    public string Name { get; set; }
    public string PhotoLocation { get; set; }
    public int DisplayOrder { get; set; }
    public bool Active { get; set; }

    public virtual Language Language { get; set; }
    public virtual ICollection<Product> Product { get; set; }
    public virtual ICollection<ProductCategoryAttribute> ProductCategoryAttribute { get; set; }
}

ProductCategoryAttribute model:

    public partial class ProductCategoryAttribute
{
    public ProductCategoryAttribute()
    {
        this.ProductProductCategoryAttribute = new HashSet<ProductProductCategoryAttribute>();
    }

    public int ProductCategoryAttributeId { get; set; }
    public int ProductCategoryId { get; set; }
    public string Name { get; set; }
    public string MetaName { get; set; }
    public string SymbolLocation { get; set; }
    public int DisplayOrder { get; set; }
    public bool Active { get; set; }

    public virtual ProductCategory ProductCategory { get; set; }
    public virtual ICollection<ProductProductCategoryAttribute> ProductProductCategoryAttribute { get; set; }
}

What I can't figure out is how to get the values from those dynamically created textboxes. Pseudocode (inside the controller) would be something like this:

  1. Get the ProductCategoryId of the product
  2. List all the attributes belonging to the selected product category
  3. For each attribute find the appropriate textbox inside the view and get the value entered
  4. Save the value to the database

I'm fairly new to the MVC so my approach may be wrong. Feel free to correct me.

9
  • Can you please post the signature of the post action method, and if the parameter is a model, the definition of the model Commented Aug 2, 2014 at 23:24
  • @StephenMuecke - Edited, parameter is model only for Product. If more clarification is needed please let me know. Commented Aug 2, 2014 at 23:55
  • 1
    Can you post your product model? Commented Aug 3, 2014 at 0:02
  • 1
    So does Product have property IEnumerable<Attribute> attributes (or similar) and Attribute have some properties such as ID, Name, Value etc? - please post relevant snippets of Product Commented Aug 3, 2014 at 0:03
  • Product, ProductCategory and ProductCategoryAttribute models are added to the post. ProductProductCategoryAttribute is just a table in a database that holds ProductId, ProductCategoryAttributeId and Value so its model is pretty much straightforward. Commented Aug 3, 2014 at 0:10

2 Answers 2

3

It's very hard to read your code so here is a simplified version that should help you. Suppose you have these two models:

public class ProductCategory
{
   public int CategoryId { get; set; }
   public string CategoryName { get; set; }
}

public class Product
{
   public Product()
   {
      Categories = new List<ProductCategory>();
   }

   public int ProductId {get;set;}
   public string ProductName { get; set; }
   public IEnumerable<ProductCategory> Categories { get; set; }
}

If these where your models then then the name attribute of your dynamically added textbox should be:

<input type="textbox" name="Categories[i].CategoryName" />

You can safely ignore the id attribute since name attribute is enough for proper model mapping/binding. Whatever value you enter in the textbox should map into an instance of a ProductCategory's CategoryName in the list of Categories attached to the Product model...

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

2 Comments

It doesn't matter what the models look like I gave you an example that is very similar to your models. Just match the properties to your model. The best way to learn anything is to try to figure it out yourself anyway...
I've responded to the OP. Thank you anyway!
0

Thank you both of you. I've found a quick and, as it seems, dirty way of accomplishing this.

Basically, you can access any HTML control by using:

var value = Request["controlName"];

That is how I was able to get values from the form. I don't know if this is the right way but it sure worked for me. Any suggestion for improving this is more than welcome.

Comments

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.