How can I hold a collection of strings to post back? - c#

From my controller I send a ViewModel with a collection of strings to be used in a <select> tag like so...
Controller:
var model = new InviteViewModel
{
SelectItems = new SelectViewModel
{
Companies = _companyRepository.GetCompanyNames()
}
};
Razor View:
<select class="form-control company_select" asp-for="Company" asp-items="#(new SelectList(Model.SelectItems.Companies))"></select>
This works perfectly and will display all the items in the drop down box. However when I go to submit the form the Companies object will be null and when the View is sent back I get a null reference exception. Normally I would create a hidden <input> tag to hold the value, but how can I do this with a collection?

There are so many ways to do this.
It seems like you may have a fundamental misunderstanding of the disconnect between Razor and html. Razor executes server side, and its result is simply a string that gets written to the response stream. Once written, razor's scope is gone and cannot hold data.
One option would be to store the collection in the application cache or session cache with a guid as the dictionary key, and then use a hidden input for the cache key. When the view is being recreated you would then have access to the server and could gather the collection.
This makes the assumption that the collection hasn't changed during the time the view was active, which given some user habits could have been a long time. There should also be some sort of metrics used when caching to invalidate old data, if this is the route you take.
Another option is to simply regenerate the collection from wherever (database?) it came from.
Lastly, you mention that the view is being returned with the empty collection, are you returning a view from a post method? That is bad practice. Look up the "post-redirect-get pattern" for why and how to avoid it.

Related

Object with items : View-Controller communication

So, I have no clue how to search for an answer to this problem, mainly because there are several aspects to it which I don't know how to solve. So - here it is.
I have an object, let's call it ObjectWithItems which has a List<Item> of Item objects. Both have separate Views and Controllers (which seems logical to me, but I can't be sure).
What I'm trying to achieve is this – go to Create action of ObjectWithItemsController and fill the necessary information specific to it. Then, I click an ActionLink "Add item", which takes me to the Create action of the ItemController. The View is rendered and I enter information for that specific Item.
What I don't know how to do is the following: when I submit the current Item, it should be passed to the former Create view of the ObjectWithItems and added to the List<Item>. Furthermore, it should contain the information inputted before calling the Item Create method and the rendering of the corresponding View.
I know this is a bit blurry description, but that is because I have just started learning ASP MVC and still don't know what's what. Any tested approaches for this?
Using Session["key"] object allow you to store any kind of object, Ex :
List<Table> Rows = db.Table.Where(t => t.id < 100).ToList(); // 100 first rows
Session["TableRows"] = Rows;
And later when you want to retreive them :
List<Table> Rows = (List<Table>)Session["TableRows"] // don't forget to cast it
Your objects will exist in Session as long as you don't reach the ASP timeout
Communication between View-controller is done through HTTP Post of the form.
< form class="form-horizontal" method="post" >
or #using (Html.BeginForm())
More info here with example

Pass entire object from view to controller in ASP.NET MVC 5

