Generating views at runtime from a database table - c#

I have a technical question as to how I can generate Multiviews (views control) using MVC framework where the views are getting generated dynamically (get details from the DB).
As per asp.net the generation of the views (control) will need to be placed in PreInit or Load events of the page. Need some technical guidance on how to go ahead.
Or is it good practice to use again the question is how to. Any other alternate solution is also welcome..

You should probably try something like this:
Generating ASP.NET MVC View Controls According to XML Configurations
The data source is XML, but that doesn't matter; you should be able to adapt the technique to a database table containing the view metadata.
The "meta-view" code for an editor form would look something like this:
#model DynamicControlsCreation.ViewModels.DefaultControlsViewModel
<p>
#using (Html.BeginForm())
{
for (int i = 0; i < Model.Controls.Count; i++)
{
<div>
#Html.HiddenFor(x => x.Controls[i].Type)
#Html.HiddenFor(x => x.Controls[i].Name)
#Html.EditorFor(x => x.Controls[i])
</div>
}
<input type="submit" value="Submit" />
}
</p>
Note that you don't get much "shape" when you generate a view in this manner; it's mostly useful for things like configuration forms. Although you can put metadata in the database like the locations of the controls on the page, by the time you do all that, you're probably better off just making conventional views.

Related

How can I get the number of existing HTML elements from code before rendering them

I'm currently trying to figure out how I can filter some HTML elements inside my code.
Basically I have some div containers which each contain some stuff I want to display.
But I only want to display a set amount (e.g. 1 or 3) of those containers which will be chosen at random.
I basically have the logic for choosing them at random already in the code.
The problem I have is that I need to somehow get the amount of containers I actually have to choose from them.
I don't want to depend on the ability of other people who work on the same code to actually update the number of containers manually when they add or delete one.
The containers are in a file looking something like this:
<div id="mainContainer">
<div id="element1">
//first container
</dev>
<div id="element2">
//second container
</dev>
<div id="element3">
//third container
</dev>
</div>
I want to get the number of those element from the code so I can filter them before the rendering of the website.
I could do the filtering by using TypeScript or JavaScript but for that I would need to load all the containers first which I want to prevent because of performance/user experience.
Is there any possibility to get like a list of all the containers or something like that?
I would really appreciate some help here :)
To the best of my knowledge you cant 'read' the DOM from within a Razor view so what you need is a different way of approaching the problem. How about something like this, which follows your current Razor layout quite closely;
#{
List<string> elementsToRender = new List<string>(5) { "element1", "element3" };
}
<div id="mainContainer">
#if (elementsToRender.Contains("element1", StringComparer.OrdinalIgnoreCase))
{
<div id="element1">
#* first container *#
</div>
}
#if (elementsToRender.Contains("element2", StringComparer.OrdinalIgnoreCase))
{
<div id="element2">
#* second container *#
</div>
}
#if (elementsToRender.Contains("element3", StringComparer.OrdinalIgnoreCase))
{
<div id="element3">
#* third container *#
</div>
}
</div>
You can still let other developers add and maintain the elements, all they need to do is make sure each one has a unique key in the elementsToRender.Contains test. For simplicity I've used the element wrapper div Id but it doesn't have to be. Then you can control which elements are shown by choosing which keys you add to elementsToRender .
You could move the population of elementsToRender into a ViewModel then populate it dynamically based on whatever logic you want.
Taking a different approach to the problem, how about putting the markup for each element into a separate partial view in a known folder. You could then scan the files in the known folder and pick which ones/how many to render into the actual page using #Html.RenderPartial.

ASP.Net MVC C# - Incorrect Html Display when visiting a page multiple times caused by CSS

I have created a basic ASP.NET MVC project. I have an index view with a form and a simple label and text box and a submit button (see code below). With the header on the page from the project I can move between multiple pages (about or contacts or home) this is a default project created in VS2012.
When I return to the index page I get what you see in this image:
When it should look like this:
Which is also what I see the first time I visit the page.
What am I doing wrong?
The view looks like this:
<div>
#using (Html.BeginForm("Details","Citizen"))
{
#Html.LabelFor(m => m.ID)
#Html.TextBoxFor(m => m.ID)
<input type="submit" value="Details" />
}
</div>
EDIT: I am using multiple CSS files, the standard that VS creates plus the jquery.moblile-1.4.5 which I'm using for a collapsible list. This looks to be causing it

Is there a way to integrate Tag Helpers into MVC CodeTemplates?

