0

I know this is pretty standard procedure, but yet due to some custom demands for the way the table is created I'm in trouble finding a way to read the data from the table and pass it back to the controller.

I build my table using records from the database each record holds rowNo and columnNo, and the problem is that each raw may have different number of columns. I couldn't find a proper plugin that can build this so instead I made a simple method that creates a string that I pass to the view.

Just to get the idea for what I'm talking about here is a snippet from the code where you can see how I create <td>..</td> :

sb.Append("<td>" + innerArray[a][0].QuestionText +
                                "<input type='textbox' value=" +
                                innerArray[a][0].FieldValue + "></td>");

I know it's not very smart to use StringBuilder and + but for now it works. So however, after building my string and passing it to the view I get this :

enter image description here

And this is the source from the View page source:

 <tr>
     <td>alabala<input type='textbox' value=></td>
     <td colspan=2><input type='textbox' value=yes></td>
 </tr>
 <tr>
     <td colspan=3>alabala<input type='textbox' value=yes></td>
 </tr>
 <tr>
     <td colspan=3>alabala<input type='textbox' value=yes></td>
 </tr>
 <tr>
     <td>alabala<input type='textbox' value=no></td>
     <td>alabala<input type='textbox' value=no></td>
     <td>alabala<input type='textbox' value=no></td>
 </tr>
 <tr>
     <td>alabala<input type='textbox' value=no></td>
     <td colspan=2><input type='textbox' value=no></td>
 </tr>
 <tr>
     <td colspan=3>alabala<input type='textbox' value=></td>
 </tr>
 <tr>
     <td colspan=3>alabala<input type='textbox' value=no></td>
 </tr>

It's how you see it - one long string containing the whole HTML code.

all text boxes are editable so what I need is a way to read the data for each text box and save/pass it along with the RowNo and ColumnNo so I can save it back in my database.

4
  • Doesn't seem like a single row to me did you mean it's contained in a single table? And how do often do want to submit your data back? After every input? Once finished? Commented Apr 25, 2013 at 6:46
  • Sorry, I see that it's misleading so I edited my question. I mean that in the View Page Source the custom generated code is shown as one long string in other words - no formatting like the one you did. And the info will be submitted only on Save button click. So basically I'll submit the data only once. Commented Apr 25, 2013 at 6:51
  • I see, and do you submit your data through ajax or is it a classic submit? Commented Apr 25, 2013 at 6:52
  • Haven't decided yet. It's my first ASP.NET MVC 3 project I see that it has a lot of build in plugins and stuff, and I have a complete freedom to do the things like I want. And what I want is just to use and learn good practices which I can reuse in the future. Commented Apr 25, 2013 at 6:55

2 Answers 2

5

Why don't you use a view model? What you have done with this string builder inside a controller action is something that goes against absolutely all good practices that you might have in the MVC design pattern.

So, as always you could start by defining a view model that will meet the requirements of your view:

public class ColViewModel
{
    public string RowNumber { get; set; }
    public string ColumnNumber { get; set; }
    public string QuestionText { get; set; }
    public string FieldValue { get; set; }
}

public class RowViewModel
{
    public List<ColViewModel> Columns { get; set; }
}

Alright, now let's go ahead and populate this view model and pass it to the view:

public ActionResult Index()
{
    // in your question you have shown something called innerArray, so I assume you
    // already retrieved this from your database or something:
    SomeDomainModel[,] innerArray = ...

    var model = new List<RowViewModel>();
    for (var row = 0; row < innerArray.GetUpperBound(0); row++)
    {
        var rowModel = new RowViewModel
        {
            Columns = new List<ColViewModel>()
        };
        for (var col = 0; col < innerArray.GetUpperBound(1); col++)
        {
            rowModel.Columns.Add(new ColViewModel
            {
                RowNumber = innerArray[row, col].RowNo,
                ColumnNumber = innerArray[row, col].ColumnNo,
                QuestionText = innerArray[row, col].Question,
                FieldValue = innerArray[row, col].FieldValue,
            });
        }
        model.Add(rowModel);
    }

    return View(model);
}

[HttpPost]
public ActionResult Index(List<RowViewModel> model)
{
    ...
}

and finally in your corresponding strongly typed view:

@model List<RowViewModel>
@using (Html.BeginForm())
{
    <table>
        @for (var i = 0; i < Model.Count; i++)
        {
            <tr>
                @for (var j = 0; j < Model[i].Columns.Count; j++)
                {
                    <td>
                        @Html.HiddenFor(x => x[i].Columns[j].RowNumber)
                        @Html.HiddenFor(x => x[i].Columns[j].ColumnNumber)
                        @Html.DisplayFor(x => x[i].Columns[j].QuestionText)
                        @Html.EditorFor(x => x[i].Columns[j].FieldValue)
                    </td>
                }
            </tr>
        }
    </table>

    <button type="submit">Save</button>
}
Sign up to request clarification or add additional context in comments.

5 Comments

Ah, you beat me by a few seconds but it's interesting that we came up with exactly the same solution; using a List<RowViewMode>. Must be correct :-)
Lol, about the first question - I don't use this because I'm on my own and on my own the thing I could think of was doing it mostly in C#. Second - you guessed right I used [,] then switch to jagged array because I thought that this will give me more options. I need time to think over your answer, but think I'm gonna try to implement it in my code. Btw Offtopic - are you working for Musala soft?
I've seen your answers in many questions here. Always something good to learn from you. It's motivating to see fellow bulgarian on this level of .NET. Pozdravi :)
I don't know if you gonna see this, but in my project is user repository pattern and Database first approach. DataAccess is separate project from the entire solution and there are the ModelExtensions and the Entities generated from the EF. Where is the place of the view model - in the DataAccess project along with the model extensions or in the actual mvc project, where in fact now there are only views and controllers folders?
The view model should be defined in the MVC project along with your views.
2

Don't pass html to your view. It's the view's responsibility to do that. I would first question the schema of your database (why does the db care about how the data will be represented by the view?). Let's assume that we don't change anything there. The way to do this is to create a View Model. I can't code it with the info you're giving us (what's the format of the data coming from the db?). But here's pseudocode.

  1. Controller retrieves records from the database
  2. Controller creates a View Model (let's call it RowModel) for each row record and fills it with the column data. You end up with a List. Let's call that rowModels.
  3. The controller calls the view with that data `return View(rowModels)
  4. The view declares a @model List<RowModel> at the top of the code.
  5. Your Razor code interates through the rows in the model and build the HTML.
  6. Create another Controller Action MyAction(List<RowModels). This is what will be called on submit. Simply iterate through the rows and perform any db update needed.

Another advantage of using View Models is that you can specify the validation that will be used for the fields instead of relying on the (possibly missing) db model validation. See this.

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.