MVC editing complex object stored in hidden fields - c#

Let's say I have a very huge model that contains lists and even those lists can have objects that contain other lists. I want to create an edit form for that in MVC4 (or 5) without AJAX.
So I figured that the first part of that is to store the entire object on the client side in hidden fields. List binding works like a charm, see http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/. Now the complete roundtrip is working, I can push out the entire object to the client in bound hidden fields, it gets back to me upon submit and the posted hidden fields are put into the complex object, nested lists and everything included.
Lists or other objects should become editable based on some action. One scenario is where a single object or list items are displayed as non-editable, and when the user clicks it, it becomes editable in-place, so for example the cells in a grid become textboxes. Another scenario is where a single object or list items are not shown at all, and when the user clicks a button, a popup window appears with the text input fields.
Is there a library or a proven way to do this?

Is there a library or a proven way to do this?
Exactly what for? Displaying a massive model in view for editing? Making a grid editable? Or popping up the records of a grid for editing?
Basically, I think you are overcomplicating this matter a bit. If you apply some separation of concerns here you will find out how easy everything becomes and in fact it's super easy to implement and most importantly much easier to maintain and scale.
Starting from the model, let's assume you've got this all-mighty massive model named Company with the following properties:
CompanyID (int)
CompanyName (string)
CompanyLegalID (string)
CompanyRegistrationNumber (string)
ContactInfo (ContactInfo class)
HeadQuaterAddress ('Address` class)
Branches (List of Branch classes)
Employees (List of Employee classes)
And the list of properties could go on and on forever.It would be easier, super easier to break down this model into smaller models. Make a CompanyModel model with the following properties...
CompanyID (int)
CompanyName (string)
CompanyLegalID (string)
CompanyRegistrationNumber (string)
Then make a CompanyContactInfo model and so on. Getting the idea? Again, separation of concerns simplifies matters a lot. Then, create action methods and views to read/edit these models.
Now for lists properties of the massive object you'd like to do the same. For example, for the list of Employee objects it'd be easier to create a CompanyEmployeesModel model with the following properties:
CompanyId (int)
Employees (List of EmployeeModel classes)
Then create a controller action method to show the list of employees...
public ActionResult EmployeeList(int companyId)
{
var employees = BusinessLogic.Get_Me_Employees_For(companyId);
CompanyEmployeesModel model = new CompanyEmployeesModel();
model.CompanyId = companyId;
model.Employees = employees;
return View(model);
}
Hope you are getting the idea so far. In the view simply create a css-formatted table to show the employee list, razor makes it super simple...
<table class="grid">
<tr>
<th></th>
<th>
Name
</th>
<th>
Phone
</th>
</tr>
#{
var alt = false;
foreach (var emp in Model.Employees)
{
<tr class="#(alt ? "alt" : string.Empty)">
<td class="cmd">
#ActionLink("edit", "Edit", "Employees", new { empId = emp.Id}, null)
</td>
<td>#emp.Name</td>
<td>#emp.Phone</td>
</tr>
alt = !alt;
}
}
</table>
Notice that the first column of the table has link "edit" that takes the user to the Edit action method of the Employee controller where obviously you will do exactly the same you've been doing with smaller models. All I'm doing is separating the logic, models, view and making them simpler, easier to maintain and easier to understand.
Hope it all makes sense to you

Jeditable http://www.appelsiini.net/projects/jeditable which does the same thing and is easier to implement

