I'm trying to do a straight forward data bind that involved two domain classes in a one to one association. Here's the two classes:
class Request
{
static hasOne = [form: Form]
Form form
}
class Form
{
static belongsTo = [request: Request]
String string
}
I then do the following data binding (this is to demonstrate the problem ... the real data bind comes from a form):
Request request = new Request()
request.properties = ['form.string': 'string value']
However, I end up with a Request object that has a null form property instead of a Request object that has a Form object for its form property along with the string value.
Try with this
class Request
{
Form form
}
class Form
{
static belongsTo = [request: Request]
String string
}
Turns out the problem wasn't with the actual classes, but the map being passed to the data binding. Even though according to the Grails documentation the following should have worked:
Request request = new Request()
request.properties = ['form.string': 'string value']
it doesn't. However, if I change the map to be I get proper binding:
Request request = new Request()
request.properties = [form: [string: 'string value']]
Related
So in my mvc 5 app, I got this default 'Index' action, which simply redirects to the search action, with the default model values:
[Route]
public ActionResult Index()
{
var model = new T();
return RedirectToAction("Search", model);
}
What i got puzzled about is how i end up with the url like '.../search?xxx=xxx...'? Is there anything i can do to customize or at least inject/replace the url generation, especially the query string part? e.g. i might want to display 1/0 for bool properties in the search model, and customize query string key names etc?
and why would someone vote down for my question? psst...
The query string generated depend on the model property name and type + value you passed in.
For example, say if your pass in model is like
public class MyModel
{
bool IsSort{get;set;}
}
If your model is like this and IsSort value is true, then you will get url like /search?IsSort=true
Say you want to change your query string to 1/0 instead of true or false, then create viewModel which has property string then assing it properly like:
public class MyModel
{
string IsSort{get;set;}
}
var model = new MyModel();
model.IsSort = true? "1":"0";
same apply to querystring key (which correspond to property name)
I have a working OData implementation with routes setup in the typical way:
var builder = new ODataConventionModelBuilder();
builder.EntitySet<Person>("People");
configuration.Routes.MapODataRoute(routeName:"OData", routePrefix:"odata", model:builder.GetEdmModel());
I'm looking for a way to programatically generate an absolute URL for a registered entity set from outside of any OData action. For example, I want to request the OData endpoint for the Person type and get back "http://host/odata/People".
The standard URL helpers don't seem to apply since the OData routing is convention-based.
You may want to leverage the IEdmModel instance generated by the ODataConventionModelBuilder.GetEdmModel().
IEdmModel model = builder.GetEdmModel(); // the builder is what you defined in the question.
var entitySetName = "";
foreach (var temp in model.FindEntityContainer("Container").EntitySets())
{
if (temp.ElementType.Name == "Person")
{
entitySetName = temp.Name;
break;
}
}
return "http://host/odata/"+entitySetName;
Note: if you define more than one entity set for an entity type, the upper code only returns the first one.
I am trying to reuse the same form for adding and editing employee information. I am using knockout js and on my view I make the knockout model:
var koModel = new EmployeeModel(div);
and if I want to populate the fields from the server I want to do something like this:
var koModel = new EmployeeModel(unserializedModelFromController, div);
I was wondering what is the best way to distinguish if the request is for a new employee or if it is to edit an existing employee.
If you turn your parameters around you can write a single constructor function.
var EmployeeModel = function(div, model) {
if (model) {
// Existing model has been passed, it's an edit request
} else {
// No model has been passed, it's a new request
}
}
This can be called like:
new EmployeeModel(div);
or
new EmployeeModel(div, model);
You can send a parameter with a default value to the view.
If you are editing an employee, you can send the value of id, you're creating not send.
The function that receives a request to store or edit could have a default value.
public void SaveOrEditEmployee(int id=0, ...) //id=0 is a default value
{
if(id==0)
{
//SaveEmployee
}else
{
//EditEmployee
Employee empl = (x => employee.id == id);
...
}
}
Or you can do likewise, receive full model and assess whether the property 'id' already exists in your database
First post time,
I've been playing around with MVC abit... I have a view which has multiple input fields, some of these fields can be blank on post.
The action method inside the controller for the post looks something like this
public ActionResult Filter(int? id, string firstName, string lastName, bool? isMember)
I've been using the DynamicQuery extension which has been kicking around in order to perform dynamic Linq querys on my database and I've encapsulated this in a Search object which is passed to the data access layer for execusion.
However, I also have a customized ViewData object which is passed back to the view for displaying the input values and the results of the query.
It all looks a little nasty in code as I'm having to set both the Search object properties AND the ViewDatas.
public ActionResult Filter(int? id, string firstName, string lastName, bool? isMember) {
var search = new Search {
Id = id,
FirstName = firstName,
LastName = lastName,
Member = isMember
};
var memberViewData = new MemberViewData {
Id = id,
FirstName = firstName,
LastName = lastName,
Member = isMember
};
memberViewData.Results = _dataRepository.GetMember(search);
return View("Search", memberViewData);
}
Am I over thinking this and really should just pass the values to the data access layer and populate the ViewData in the controller, or is there a much more elegant pattern or practise I could use?
Sorry if this seems dump, not allot of people to bounce ideas off and time to dig into the framework.
Use modelbinder to bind data
According to your snippet MemberViewData class has the Results property in addition to properties of Search class. So first step would be to make MemberViewData derive from Search and define a constructor that accepts Search instance as parameter and assigns it's basic properties from it. Next I would change the action method like so:
public ActionResult Filter(Search search)
{
return View("Search", new MemberViewData(search)
{
Results = _dataRepository.GetMember(search)
});
}
Like Tadeusz mentioned, a ModelBinder can help build the MemberViewData for you, which would leave only the results to be fetched.
You could also decide on creating a presentation service that understands how to build this view data object and simply delegate to it. I'd prefer the model binder approach here though.
I have a complex JSON object which is sent to the View without any issues (as shown below) but I cannot work out how Serialize this data back to a .NET object when it is passed back to the controller through an AJAX call. Details of the various parts are below.
var ObjectA = {
"Name": 1,
"Starting": new Date(1221644506800),
"Timeline": [
{
"StartTime": new Date(1221644506800),
"GoesFor": 200
}
,
{
"StartTime": new Date(1221644506800),
"GoesFor": 100
}
]
};
I am not sure how this object can be passed to a Controller Method, I have this method below where the Timelines object mirrors the above JS object using Properties.
public JsonResult Save(Timelines person)
The jQuery I am using is:
var encoded = $.toJSON(SessionSchedule);
$.ajax({
url: "/Timeline/Save",
type: "POST",
dataType: 'json',
data: encoded,
contentType: "application/json; charset=utf-8",
beforeSend: function() { $("#saveStatus").html("Saving").show(); },
success: function(result) {
alert(result.Result);
$("#saveStatus").html(result.Result).show();
}
});
I have seen this question which is similar, but not quite the same as I am not using a forms to manipulate the data.
How to pass complex type using json to ASP.NET MVC controller
I have also seen references to using a 'JsonFilter' to manually deserialize the JSON, but was wondering if there is a way to do it nativly though ASP.NET MVC? Or what are the best practices for passing data in this way?
Edit:
This method should no longer be needed with the arrival of MVC 3, as it will be handled automatically - http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net-mvc-3-preview-1.aspx
You can use this ObjectFilter:
public class ObjectFilter : ActionFilterAttribute {
public string Param { get; set; }
public Type RootType { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext) {
if ((filterContext.HttpContext.Request.ContentType ?? string.Empty).Contains("application/json")) {
object o =
new DataContractJsonSerializer(RootType).ReadObject(filterContext.HttpContext.Request.InputStream);
filterContext.ActionParameters[Param] = o;
}
}
}
You can then apply it to your controller methods like so:
[ObjectFilter(Param = "postdata", RootType = typeof(ObjectToSerializeTo))]
public JsonResult ControllerMethod(ObjectToSerializeTo postdata) { ... }
So basically, if the content type of the post is "application/json" this will spring into action and will map the values to the object of type you specify.
You say "I am not using a forms to manipulate the data." But you are doing a POST. Therefore, you are, in fact, using a form, even if it's empty.
$.ajax's dataType tells jQuery what type the server will return, not what you are passing. POST can only pass a form. jQuery will convert data to key/value pairs and pass it as a query string. From the docs:
Data to be sent to the server. It is
converted to a query string, if not
already a string. It's appended to the
url for GET-requests. See processData
option to prevent this automatic
processing. Object must be Key/Value
pairs. If value is an Array, jQuery
serializes multiple values with same
key i.e. {foo:["bar1", "bar2"]}
becomes '&foo=bar1&foo=bar2'.
Therefore:
You aren't passing JSON to the server. You're passing JSON to jQuery.
Model binding happens in the same way it happens in any other case.
A different take with a simple jQuery plugin
Even though answers to this question are long overdue, but I'm still posting a nice solution that I came with some time ago and makes it really simple to send complex JSON to Asp.net MVC controller actions so they are model bound to whatever strong type parameters.
This plugin supports dates just as well, so they get converted to their DateTime counterpart without a problem.
You can find all the details in my blog post where I examine the problem and provide code necessary to accomplish this.
All you have to do is to use this plugin on the client side. An Ajax request would look like this:
$.ajax({
type: "POST",
url: "SomeURL",
data: $.toDictionary(yourComplexJSONobject),
success: function() { ... },
error: function() { ... }
});
But this is just part of the whole problem. Now we are able to post complex JSON back to server, but since it will be model bound to a complex type that may have validation attributes on properties things may fail at that point. I've got a solution for it as well. My solution takes advantage of jQuery Ajax functionality where results can be successful or erroneous (just as shown in the upper code). So when validation would fail, error function would get called as it's supposed to be.
There is the JavaScriptSerializer class you can use too. That will let you deserialize the json to a .NET object. There's a generic Deserialize<T>, though you will need the .NET object to have a similar signature as the javascript one. Additionally there is also a DeserializeObject method that just makes a plain object. You can then use reflection to get at the properties you need.
If your controller takes a FormCollection, and you didn't add anything else to the data the json should be in form[0]:
public ActionResult Save(FormCollection forms) {
string json = forms[0];
// do your thing here.
}
This answer is a follow up to DaRKoN_'s answer that utilized the object filter:
[ObjectFilter(Param = "postdata", RootType = typeof(ObjectToSerializeTo))]
public JsonResult ControllerMethod(ObjectToSerializeTo postdata) { ... }
I was having a problem figuring out how to send multiple parameters to an action method and have one of them be the json object and the other be a plain string. I'm new to MVC and I had just forgotten that I already solved this problem with non-ajaxed views.
What I would do if I needed, say, two different objects on a view. I would create a ViewModel class. So say I needed the person object and the address object, I would do the following:
public class SomeViewModel()
{
public Person Person { get; set; }
public Address Address { get; set; }
}
Then I would bind the view to SomeViewModel. You can do the same thing with JSON.
[ObjectFilter(Param = "jsonViewModel", RootType = typeof(JsonViewModel))] // Don't forget to add the object filter class in DaRKoN_'s answer.
public JsonResult doJsonStuff(JsonViewModel jsonViewModel)
{
Person p = jsonViewModel.Person;
Address a = jsonViewModel.Address;
// Do stuff
jsonViewModel.Person = p;
jsonViewModel.Address = a;
return Json(jsonViewModel);
}
Then in the view you can use a simple call with JQuery like this:
var json = {
Person: { Name: "John Doe", Sex: "Male", Age: 23 },
Address: { Street: "123 fk st.", City: "Redmond", State: "Washington" }
};
$.ajax({
url: 'home/doJsonStuff',
type: 'POST',
contentType: 'application/json',
dataType: 'json',
data: JSON.stringify(json), //You'll need to reference json2.js
success: function (response)
{
var person = response.Person;
var address = response.Address;
}
});
in response to Dan's comment above:
I am using this method to implement
the same thing, but for some reason I
am getting an exception on the
ReadObject method: "Expecting element
'root' from namespace ''.. Encountered
'None' with name '', namespace ''."
Any ideas why? – Dan Appleyard Apr 6
'10 at 17:57
I had the same problem (MVC 3 build 3.0.11209.0), and the post below solved it for me. Basically the json serializer is trying to read a stream which is not at the beginning, so repositioning the stream to 0 'fixed' it...
http://nali.org/asp-net-mvc-expecting-element-root-from-namespace-encountered-none-with-name-namespace/