Is there a way to pass entire object from ASP.NET MVC 5 View to a Controller? This is my situation:
I have a View that displays all rows from a DB table
The view's model is IEnumerable
Each row has a link after it's data that leads to the scaffolded UPDATE view
Is there a way to pass the entire object to the Update controller method so it would initially fill the form inputs with the old data? Something like:
#Html.Action("Update me!", "Update", new { objectFromModelList })
And then in the controller
public ActionResult Update(MyType parameter)
{
return View(parameter);
}
Or something like that. Please help, I am new to this and can't find the answer anywhere.
Your objects could be so big! Query string's has a limitation on how much data you can pass via those based on the browser. You should consider passing a unique id value (of the record) and using which get the entire record from db in your action method and pass that to the view.
#foreach(var item in SomeCollection)
{
<tr>
<td> #Html.Action("Update me!", "Update", new { id = item.Id }) </td>
</tr>
}
and in the action method
public ActionResult Update(int id)
{
var item = GetItemFromId(id);
return View(item);
}
Assuming GetItemFromId method returns the method/view model from the unique id value. Basically you get the entire record using this unique id from your db table/repository.
Assuming that your Update View isn't of type IEnumerable...
You just need to pass the ID of the record that you want to send to the Update view...
Like so:
#Html.Action("Update me!", "Update", new { id = item.ID })
Then your Update action would look like this:
[HttpGet]
public ActionResult Update(int id)
{
var parameter = db/* connection string variable */.TableName.Find(id);
return View(parameter);
}
Then your link should work appropriately.
Hope this helps!
I have searched myself and the best way, aside from passing the ID, that I have found is to store any other variables that you might need into hidden input fields or HTML5 tags. Then you can script a way to handle any button/link click events. This way you can store vital object properties of each record and easily pass them back to a controller. Think Client-side here, Once the data ends up Client-Side, use Client-Side tools to handle and pass it back to server side/controller.
I do something similar with a type of library reservation system that allows users to reserve items on available dates. I pass all available records to the view. Each record has a few fields that I want to hold onto including the ID for users reference. When the user clicks the button, I collect the needed fields.
You could use HTML5 form input fields that are hidden or you could just use JavaScript to collect those values using GetElementByID. An example of this would be to store the ID in the div wrapper. Then have another div hold a sub parameter. You can use Javascript to find the record ID and then get the second div by it's id. Example would be get the id NameRecord from XRecord where X = the ID passed.
I then pass those values to the controller, instantiate a new class/object for the reservation. The new class object also has the item class/object as a property. For example consider the following;
var reservation = new Reservation
{
myKit = new ResourceKit()
};
After that, you can store it in a session if you need to build on it. In my case I am holding it in a session because I allow the user to check availability/dates. These items are a physical resources that gets checked out similar to a library and are transferred via office mail.
If you dont mind the data sitting client-side, you can store it using LocalStorage and JavaScript. This type of data isnt secure at all much like a cookie. One of the ways that I have used this is to set site preferences. Users can select a color scheme and those preferences are stored in LocalStorage. That way when the return to the site those preferences remain. This is a key attribute of LocalStorage and might not be applicable to your needs/circumstances.

Is it possible to "inject" updates into a Knockout ViewModel?