The very huge model is a business requirement, it has to be edited as one entity, preferably on one page, it makes perfect sense but I can't talk about it. I originally thought (or hoped) there was an easy to describe solution, but apparently, this isn't a common thing in MVC. It would be very different with AJAX, it has its pros and cons. For sure it's more widely used, hence more documented. Without AJAX, there is only one round-trip, which is a bit bigger, but it's a smoother user experience. Anyway, here's a rough guide how to do it the way I asked.
The client-server roundtrip is handled by MVC with (mostly) hidden fields as I said in the question. Later it can be optimized by encoding some stuff in JSON instead of hidden fields, it doesn't affect the rest of the system.
Normal fields are stored in normal editors, not hidden fields. It makes no difference from the perspective of the client-server roundtrip. So these can be edited in place.
Grid rendering is also easy. Server-side MVC grids are suboptimal in this case, because they would send redundant data to the client side. Luckily there are a lot more client-side grid solutions, they are by nature server platform independent. Just collect the required data from the hidden fields and use a JavaScript grid library to build a grid from it when the page loads. Naturally, as I said, the lists can contain lots of data and other nested lists, but in this simple grid, a few necessary columns must be selected, no problem with that.
Now comes the interesting part, how to edit a grid row with all that complex data. Let's say I have a list of Persons in my model, and they have a list of Addresses. There is a Person grid, and when you click on a row, you want the end user to be able to edit additional data for a Person and also his Addresses.
First of all, the Person editor template has to be sent to the client side in advance. We need to put that editor template inside our view, and hide it. Whenever the user wants to edit a person, we create a JS dialog with the contents of that editor template.
We need to bind the Person editor template to a Person object stored in the hidden fields. Based on which row the user clicked, we get an index, and we bind Model.Persons[index] to that template. Knockout.js is a good candidate for JS binding. It does all the field copying back and forth.
An MVC editor template can also contain validation logic. It's no problem in this case, because we rendered the editor template to the client side as a whole. The validation will happen inside the popup window without any kind of magic. When the user presses the save button, validation will run, and when it succeeds, we use the binding engine to copy the popup contents back into the hidden fields.
It is not the simplest of things, but it is very straightforward. Actually, several different JS libraries are needed, not as I hoped. So if anyone wants to edit a complex model on a single page without AJAX, it is certainly possible. It's still not completely documented because I can't share more details. But it has its advantages: only one round-trip, hence faster user experience, and there's no need to maintain state on the server, all the data is retrieved and saved as one entity in one roundtrip.

Related

How to avoid code duplication if multiple pages look almost the same?

I have a couple of pages for e.g. Product that look almost the same. I have Product/Add and Product/Modify/{id} pages where one is an empty form to add new Product and the second one comes already filled with data for a current product and can be updated with additional information. Because Razor Pages separates this into Add and Modify PageModels, I have a different cshtml view for each of them.
I tried to use ViewComponents to build reusable parts of these views, but they are only good if all you want to do is display data. Because ViewComponents don't support Binding all I have left is somehow send ajax requests and append the data to submit, which even sounds wrong and probably isn't the right approach.
Is there any other way of creating these pages without duplication?
You can create one page for create and edit by sending a new object of the Product model (with no data in id attribute) and a created object (with data in id attribute) in case of editing. And in the view you can do rendering based on the sent object (whether it is new or not).

Sitecore: Drop Down Search Menu

I am in need of hopefully an example for a drop down list search function. Not sure what the correct terminology would be.
Needed:
Two drop down lists then a submit button. First being of Country, then the second being of Department. So say you picked France and HR, it would display a contact person below.
Is there any examples of something of this sort? Would be nice have code in CS then have my end user be able to add and link the two together in Sitecore. So they could add Countries they would like, departments they would like, then the respected person linked to the two fields.
So if I understand you correctly, you're taking multiple inputs and producing results for that combination of them. I'll make some assumptions and try to give you enough direction to get started. This will take a bit of explaining.
Starting from scratch, we've got a Contact template that has, at least, a Country and Department field. You'll need templates and lists of items for each of those two fields. You could get these values from another source, but let's just keep it simple for now and use lists of items. This sounds hierarchical, so I'd suggest you define your departments as children of your Country items. What other fields are on these items doesn't really matter at the moment.
Next, you'll want to communicate the end-user's selections back to your Sitecore instance. I'll assume that you're using Sitecore MVC, but the same principles apply for web forms.
Set up a controller to parse your parameters, country and department, and a form in your View with <select> elements populated from the lists of countries and departments. When the country selector is changed, you can either reload the page with the value set as a request parameter or use AJAX to ask your controller directly. If you structure the model so that it doesn't rely on the rendering context, you can submit your form results to /api/sitecore/{controllername}/{actionname}?country={values}&department={values} and get the data that way. (If you want an example of the kind of JS you need to do this I can provide one.) You could disable or hide the Department <select> until this is selected so that users don't get confused, then use the same technique to also set the Department parameter/submit that value. Once those two values are in the request, you have enough information to get a list or single Contact and display that information, also using the same technique.
If you have a more specific question about a particular aspect of this process I'd be happy to explain.

