Map a complex MVC ViewModel in knockout - model-view-controller

I have a MVC view which contains observables and observablearrays. What is the proper way to map?
My MVC ViewModel looks similar to this:
public class CategorysEditViewModel
{
public Category Categorys { get; set; }
public IEnumerable<Expert> candidates { get; set; }
public IEnumerable<Expert> experts { get; set; }
}
public class Category
{
public int CategoryID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Policy { get; set; }
}
public class Expert
{
public int ExpertID { get; set; }
public int CategoryID { get; set; }
public string Name { get; set; }
public string ExpertGUID { get; set; }
}

Assuming the cshtml file is strongly typed to the CategorysEditViewModel, you can serialize the view model object to JSON and then use the ko.mapping tool to map it to a knockout viewmodel.
Check out this post: Best practice on passing Mvc Model to KnockoutJS

Related

Dynamic multi header column in Kendo MVC grid

I want to create a grid from the following model.
public class ProgramBreakdown
{
public string ProgramName{ get; set; }
public List<MonthwiseInfo> MonthwiseProgramInfo { get; set; }
}
public class MonthwiseInfo
{
public string Month { get; set; }
public int TotalUsers { get; set; }
public int ActiveUsers { get; set; }
public double ActivePerc{ get; set; }
}
Is there a way to dynamically add/define multi-header columns like shown in the image in Kendo MVC - server side or client side?

EmitMapper (Flattened to Hierarchical)

I'd like to map from a flattened object to a hierarchical object based on a simple naming convention. For example:
public class FlatObject {
public string Name__FirstName { get; set; }
public string Name__MiddleName { get; set; }
public string Name__LastName { get; set; }
}
public class HierarchicalObject {
public SubObject Name { get; set; }
}
public class SubObject {
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
}
The simple naming convention is the double-underscore within the FlattenedObject.
How would I accomplish this using EmitMapper?
EmitMapper cannot do this task without significant code changes.

scaffolding seems not to work properly

