Updating the model in the controller? - c#

I'm using ASP.NET MVC 3. I have a question if it's possible to update the model, even if it's not being sent to the controller? Perhaps the question is completle of, or I'm doing things in a wrong way?
I have an ajax-call to a controller method. I'm passing in an id. I would like the controller to find some stuff in the db, and then update the model, passing it back to the view.
I've got a pretty big model... I've found some solutions, where to convert the model to a javascript object, and send it to the controller. Is that the only/right way?
How to send a model in jQuery $.ajax() post request to MVC controller method
I thought that maybe the controller has the model, where I could update some fields in it?
The call to the controller:
function getBis(id) {
$.ajax({
type: "GET",
url: '#Url.Action("GetBis")',
data: { "id": id },
dataType: 'json',
cache: false,
success: function (data) {
// Do something here
},
error: function (jqXHR, textStatus, errorThrown) {
alert("Problem!");
}
});
}
The controller code:
public ActionResult GetBis(string id)
{
BeslutIStortDTO viewModel = new BeslutIStortDTO();
int theId;
if (!Int32.TryParse(id, out theId))
throw new Exception("Wrong id");
viewModel = _blLayer.GetBIS(theId);
// somehow update the model here!
return View("index", viewModel);
}

usually you "pass the model" between JQuery and your controller when you need to "reflect" what ever is changed on your UI without doing any mapping(MVC is smart enough to construct a new object from the parameters you give it). In your case you said you just need to pass an ID to do some stuff on your model. So all you need to do is pass the ID as parameter, get it within the controller action and then do your stuff.
have a look at the below link
Pass a parameter to a controller using jquery ajax

First by updating the model, do you mean you want to update the record in the DB? That is not a good practice to do in a get request. If not read on..
Once you got your object with GetBis method, you can change all properties of it.
If you want to send this object to Javascript, use JSON Result.
return JSON(viewModel);
and one more thing, don't initialize view model in the first line of code, unnecessary object allocation.