Can I display datagridview on view like we do in forms? if yes then how?

I know some people suggesting to use JQuery or other Javascript libs. I am looking to use common gridview or similar. Just let you know this is my learning phase so it could be very basic question for advance users.
You can't (or at least shouldn't if it's even possible) use the actual WebForms controls in MVC. If this is indeed a learning experience for you, you'd be better off learning some new ways of doing these things.
At its simplest, if you just want to display a table of data then you would have that data as an object in your model. For example, if you want to have a table of Customers then your model might have a property such as:
public IEnumerable<Customer> Customers { get; set; }
Let's say for the sake of argument that a Customer has a Name and an Address property on it. Then in your view, you'd simply loop through those for your table:
#foreach (var customer in Model.Customers)
{
<tr>
<td>#customer.Name</td>
<td>#customer.Address</td>
</tr>
}
Starting from there, you can build more functionality appropriately. For example, maybe each record in the table needs to have a link to "edit" that Customer. Then you'd build a link to the corresponding edit action using perhaps a customer's ID property (again, for the sake of argument, assume there's one there):
#foreach (var customer in Model.Customers)
{
<tr>
<td>#customer.Name</td>
<td>#customer.Address</td>
<td>#Html.ActionLink("Edit", "Customers", "Edit", new { id = customer.ID }, null)</td>
</tr>
}
(There are different overloads of the ActionLink method you can use.)
As you build this, you will get a better understanding of how simple the client-side rendering of this really is (or should be) and find yourself generally more hands-on with your HTML than generally happens in WebForms. Continuing along this path, you'll find it becomes a lot easier to make use of some pretty powerful client-side plugins (there are a ton of jQuery plugins for tables, for example). Things like paging, sorting, etc. become a lot cleaner through either AJAX calls (which are trivial to write server-side in MVC) or through just rendering all of the data in the initial page load and paging/sorting/filtering client-side.
You might like to take a look at this question: grid controls for ASP.NET MVC?
It was closed as not constructive for being a request for recommendations, but there are certainly a lot of data grid options recommended there that you might like to check out.
But in short, ASP.NET MVC does not really share WebForms' design philosophy of dragging and dropping complex components - its philosophy is more aimed at "I know exactly what I want on my page, now I need to implement it". If that's not what you're after, you might be better sticking with WebForms.
HTML elements that show information to user or gather data from him/her can be categorized in simple and complex; simple elements like TextBox, ComboBox, etc. have HtmlHelper in ASP.NET MVC , so it is rational that developers seek for HtmlHelpers for complex elements like GridView; it's complex because it should have paging, filtering, grouping, etc. In my last project with ASP.NET MVC I needed to use one of them and I found two fantastic library:
Grid.Mvc
Telerik Extensions for ASP.NET MVC
Both of them are Open Source and efficient, but I prefer the first one because it's simple, well-designed and easy to configure.

How do I pass values from a database between pages in WPF?

I created an application that connects to an SDF database. The user is given a list of movies in a cinema. The user can select a movie and press an 'ok' button.
The user should then be presented with another datagrid which contains all the information of that movie.
I've tried passing the SelectedIndex between the two pages, it sends the SelectedIndex to the information page, but it won't assign it to the same SelectedIndex.
public Desc(int input_id)
{
InitializeComponent();
cinemaEntities = new cinema1.cinemaDBEntities();
movieViewSource = ((System.Windows.Data.CollectionViewSource)(this.FindResource("moviesViewSource")));
System.Data.Objects.ObjectQuery<cinema1.movie> moviesQuery = this.GetMovieQuery(cinemaEntities);
movieViewSource.Source = moviesQuery.Execute(System.Data.Objects.MergeOption.OverwriteChanges);
moviesListView.SelectedIndex = id;
What to do depends on the purpose of the software, but in any case I would recommend to spend a little more effort on the architecture of your software. As you want to use WPF, you should decide whether to go for a MVVM (Model-View-ViewModel) approach which is highly maintainable and has numerous advantages, but demands some time to get familiar with. The quick solution which is absoulutely fine for small or simple apllications is to code your GUI logic in the codebehind of your views and controls.
Anyway, I would create a model layer which mirrors your database data in according types (MovieDatabase has a Collection of Movies, etc. etc.). Then write an adapter to fill the model from the database.Then either use the model in your views - if you want to do it quickly - or write ViewModels to your Models (which is better) and use those in your views.
This being said, from the code you posted its hard to tell, what the problem is. Do you have a little bit more context? Why don't you pass the SelectedItem?
Why not just pass the Movie object to the second page? And then use .SelectedItem. Why does the second page need the whole list anyway if it is detail for just one movie?

Sending collection of items in ASP.NET MVC

I've got two classes in my MVC project Order and Product.
Because Product can be ordered many times and Order can have many products I've got third entity which is OrderedProduct. It joins those two entities in many-to-many relation.
Now what I'm trying to do is to let user to make an order by putting products from the drop down list to the box and then to save my order. Also client have to fill some fileds in the Order entity such as Address data etc. All I want is to have it all on one single page. User can add as many items from dropdown as he like, then he can add whole order.
To make it easier to visualize look at this picture:
Now the problem is how to implement such behaviour in my MVC app. Should I build a ViewModel that combines Order class and list of Product or use partial view for Product classes?
Also which is my main problem, how can I (in elegant way) retrieve the full list of chosen products or at least product id's in the controller after POST request? In this case how can I specify that what I'm sending is a collection of ids? It's simple to add one object, but what about whole collection?
This is the place when I do not fully understand asp.net MVC, so please give me some bright ideas ;) Greetings to you all, thanks in advice for all your answers!
The desired interface seems a bit confusing to me but here's how you can handle these things.. modify to your desire. I'm going to assume OrderedProduct is an object for ordering that contains a Product ID and a quantity and that you want to be able to modify them all at the same time.
Make Order your ViewModel. Given that it has a List<OrderedProduct> property called OrderedProducts:
Create a small editor control with a ViewModel of OrderedProduct. No form, just a textbox/dropdown/whatever bound to the product name property and a textbox bound to the product quantity. Important: put this control in views/shared/EditorTemplates and call it OrderedProduct.ascx.
Give your Order object a property called NewOrderedProduct of type OrderedProduct.
In the form for the Order view do: <%=Html.EditorFor(m=>m.OrderedProducts)%> this will give you an editable list current items in the order.
After that do: <%= Html.EditorFor(m=> m.NewOrderedProduct) %> this is where you can add new items.
Have the [POST] action take a type of Order.
Now when it submits if the NewOrderedProduct property is valid you can add it to the OrderedProducts list and redisplay. You can add as many as you want this way and they will all autobind.
Have a separate submit button in the form for submitting the order. Check for the existence of that button's name in the [POST] and submit all at one time.
This gets you a straight HTML working version. From there you can Ajaxify it if you want.
Edit
Updated to reflect the function of the OrderedProduct object and correct the type the post accepts

Categories