I created a new asp.net MVC3 application (internet application), and then I added a new model with 3 classes:
public class BizCard
{
[Required]
public string BizCardID { get; set; }
[Required]
public string Name { get; set; }
public string Address { get; set; }
public List<string> PhoneNumbers { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
public BizType type { get; set; }
public List<BizService> OfferedServices { get; set; }
public string Description { get; set; }
}
public class BizType
{
public int BizTypeID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public double Price { get; set; }
}
public class BizService
{
public int BizServiceID { get; set; }
public List<BizType> AllowedBizTypes { get; set; }
public string Name { get; set; }
}
After that, I created a new controller, using the template "Controller with read/write actions and views using entity framework", I set the Model class to be "BizCard" and the data context class to be a new class which is called "BizDB". I was expecting to get a new class named BizDB that inherits from DbContext and includes 3 instances of DbSet:
DbSet<BizCard>, DbSet<BizType>, DbSet<BizService>.
In spite of that, I get the class with only one:
DbSet<BizCard>.
Am I missing something?
You are doing this using EF Code First approach.
1. So, you have to create a context class which should inherit DbContext containing required models as DbSet
2. Build the solution. Otherwise it will not be displayed at controller creation
Then you can create the controller using necessary model and its dbcontext.

What is the proper sequence of method calls when using a multi layered architecture?

I have built a simple survey-tool using MVC 3 with only 1 layer (MVC). I regret this now. All my database access and mapping is handled in the controllers, and some other mapping classes.
I would like to switch over to using three layers:
Presentation (MVC)
Business Logic
Data / Persistence (EF)
I am using the Entity Framework to handle everything with the database. The entity framework creates it's own domain classes. Where should the mapping between the Models that MVC uses and the models that EF creates go?
If the mapping is in the business layer, is there a need for the Models folder in the MVC project?
A survey-question consists of the Question itself, Rows and Columns. Theese are the models that i use:
public class Question {
public int Question_ID { get; set; }
public Boolean Condition_Fullfilled;
[Required(ErrorMessage = "Dette felt er påkrævet")]
public String Question_Wording { get; set; }
public String Question_Type { get; set; }
[Required(ErrorMessage = "Dette felt er påkrævet")]
public String Question_Order { get; set; }
public String Left_scale { get; set; }
public String Right_scale { get; set; }
public int Scale_Length { get; set; }
public String Left_Scale_HelpText { get; set; }
public String Right_Scale_HelpText { get; set; }
public Boolean Visible { get; set; }
public Boolean IsAnswered { get; set; }
public String Question_HelpText { get; set; }
public int Category_ID { get; set; }
}
public class MatrixColumns
{
public int Column_ID { get; set; }
public int Column_Number { get; set; }
public String Column_Description { get; set; }
public Boolean IsAnswer { get; set; }
public int? Procent { get; set; }
public bool Delete { get; set; }
public bool Visible { get; set; }
public int? Numbers { get; set; }
public String Help_Text { get; set; }
}
public class MatrixRows
{
public bool Delete { get; set; }
public bool Visible { get; set; }
public int Row_Id { get; set; }
public String Row_Number { get; set; }
public String Row_Description { get; set; }
public String Special_Row_CSS { get; set; }
public String Help_Text { get; set; }
// Dette er summen af procenterne af alle kolonner i rækken
public int RowSum { get; set; }
}
All the data for theese models is retrieved in the Controller, based upon a QuestionID, and mapped to a ViewModel that looks like this:
public class ShowMatrixQuestionViewModel : Question
{
public Dictionary<MatrixRows, List<MatrixColumns>> columnrow { get; set; }
public List<MatrixColumns> columns { get; set; }
public List<MatrixRows> rows { get; set; }
public ShowMatrixQuestionViewModel()
{
columns = new List<MatrixColumns>();
rows = new List<MatrixRows>();
columnrow = new Dictionary<MatrixRows, List<MatrixColumns>>();
}
}
So when i want to send a ShowMatrixQuestionViewModel to a View from my Controller, what is the route i should take?
This is my suggestion:
-> Controller calls a method in the business layer called
public ShowMatrixViewModel GetQuestion(int QuestionID) {}
-> GetQuestion calls the following methods in the data layer:
public Question GetQuestion(int QuestionId) {}
public MatrixRows GetRows(int QuestionId) {}
public MatrixColumns GetColumns(int id) {}
-> Entity framework returns "pure" objects, which i want to map over to the ones i posted above
-> GetQuestion calls methods to map the EF models to my own models
-> Last GetQuestion calls a method that maps the Questions, Rows and Columns:
ShowMatrixQuestionViewModel model = MapShowMatrixQuestionViewModel(Question, MatrixRows, MatrixColumns)
return model;
Is this correct?
Thanks in advance
To answer the first part of your question:
"Where should the mapping between the Models that MVC uses and the models that EF creates go?"
The answer is that the models MVC uses are the models created by the EF. Your EF tool in the ASP.NET MVC project is either Linq to SQL Classes or the ADO.NET Entity Framework Model. You should create these inside the Models folder in your project and they provide your data / persistence (EF).

Asp.Net MVC3 - How create Dynamic DropDownList

I found many articles on this but still I don´t know how exactly to do this. I am trying to create my own blog engine, I have View for create article (I am using EF and Code first) and now I must fill number of category in which article should be add but I want to change it to dropdownlist with names of categories. My model looks this:
public class Article
{
public int ArticleID { get; set; }
[Required]
public string Title { get; set; }
[Required]
public int CategoryID { get; set; }
public DateTime Date { get; set; }
[Required()]
[DataType(DataType.MultilineText)]
[AllowHtml]
public string Text { get; set; }
public virtual Category Category { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
}
public class Category
{
public int CategoryID { get; set; }
[Required]
public string Name { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
I know I must use Enum (or I think) but I am not exactly sure how. I don´t know which tutorial from that I found is best for me.
Edit:
Thanks for your answers but I found something else. I am trying this:
This is my model:
public class Article
{
[Key]
public int ArticleID { get; set; }
[Display(Name = "Title")]
[StringLength(30, MinimumLength = 5)]
[Required]
public string Title { get; set; }
public DateTime Date { get; set; }
public int CategoryID { get; set; }
[Required()]
[DataType(DataType.MultilineText)]
[AllowHtml]
public string Text { get; set; }
public Category Category { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
public IEnumerable<Category> Categories { get; set; }
}
public class Category
{
[Key]
public int CategoryId { get; set; }
[Required]
public string CategoryName { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
This is my controller to create article:
public ActionResult Vytvorit()
{
IEnumerable<Category> categories = GetCaregories();
var view = View(new Article() { Categories = categories });
view.TempData.Add("Action", "Create");
return view;
}
private static IEnumerable<Category> GetCaregories()
{
IEnumerable<Category> categories;
using (BlogDBContext context = new BlogDBContext())
{
categories = (from one in context.Categories
orderby one.CategoryName
select one).ToList();
}
return categories;
}
private Category GetCategory(int categoryID)
{
return db.Categories.Find(categoryID);
}
//
// POST: /Clanky/Vytvorit
[HttpPost]
public ActionResult Vytvorit(Article newArticle)
{
try
{
if (newArticle.CategoryID > 0)
{
newArticle.Category = GetCategory(newArticle.CategoryID);
}
if (TryValidateModel(newArticle))
{
db.Articles.Add(newArticle);
db.SaveChanges();
return RedirectToAction("Index");
}
else
{
newArticle.Categories = GetCaregories();
var view = View(newArticle);
view.TempData.Add("Action", "Create");
return view;
}
}
catch
{
return View();
}
}
And this is part of my view:
#Html.DropDownListFor(model => model.CategoryID, new SelectList(Model.Categories,"CategoryID","CategoryName"))
#Html.ValidationMessageFor(model => model.CategoryID)
I have problem with NullReferenceExeption but I don´t know why. Can I do it this way? It looks very easy for me.
Your model seems quite strange. It contains properties such as CategoryID and Category which seem redundant. It also contains a SelectListItem collection property called Categories. So, is this a model or a view model? It looks quite messed up. Let's assume it's a model. In this case it would more likely look something like this:
public class Article
{
public int ArticleID { get; set; }
[Required]
public string Title { get; set; }
public DateTime Date { get; set; }
[Required()]
[DataType(DataType.MultilineText)]
[AllowHtml]
public string Text { get; set; }
public virtual Category Category { get; set; }
public IEnumerable<Category> Categories { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
}
public class Category
{
public int CategoryID { get; set; }
[Required]
public string Name { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
Now that the model is clear we could define a view model which will be passed to the view. A view model is a class which is specifically designed for the view. So depending on what you intend to put in this view you define it in this view model. So far you have talked only about a drop down, so let's do it:
public class ArticleViewModel
{
public int SelectedCategoryId { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
}
and then we have a controller:
public class ArticlesController: Controller
{
private readonly IArticlesRepository _repository;
public ArticlesController(IArticlesRepository repository)
{
_repository = repository;
}
public ActionResult Index()
{
Article article = _repository.GetArticle();
ArticleViewModel viewModel = Mapper.Map<Article, ArticleViewModel>(article);
return View(viewModel);
}
}
So the controller uses a repository to fetch the model, maps it to a view model (in this example I use AutoMapper) and passes the view model to the view which will take care of showing it:
#model AppName.Models.ArticleViewModel
#using (Html.BeginForm())
{
#Html.DropDownListFor(
x => x.SelectedCategoryId,
new SelectList(Model.Categories, "Value", "Text"),
"-- Select category --"
)
<input type="submit" value="OK" />
}
I have gone through this as well and I have to agree that at first it seems odd (In my explanation I'm assuming you want to select one category only, but the process is very similar for a multi select).
Basically you need to perform 3 steps:
1:
You need two properties on your viewmodel
One will hold the selected category id (required for postback) and the other will a SelectList with all possible categories:
public class Article
{
public int ArticleID { get; set; }
public int CategoryID { get; set; }
public SelectList Categories { get; set; }
}
2:
Also before passing the viewmodel on to the view you need to initialize the SelectList (Best practivce is to prepare as much as possible before passing a model into the view):
new SelectList(allCategories, "CategoryID", "Name", selectedCategoryID)
3:
In the view you need to add a ListBox for the CategoryID property, but using the Categories property too fill the ListBox with values:
#Html.ListBoxFor(model => model.CategoryID , Model.Categories)
Thats it! In the post back action of the controller you will have the CategoryID set. You can do whatever you need to from there to persist things in your db.

Resources