I have a number of inputs on my page. I would like to save the changes to the model on the input blur, so as I change the value of each input it gets saved back to server, like Google contacts.
<input id="FirstName" name="FirstName">Jack</input>
I create a blur event using jquery to post the value back to the server. It posts a structure with the name of the input, the value and an id of the entity.
$.post(url, { id: "2", key: "FirstName", value: "Jack" }, successFuction);
In my controller I have:
public ActionResult EditField(int id, string key, string value)
I then retrieve the entity using EntityFramework with the id. I then wanted to update the property on the model for the field.
var entity = _db.Get(id);
entity[key] = value;
return Content "Success";
Which I obviously can't do! The only way I can think off is multiple methods for each field so EditName, EditAddress etc. which seems wrong. I want this method to be able to handle each property of the model.
What is a better way to structure the controller instead of writing multiple methods for each individual field?
You could post your entire form (e.g. first name, last name, etc.) on each blur for any of your fields (this should be fine since you're saving all changes as the user progresses on the form anyway). Unless you're really trying to save bytes, posting the whole form seems fine.
You could just post the field name and then use reflection to look up the property of your object and set the value.
I think that you can do it if you are willing to model the entity in a general way:
public class FieldEntity {
public int Id { get; set; }
public string Key { get; set; }
public string Value { get; set; }
}
Then use it inside the context like:
var fieldEntity = db.Find(id);
fieldEntity.Key = key;
fieldEntity.Value = value;
db.SaveChanges();
However, it is usually better to structure data in a way that is meaningful. In the example you describe it looks like you might have a Person and Address entity. So why not have a Person entity that has a property Address?
Related
I am having trouble passing a property value from one model to another,
I have a property referenced in the OrderTotalsModel here:
public string OrderTotal { get; set; }
I need that to show in the popUpOrderSummary View which uses the ShoppingCartModel,
I have created a property in this model:
public string popUpOrderTotal { get; set; }
I am aware that i need to pass the value of this property from the OrderTotalsModel to the ShoppingCartModel by using the ShoppingCartController,
I have so far added this code below the PrepareShoppingCartModel method:
model.popUpOrderTotal =
I have tried:
model.popUpOrderTotal = OrderTotalsModel.OrderTotal;
If you need to use the same value in 2 models, you need to retrieve it from the same place.
If you are setting the value for OrderTotal in your controller, set it in the same way for the ShoppingCartModel e.g. by retrieving it from the database or calculating it.
If the value is set or updated in a view, this value needs to be posted back to an action where you can either save it for later use, or use it immediately to display another view such as your shopping cart.
I am having trouble understanding and implementing a view model. For example, say I have a Blog object, where each Blog object represents one blog post. I have a view that contains a list of each blog (title, text, date posted, etc...). Currently I am passing a list of blog objects to the view, but I would rather pass a list of BlogViewModel objects to the view. How do I do it? Does anyone have any good resources that will help me understand View Models?
Edit
The BlogViewModel I want to pass will contain abbreviated fields for the title and the text of the Blog. For example, I only want to show the first 10 characters of the title and the first 25 characters of the text.
Assuming you are currently doing something like:
public ActionResult GetBlogs()
{
var someService = new FooService();
var blogs = someService.GetMeMyBlogs();
return View("bloglist", blogs);
}
To use view models you need to either return them from your service, or convert the objects in the controller before sending them on to the view.
One option is to create an extension method for the Blog object.
Say we have a few properties something like:
public class BlogVM
{
public string Title {get;set;}
public string Body {get;set;}
public string AuthorName {get;set;}
public int Id {get;set;}
}
We could write an extension method:
public static BlogVM ToBlogVM(this Blog source)
{
return new BlogVM
{
Title = source.Title.SubString(0, 10),
Body = source.Body.SubString(0, 25),
AuthorName = source.Author.Name,//assuming you have some kind of Author table, I'm sure you get the idea..
Id = source.Id
};
}
Now in your controller you can do something like
public ActionResult GetBlogs()
{
var someService = new FooService();
var blogs = someService.GetMeMyBlogs();
return View("bloglist", blogs.Select(x => x.ToBlogVM()));
}
Which passes a list of BlogVM objects to your view.
edit: probably worth adding a few words on why ViewModels.
why send the view everything if it doesn't need it? In your example, your body might be a big block of text. If you are only going to display 25 chars, only send it 25 chars
some of the info in the object might be sensitive. You might want to send the Author's name, but certainly not other information you might hold such as his name, email or even password or address.
similarly, in a POST scenario you can control what information can potentially be sent back to you. If you allow the user to POST back to a full object, they can potentially send you back updated fields you might not expect. If you use a VM, you can control what information you will accept.
I find it easier/quicker for building views
I am trying to build a helper class for Datatables and need some advice.
I want to create a helper that I can pass in an object that represents the settings for a DataTables that is typed by a specific model. This object would contain a collection of expressions that represent the columns to be used by the helper. As part of the DataTables object there will be a property that holds the URL that servers up the data for the grid. This will effectively be the sAjaxSource parameter. As part of the URL call, a JSON package will be sent that will contains the information about the columns. This whole section, I understand how to build. Basically, I would build out the DataTables JavaScript code including column definitions and create a JSON object that represents the columns I want to pass in the URL.
The area I needs some advice on is building the data for the specific columns once hte call is made to the server / controller. So my controller may look like this:
public ActionResult GetUsersList(IEnumerable<DatatableColumnJson> columns)
{
var users = _someUserRepository.GetAll();
foreach (var user in users)
{
//Here I would build the JSON that DataTables needs to render the grid.
//I would iterate through the users and pull out the data for the specific columns
}
return Json(someCompleteDataTablesObject, JsonRequestBehavior.AllowGet);
}
Supporting Classes:
public class DatatableColumnJson
{
public string Name { get; set; }
public string Visible { get; set; }
}
public class User
{
public string UserName { get; set; }
public string Email { get; set; }
}
So I first thought I could use reflection, but that seems to be a little intensive, maybe. Another thought was to transform the column names into expressions to possibly pull out the data. I want something efficient and that doesn't have a lot of overhead, but maybe I am asking too much.
I am using ASP.Net MVC 3 and I need to create a single drop down list which contains items that relate to multiple database tables.
Normally, if I need to do a drop down list for a single data type I can easily use the ID as the "value" for each drop down option and would do something like this:
#Html.DropDownListFor(x => x.SelectedID, Model.GetMyList())
But now I want to mix up multiple data types. So lets say for this example I want to create a single list to represent something like "Owner" and this can be either a "User" or a "Customer". In this example, both User and Customer are separate database tables and therefore the ID value alone is not enough to identify them correctly.
So what are the best ways to achieve such functionality?
Straight off the top of my head, my first thoughts are to create a "custom" value string which could then be parsed server side to work out the ID and data type, something like...
"USER|1"
"CUSTOMER|1"
I know I can make this work, but am I making this more complicated than it needs to be? Is there a built-in or advised way of doing this?
In your Model can you not do something like this:-
public class Model
{
public string Owner { get; set; }
public List<MyList> ListCollection { get; set; }
public class MyList
{
public int Id { get; set; }
public string Value { get; set; }
}
}
So then when you are checking which list item is selected you also have access to the "Owner" field which will tell you what table it belongs to ?
As nobody has come up with anything better, I can confirm that my original idea (as unwanted as it was) did the job.
When setting the value of the select options, a custom string should be created that can easily be parsed server side, this was achieved using a pipe separating the TYPE of entity, and the ID, for example:
"USER|1"
"USER|2"
"CUSTOMER|1"
"CUSTOMER|2"
Once the selected value is passed to the server, it can then be parsed something like the following:
string option = "USER|1";
string[] values = option.Split('|');
string entityType = values[0];
int entityId = Int.Parse(values[1]);
which can then be used something like this:
if(entityType == "USER")
UpdateUser(entityId);
else//CUSTOMER
UpdateCustomer(entityId);
I've currently got an issue where I need to see which fields have been changed on an Edit field for auditing purposes, in which I have code for, but I think my problem lies within my MVC View.
I have (test code):
[HttpPost]
public ActionResult Adjustment(GroupPolicy groupPolicy)
{
if (ModelState.IsValid)
{
_service.SaveGroupPolicy(groupPolicy);
return RedirectToAction("Index");
}
return View(groupPolicy);
}
Which is fine, the Policy saves. However, take this into consideration:
GroupPolicy has, say, 3 fields (in reality there are, maybe, 60):
bool IsPolicy
string Name
string Description
Name and Description are on the form, so that's fine. IsPolicy isn't used on the form, so that gets defaulted to false when posted back to the GroupPolicy object in the Adjustment method.
I can't really put IsPolicy in a Hidden field on the form, as that won't be elegant for 60+ fields in my actual solution, the HTML would be all over the place.
Now that the bool is defaulted to false, it completely abolishes the chance of me knowing if the field has changed or not. All I really want is a method for this data to be preserved, whilst keeping the new information on the Edit form.
Is this possible, am I missing something obvious?
Well first of all, GroupPolicy should be a view model and not an entity - and as such it should be tailored for the view e.g.
public class GroupPolicyViewModel
{
[HiddenInput]
public Guid Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
...
}
Then in your action you don't need to worry about assigning values that have changed, you just map the view model directly across e.g.
public ActionList Adjustment(GroupPolicyViewModel viewModel)
{
if (ModelState.IsValid)
{
// pull actual entity from service
var groupPolicy = _service.GetGroupPolicy(viewModel.Id);
// update entity from view model
groupPolicy.Name = viewModel.Name;
groupPolicy.Description = viewModel.Description;
...
}
}
This keeps a clean separation between your view & business logic. Also, it allows you to add annotations for client-side validation without affecting your real model.
GroupPolicy has, say, 3 fields (in reality there are, maybe, 60)
I would recommend using AutoMapper for this e.g.
// call this once only e.g. Application_Start in the Global.asax
Mapper.CreateMap<GroupPolicyViewModel, GroupPolicy>();
...
// in your Adjustment action
var groupPolicy = _service.GetGroupPolicy(viewModel.Id);
groupPolicy = Mapper.Map<GroupPolicyViewModel, GroupPolicy>(viewModel, groupPolicy);
_service.SaveGroupPolicy(groupPolicy);
If IsPolicy not on the form then it shouldn't even be part of your model - this will prevent posting of this field into your model and so your check won't even be needed for IsPolicy.
Rather than accepting GroupPolicy as the parameter into the action, create a cut down object GroupPolicyInputModel with only fields that are on the form.
Then use your generic auditing to only compare all the posted fields, as per any other form.