I have just gotten started with ASP.NET MVC 5 (C#) and have been a little confused by the HTML helpers.
#using (Html.BeginForm("Add", "Song"))
I understand how this can be helpful, but feel that for people who do not know Razor/C#, that this will be a steep learning curve if not properly exposed. I am also aware of the Tag Helpers that are available and like what I see so far.
<form asp-action="Add" asp-controller="Song">
To me, this seems more appropriate, as it means that people who do not understand Razor syntax will be able to more easily read and understand what is happening, as it bears much more similarity to "normal" HTML. That being said, changing each page to use Tag Helpers seems monotonous and unnecessary.
I have recently found the CodeTemplate files, and included them in my project with the intention of adding the Tag Helpers in the template files. However, I soon realized that most Tag Helpers need a specific Controller or whatever to fill out the element attributes. Obviously, this Controller/whatever will change dynamically depending on which Controller/whatever prompted the creation of the View. If I hardcode asp-controller="Song" and then I try to create an Album View from this CodeTemplate, I obviously will have used the wrong controller.
Is there a way to access the dynamic property of whatever Controller, Link, etc called the View? In other words, is there someway of doing this in the CodeTemplate, where This is the Controller/whatever that constructs the View from the modified CodeTemplate?
<form asp-action="This.Action" asp-controller="This.Controller">
Example:
If I had <form asp-action="This.Action" asp-controller="This.Controller"> in my CodeTemplate in all Views, and then created the Views from different Controllers:
Song Controller
Create View - <form asp-action="Add" asp-controller="Song">
Update View - <form asp-action="Edit" asp-controller="Song">
Album Controller
Create View - <form asp-action="Add" asp-controller="Album">
Update View - <form asp-action="Edit" asp-controller="Album">
Is this possible at all? Or am I completely off? Let me know! Thanks!
You can try the solution I found here.
<form asp-controller="#this.ViewContext.RouteData.Values["controller"].ToString())"
asp-action="#this.ViewContext.RouteData.Values["action"].ToString())">

Where should calculations be done in MVC?

I need to perform some conversion calculations on data I am pulling from an SQL server. It seems like the best place to do it is in the view while I am looping through the collection, but I am not sure if that is best practice or not. Also, I am not sure how to go about doing it in the view.
I am still relatively new to this and slowly learning, so I am not even sure of the syntax to accomplish what I am trying to do.
As always any and all help is greatly appreciated.
<div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
#foreach (var item in Model.OR_OP)
{
<div class="panel panel-default">
#Html.Raw("<div class=\"panel-heading\" role=\"tab\" id=\"heading")#Html.DisplayFor(modelitem => item.NAME)#Html.Raw("\">")
<h4 class="panel-title">
#Html.Raw("<a data-toggle=\"collapse\" data-parent=\"#accordion\" href=\"#collapse")#Html.DisplayFor(modelitem => item.NAME)#Html.Raw("\" aria-expanded=\"true\" aria-controls=\"collapse")#Html.DisplayFor(modelitem => item.NAME)#Html.Raw("\">")
#Html.DisplayFor(modelitem => item.NAME)
-
#Html.DisplayFor(modelitem => item.DESCR)
#Html.Raw("</a>")
</h4>
<div>
<div class="btn-custom-start">Start</div>
</div>
<div>
<div class="btn-custom-stop">Stop</div>
</div>
#Html.Raw("</div>")
#Html.Raw("<div id=\"collapse")#Html.DisplayFor(modelitem => item.NAME)#Html.Raw("\" class=\"panel-collapse collapse collapse\" role=\"tabpanel\" aria-labelledby=\"heading")#Html.DisplayFor(modelitem => item.NAME)#Html.Raw("\">")
<div class="panel-body">
#Html.DisplayFor(modelitem => item.PWPLACE)
#Html.DisplayFor(modelitem => item.PPARTS)
#Math(item.PTE.Value/60) <------ this is where I would like to do the calculation.
#Html.DisplayFor(modelitem => item.PTE)
#Html.DisplayFor(modelitem => item.PTR)
</div>
#Html.Raw("</div> ")
</div>
}
</div>
Any logic type operations should really be done in the Controller. Then the result should be saved to a View Model by Controller. That Model should be used in the View so you can display the result of some sort of operation you performed on data. The idea is that the Controller changes the View Model and if appropriate the Entity Model.
The View Model in the Controller should be set based on your Entity Model if you have one. If you are using DDD, then a lot of the Controller's logic should sit in the Domain Models, the logic which is appropriate to the domain of course, e.g. Calculations.
So looks like you are using Entity Framework. If you read on the page that you linked at the top:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
I think your models get generated from the Q-MakModel.Context.tt file. Make sure that the Context file contains those two properties, because every time EF regenerates the model, it will remove those properties if they are not present in the template. Another thing to consider, I wouldn't use an Entity Model in the UI View. I would use a custom View Model
Then in the Controller map the View Modelto the Entity Model and do a save. When you load the View, because of MVC the Controller loads first so you map the Entity Model to the View Model and return that to the view.
This will protect your Entity so you don't save garbage in the database.
In the View Model I would only put things which are relevant for that View.
I have added this into an answer just because it's too long to comment above.
Let me know how you get on, it's definitely EF deleting those 2 properties.
In this case you can do calculation in Model. I recommend you add a property in your Model class something like:
public PropertyName
{
get
{
return #Math(this.PTE.Value/60);
}
}

MVC: Dynamically create new element from template

I have an MVC app. Some elements are rather complex, so I created a template for them.
I use them calling #Html.EditorFor(). The problem is that I need a possibility to create such elements dynamically, I mean after clicking on a button 'Create New' I want to generate an empty template and let user to fill it. I can use mustache template engine or smth like this, but in this case I need to duplicate my html - in razor template and in html. I don't want to repeat myself, what is the best way to achieve this?
Another problem is that when I generate view for IEnumerable<> - razor created proper names for elements with proper indexes. In a case I want to create new element - how should I set these indexes to let binder properly work on POST? Is there is a better solution than using jQuery for this?
Thanx in advance.
UPDATE:
Here is an editor template:
#model FakeViewModel
<li>
<div>
<h3><span>#Model.Title</span><span class="icon-remove"></span><span class="icon-move"></span></h3>
<div>
#Html.HiddenFor(m => m.Id)
#Html.HiddenFor(mp => mp.Category)
<div>
<span class="font-small">Title</span>
</div>
<div>#Html.TextBoxFor(m => m.Title, new { #maxlength = FakeViewModel.MaxTitleLength, #class = "title-textbox" })</div>
<div>
#Html.TextAreaFor(m => m.Description, new { #placeholder = "short description", #data_max_length = "90" })
</div>
</div>
</div>
</li>
This is how I render it, "Special" is a type of IEnumerable<FakeViewModel>
<ul class="container" id="special">
#Html.EditorFor(m => m.Special)
</ul>
So, after rendering this I have got a layout with correct names, I mean Special[0].Id, Speacial[0].Category, etc.
Now, I want to create an empty template. For now I am using mustache template, it should have the same layout as editor template:
<script type="text/template">
<input name="Special[{{itemIndex}}].Category"
</script>
The problem is, that I use the same layout in two different places - in mustache template as well as in razor editor template.
If I need to change this layout - I need to change it in two places. I want to avoid this.
Another problem is that I need hardcode names ("Speacial" in this example) and manually put index, category and etc.
Whatever solution you use, JavaScript will be required. jQuery is just a JavaScript framework, so you could switch it out with something else, if you preferred, but you should stick with some sort or JavaScript framework, as the code for doing XMLHttpRequest cross-browser is tedious and prone to error.
As for your HTML, you can choose to either include it as a template on page load or request it fresh via an AJAX request. Personally, I'd go with a template because AJAX doesn't really buy you anything in this scenario, and it's just an extra request.
Either way, you're unfortunately not going to be able to use the Razor HtmlHelper methods, at least without mangling the HTML afterwards via JavaScript anyways; they simply won't generate the proper naming convention required for binding list objects outside of a for loop. The model-binding convention is easy to replicate manually, though, it's just:
YourCollection[N].FieldName
So if you had a list of Cars on your model and you wanted a field to edit the Color of the 3rd car, you would use:
Cars[2].Color
Any good JavaScript templating solution should be able to automatically insert the N value based on the object's position in the list of other objects.
You can use a string builder to dynamically create the html in the get method of your controller and then post that to the view. The other way is to create your own htmlhelper.
Partialview is the solution:
you can create a partial view and have it added every time you want it to be used or injected into the view. you can run a for or foreach look on that partial view and have it repeat as many times as you want.
1: create a partialview.
2: put everything you want to be rendered 2 times in the partial view.
3: replace the view code with partial view. like:
#html.Partial("~/views/partials/_samplename.cshtml")
you can repeat this partial view anywhere in the project and by changing anything in the partialview it would change everywhere.

Categories

Resources