The short answer is Yes and No, depending upon exactly what you mean, however you may want to reconsider your design. I would guess you are actually trying to render a Domain Entity to your view, rather than a View Model. This is a common newbie mistake.
One thing I would like to clarify is the difference between domain entities, and view models.
Domain entities are generally pulled from your persistence layer, and that is where your state changes should take place.
View models are temporary constructs, created on the server, just before a view is output as HTML, to be used as the data storehouse for the View template. It does not exist on the client's web browser after the request, and it no longer lives on the server after a request.
If you are using Ajax to perform some type of data change, instead of reloading the page, then what you would generally do, is make changes to the Domain object (via Id), rather than the View Model you originally passed in (which doesn't exist anymore).
For example.
I have a domain entity which is tied to a database record.
Person {long id=1;string name=bob;bool enabled=true}
I have a view model (that i map to bob in the initial get controller function)
PersonData {long id=1;string name ="bob", enabled=true}
To do this, in my initial page GET controller function, i pull up the Domain entity bob from the database, copy his data over to an instance of the view model, then pass the view model to the View("EditPerson",pd) action result, which goes through the razor view page and view model, and substitutes values into the HTML it is writing to the response stream, where appropriate.
Now, you have HTML on a client's web browser, that is IT. No view model exists. Now you have some Ajax which is browser side scripting, that says when I click a "Toggle Status" link for instance, what would happen is the browser (without changing pages) will submit a request to the ajax url you provided, passing in an Id of bob. Your controller function should then load the Entity version of Bob, and toggle the Entity version of Bob's enabled to an appropriate value, then persist that change to the database.
Nowhere at all does the original VIEW Model come into play, as it has not existed since the initial page was rendered to the browser.
Is there something specific you want to accomplish that you cannot see a way to do with this pattern?

Related

Updating Controller and Views after adding column to Model

I am new to Entity framework, so this is probably a stupid question.
I have added a new field to a Model class. I have created the migration and updated the database and this all works as expected. The new column has appeared in the SQL table.
I have manually modified the Create/Details Views (I'm guessing this isn't automatic) to include the new column. The new column is called "Level".
However, my Controller class doesn't seem to have picked up the changes. It doesn't insert the value when creating a new row. There are references to column names in the Controller class, but the new column name isn't there. E.g.
public async Task<IActionResult> Create([Bind("Id,Name")] Course course)
Is there any way to "refresh" the Controller to pick up the changes? Or will I have to manually edit the lines where the columns are named and add the new column?
If your view has a control bound to this new Level field and you want to pass it to the controller to write, then you will need to add it to the Bind attribute:
public async Task<IActionResult> Create([Bind("Id,Name,Level")] Course course)
While it might look like when you pass a Model to a view, and have a Form in the view that calls an action on the Controller passing that Model back, this isn't actually what happens. ASP.Net MVC is merely formatting the code in that way. Honestly this is a bit of a bad practice when using EF Entities as it trips up quite a few developers expecting that Entity references are being passed between server and view. It leads to confusing problems and is also an open door to data tampering when used incorrectly.
When the controller passes the Model to the View(), it is passing that Model to the View Renderer to compose the HTML view that will be sent to the browser. So if you're passing a Course entity, that entity does not travel to the client, it is consumed by the Server to build the HTML.
When your Form goes to call the controller, it will automatically append any bound fields that it knows about. This will include any bound entry controls, and if there are any details that don't have edit controls bound to them, you need to use bound Hidden controls to ensure that the MVC Javascript knows to pick those up too.
If you use a Bind attribute, this tells MVC which properties coming back from a Form submit or Ajax call that you actually want to accept. If "Level" isn't in there, the value will be ignored even if passed. The View does not pass an actual entity, it will be a set of named parameters that MVC has some magic smarts to convert into a Model object based on convention.
The Action could be written as either:
public async Task<IActionResult> Create([Bind("Id,Name,Level")] Course course)
or
public async Task<IActionResult> Create(int id, string name, string level)
where in the second case you'd need to handle the creation and population of your Course entity using the values passed in.

passing multiple models to controller to build ViewModel

So I'm consuming a RESTFul API to get the data I need. This API returns json and i converted this to C# models. The API returns some general info about a vendor and an array with products. The array of products also consists out of arrays for pricing information and product availability etc...
The problem im facing is that when a product is selected by a user to buy i have to gather specific information out of the different array's. Currently I've made a ViewModel for the data that needs to be send to process the order. This is done by binding the actual data using hidden fields and use a HttpPost from the view, resulting in +/- 30 hidden fields to set the proper data values.
I'm kinda new to MVC and this seems dirty. I thought i would be able to pass the models(for example the VendorModel,ProductModel,PricingModel,AvailabilityModel) from the view(with a POST) to the controller and create the ViewModel(based on the models send) so that i can send that to the API.
Is this actually how it should be done or is my design faulty and should i approach this differently?
A side note: One of the things i found is that most people suggest to use an identifier to get the data you need but the problem is that the API doesn't have the right calls to get Product, Pricing, Availability data based on Id, its just one big object with array's based on the search query.
Edit
So after some information i decided to try out nested models and created a viewmodel like this:
public class TestViewModel
{
public TestViewModel()
{
productInfo = new ProductInfo();
}
public ProductInfo productInfo { get; set; }
}
My view is like this(super simpel):
#using (Html.BeginForm("CreateOrder","Products"))
{
//Vender info etc...
//This is how i render partial view now:
{Html.RenderPartial("Info/ProductInfo", Product.ProductInformation.ProductInfo);}
<input type="submit" value="Order" class="btn btn-default" />
}
My controller(TestViewModel.ProductInfo is always null):
public ActionResult MakeReservation(TestViewModel testViewModel)
{
//Doesnt do anything just debugging TestViewModel
return View();
}
I'm not posting any inputs but just want to pass the modal with the data to the controller. How will MVC know which data to bind, because now it doesnt bind. Do i have to bind it myself somehow?
I had the similar situation and I have one suggestion, you can pass all the models to the view as save in a javascript object as JSON using the example code which I used like below-
<script type="text/javascript">
var pageBlockOptionsJSON = #(Html.Raw(Json.Encode(DesignOrderBlocks)));
var controlTypeJSON = #(Html.Raw(Json.Encode(controlList)));
</script>
Then you can do all the manipulations using jQuery to structure and create a javascript object and post that object to Controller Action. You can create the same or exact structure which is needed on the server. As specified in this url - http://www.nickriggs.com/posts/post-complex-javascript-objects-to-asp-net-mvc-controllers/
In this way you don't need to have use huge amount of hidden fields and you can do all the dirty work on the client side using jQuery.
I am sure this will help you out in doing the thing in the right way. Let me know if you need some details.
For people that somehow find this questions i solved this issue by saving the model to an database as an search result using entity framework. After getting the result i save it and create a viewmodel. After posting i send the id's that entity framework generated and search the right models in the database creating a new postviewmodel.

Standard practice on calling Javascript from MVC

I'm pretty experienced with Web Forms, but attempting a site in MVC to broaden my skill set. In Web Forms, you could do something like this to execute some JavaScript when the page loads:
ScriptManager.RegisterStartupScript(this, this.GetType(), "unique-script-id", "alert('Data saved.');", true);
What is the equivalent way to do this from a Controller? Should I pass a JavaScript block in the ViewBag, then in my View check for the existence of that script and render it? Or should I abandon the idea of doing this from my controllers and instead use AJAX from the client side to post the form to a Web API, and then based on the HTTP status code display the appropriate message?
public ActionResult Submit(ArticleModel article)
{
//save model to database
//I think here I want to do the MVC equivalent of registering a startup script providing a success message.
return RedirectToAction("Index");
}
What is the equivalent way to do this from a Controller?
You don't. Not from the controller anyway.
JavaScript is part of the view. The controller provides a model to the view, nothing more. It shouldn't be coupled to the view in any way. Your JavaScript would be invoked within the view.
If you're looking to conditionally include JavaScript in the view, you can wrap it in a conditional check on a model property:
#if(Model.SomeBooleanProperty)
{
<script type="text/javascript">
// your script here
</script>
}
Then the model would be logically determining whether or not that functionality is invoked. The view is simply binding to the properties on the model.
Edit: Another approach, structurally similar but without adding a property to a model, is to use something like ViewBag. In your controller you'd set the value:
ViewBag.SomeBooleanProperty = true;
Then you'd check it in the view:
#if(ViewBag.SomeBooleanProperty)
{
<script type="text/javascript">
// your script here
</script>
}
Keep in mind, however, that this introduces some coupling between the controller and the view. The view now assumes that something other than the model has been set. It then becomes the responsibility of any code which returns that view to explicitly set that value. Models are a way to enforce this more explicitly, eliminating the coupling.
Additionally, you seem to be misunderstanding something in one of your comments:
This information I'm talking about isn't data, so it doesn't belong in the model.
Models don't contain just data. Models contain the core business logic of your application. Just data results in "anemic models."
Learning the "MVC Way" of doing things will help you in the long run to develop more modular, testable applications.
In your example, you are wrapping your functionality around multiple components. You are wanting your controller to tell your view to perform some action. This is the practice that MVC frameworks in general strive to deviate from.
MVC frameworks, including ASP.NET MVC, adhere to the principal of least responsibility.
The job of your controller is to Control your application flow. It isn't even really responsible for program logic, you will likely have Services to handle things like Database management, complex calculation, etc. Your controller shouldn't really care about the view, or how the view displays information; it should only care how to make a view and tell the view to do it's thing. Typically, controllers can be slimmed down to less than 10 lines of code in all but extremely complex scenarios.
By the same token, the view shouldn't care how the controller works, or the services that the controller responds to. Views should never be told how to display information, errors, etc, only given data or a status to work with.
Keeping this separation of concerns means a few things. First, it ensures that you can make changes to one part of the application without it having a major impact on another portion. Secondly, you can test if the controller is working without ever having a view, and you can render the view with sample information without a functional controller. This makes your development team much more efficient.
Bottom line, you should keep the idea of Separation of Concerns in the front of your mind when working with MVC, and if you are ever thinking that you need to have your controller tell the view to show something, you are probably going the wrong direction with your overall architecture.
Hmm..
You can directly use javaScript in CSHTML and if you want to show your script under condition than you can bind it inside if condition just pass a signal from controller to show your script only
true or false
EXAMPLE
set a boolean value from controller and keep in ViewBag
ViewBag.isSubmit= true;
and then check condition in your view
#if ((bool)ViewBag.isSubmit==true)
{
<script>
alert('Submit Successfully');
</script>
}
but remember to insert # before if because this is CSHTML and uses Razor syntax.

passing in an additional parameter with the model to a View

Still learning Mvc so sorry if this question is a bit weird.
I am passing the model in my Controller method and want to pass an additional parameter.
what I want to achieve is something like this but the parameter overload does not allow for the 'additional' parameter.
#using (Html.BeginForm("SubmitCall", "Home", new { Id = Model.ProductDetail.ProductId }))
and then in the controller
public ActionResult SubmitCall(ViewModel model, int Id)
{
return RedirectToAction("DetailViewById", model, new {productId = Id});//not allowed
}
Is there a better way of achieving this?
Kind regards
If your only intention is to redirect the client to another URL then the above scenario is not the right way to achieve this.
RedirectToAction will send a HTTP 302 with the Location information generated from your route information (again, in your case this would be the URL to DetailViewById with productId as a parameter or part of the URL - depends on your route configuration).
If you need to persist the ViewModel that is submitted by the client and operate on it once the user is requesting your redirected action, then i would suggest to use TempData which is designed for between-request persistence of such data.
Usually, the ViewModel is a combination of what you have coming back from database (DTO) + extra bits and pieces you need TO and FROM View.
So in my opinion, you should add this extra property to your Viewmodel.
Create an anonymous object for parameters:
return RedirectToAction("DetailViewById",
new {
productId = Id,
model.Property1,
model.Property2,
...
});

ASP.net mvc3 Get data from View to Controller C#

I am currently using ViewBag to pass a Datatable, and some other dynamic data to the view. The data is displayed to the user in a table, and depending on which columns the user chooses, certain calculations are performed. My problem is, these calculations need to be chained, so that when the user performs a calculation, the state of the data is maintained, and further calculations on that data are then possible.
How can I get the current datatable state from the view into the controller each time? The calculations need to be performed on that current state.
If it makes any difference, I could easily change the view into a strongly typed view, and create a new object to abstract the datatable and the other dynamic data away.
Any advice welcome.
Thanks.
This sounds like some AJAX to me. You should be able to post the state back to the server (another method in your controller) and store it however you need to.
MVC3 has some great JSON stuff which should make your life easier. That + jQuery, you should be laughing.
I do encourage you to avoid DataTables and DataSets if possible. They should be considered to be the worst kind of DTO's since you can never guarantee what they contain and when (unless you follow the call chain back to their origin and make sure that they are not changed anywhere on the way).
By using proper view models you know what they contain by just looking at them, and you can also put all formatting logic inside them instead of in the view.
I've written a blog entry about why you should use view models: http://blog.gauffin.org/2011/07/three-reasons-to-why-you-should-use-view-models/
As for your question: The easiest way is to use jQuery/Ajax and return Json (which is easy if you are using proper view models).
<script type="text/javascript">
$(function() { //<-- runs the script when the document has been loaded
$('#formid').submit(function() { // <--- hook form submit event
$.post('#Html.Action("CalcOne")?option='+ $('#id').val(), function(data) {
var result = data.result;
$.post('#Html.Action("CalcTwo")?option='+ result, function(data) {
//do third calc
});
});
});
});
</script>
And in your controller:
[HttpPost]
public ActionResult CalcOne(int option)
{
//do some calculations
return Json(new MyModel{ Result = option + 1 });
}

Categories

Resources