I'm currently looking for a solution to my issue: In our ASP.NET MVC application there are pages that are used for realtime data visualization of industrial devices. When the page gets loaded, a loading icon is shown while I fetch the viewmodel data with the current values for all the datapoints from a database. That works quite well, but it is static, by which I mean that the values don't change on the page after it finished loading. The web application itself uses a TCP listener that receives messages with values from the devices. These messages (which basically consist of a device id, a datapoint id and the value) don't arrive in fixed intervals but event-based, e.g. when a temperature value changes 0.5 K up or down.
On my page I have some graphical widgets like gauges and many other elements that correctly show the values from the initial data that gets loaded on the page load. They are bound to the Knockout viewmodel.
The problem is this: whenever a new value arrives on the server, I want to show it on the page without the need for a reload. I definitely don't want to re-transmit the whole viewmodel with some hundred datapoints on every message that arrives on the server (appr. 1 to 15 per second). In order to achieve that, I implemented the SignalR framework, which really works great. With that mechanism I now receive the new value in the client window (that means, I receive it in Javascript and now have a value object like described below).
What I need now is this: as every viewmodel gets built dynamically, they are all different. The object and properties tree is not the same for two devices, so each of them can have varying levels of subobjects. The only thing that is the same is the structure of the object that actually holds the value for each datapoint: it always consists of the aforementioned device id, the datapoint id and the value.
I need a way to update the double-type value inside the value object within the viewmodel whose device id and datapoint id match the newly arrived value message (that also consists of these two address-like ID's and the value).
I hope I got the idea across. Is there a way to do this? What would be the best practice for such a mechanism? I recently switched to Knockout-MVC (kMVC nuget package), but I'd also go back to "pure" Knockout.js and some additional scripting if that helps.
Thanks for your help and recommendations!
http://nthdegree.azurewebsites.net/mvvm-2/
Here is an article speaking to the Knockout mapping plugin
The general idea is that you should have your view model code which loads your model.
You would bind up your view model which will have a property you load from the server with an ajax call (see bottom of article).
You then just update the model with the result with
ko.mapping.fromJS(newData, mapping, modelToUpdate)
var mapping = {}; //define your mapping (see documentation or blog post)
function ViewModel(){
var self = this;
self.model = ko.mapping.fromJS({}, mapping);
self.hub = $.connection.myHub();
self.hub.client.updateModel = function(data){
ko.mapping.fromJS(data, mapping, self.model);
};
self.hub.start().done(function(){
//you could either make a call or have the "OnConnected" method trigger an 'updateModel'
});
}
ViewModel properties when linked to a DOM element allows editing which is actually updating the data in the KO observable array. Is it possible for you to change the "graphical widget"'s value (assuming that it is using some property to maintain height and width) using the IDs which you said are consistent?
I have not tested; the other option is to use KO foreach loop and update the related value.

Does ASP.NET MVC form post autopopulate fields?

I have a form like ...
#using (Html.BeginForm("create", "Account", FormMethod.Post, new { id = "accountform_form" }))
{
#Html.TextBoxFor(e => e.ShipFirstName)
...
}
while testing, I was surprised to see the field retained its value on postback even without me assigning it to the view-model. Using the debugger, the value for ShipFirstName is null right at the end of the action when returning the view, so why would it show the value that was in the field? Have I been unnecessarily assigning posted values to view-model properties all this time? Or is there something else going on?
Update: the action is like so...
[HttpPost]
public ViewResult Create(AccountFormModel postModel)
{
var model = new AccountFormModel(postModel, stuff, stuff); //I use posted values and paramters to create the actual view model
return view(model);
}
So, I see the GET form, enter values, say I enter a field and leave a required field blank, submit, the resulting page has the value I entered in the other field, who's putting it there when in the model it's null?
I ran into something similar earlier today (a checkbox was always checked). Have a look at Changing ViewModel properties in POST action and see if this is similar.
Basically calling ModelState.Clear() fixed it for me.
As you're passing the model back to the view after it has been POSTed, MVC is taking the stance that you're doing so because the form contains errors. So, rather than making the user fill out the form again, it repopulates it using the ModelState collection. In this case, the values in the ModelState collection take precedence over the changes you make in the action (which does feel a bit weird).
You can get around this either by calling ModelState.Clear() or using ModelState.Remove(string key), where key is the name of the property.
If you'd like a full explanation of why this is the case, see ASP.NET MVC’s Html Helpers Render the Wrong Value!. Excerpt:
Why?
ASP.NET MVC assumes that if you’re rendering a View in response to an HTTP POST, and you’re using the Html Helpers, then you are most likely to be redisplaying a form that has failed validation. Therefore, the Html Helpers actually check in ModelState for the value to display in a field before they look in the Model. This enables them to redisplay erroneous data that was entered by the user, and a matching error message if needed.

How do I persist a value accross views

Completely new to asp.net mvc... completely new to web apps so bear with me...
Lets say I have an Action on a controller that requires a specific piece of information, say an int Id value.
A view is rendered from this Action. This view contains a button which will take the user off to a new Action on another Controller.
On the view of this second Action, there is a link that will send them back to the original Action on the Controller. Obviously, I've lost the original Id value and therefore the information I need to render my original view. What do I need to be looking into to solve this? Are there techniques/patterns that could be used to help?
I know I can keep passing the value around but if the other controller doesn't actually need this value it seems wasteful. I think I'm probably approaching the problem the wrong way to be honest. Any help appreciated.
I know I can keep passing the value
around but if the other controller
doesn't actually need this value it
seems wasteful.
But the second controller does need the id to function properly - as you've said, it needs the id to render the return link. Passing it around is the right thing to do.
There are many ways you can achieve this. Some of them are :
You can keep the value in the Query String.
If navigation from Action-1 to Action-2 is done via posting a form, you can send the value with a hidden input tag. Eg : <input type="hidden" name="n" value="v" />
You can use TempData to persist information between two requests (though it doesn't look like this is a good solution for your case)
Without knowing what exactly you are trying to do, it's hard to know best solution.

Categories

Resources