Reputation: 79
I am confused about how to update my viewmodel in MVC3. What I am trying to do on a button click search my viewmodel for a particular list item. Example:
BooksViewModel
public List<Book> Books{get;set;}
In my view when the user clicks on a button I need to search the List in the ViewModel like this:
Controller
public void SetContent(int chapterId, int paragraphId)
{
var paragraph = booksViewModel.Books.Where(b =>b.ChapterId == chapterId).First().Chapter.Paragraphs.Where(p => p.Id == paragraphId).First()
model.CurrentParagraph = paragraph;
}
The problem I am having is that I cant access the instance of the BooksViewModel from the controller. How do I access the instance of the viewmodel that the view is using that already has the data which was retrieved from the database? Or am i going about this all wrong?
THanks in advance
edit
maxim suggested passing in my model from the view to the secondary call to the controller (i.e. to filter the model)
would i do that by using the @Model keyword like this:
$.ajax({
type: "POST",
url: "/Books/SetSelectedContent?id=" + id + "¶graphId="+paragraphId+"&model="+@Model, // the URL of the controller action method
data: null, // optional data
success: function(result) {
},
error: function(req, status, error) {
alert('error' + error);
}
});
When I tried this it seemed the ajax call choked on @Model
Upvotes: 0
Views: 295
Reputation: 5024
Remember that the web and views are stateless. Once the action is executed, it's gone (unless you session things, but that's a different beast).
If you want to search the list after it's been passed to the view, in a different controller action (brand new request, everything from the previous request is gone), then you'll have to recreate the list.
public MyController
{
public ActionResult Index()
{
var books = _service.GetBooks();
return View(new BooksViewModel
{
Books = books
});
}
// Once the button is clicked, it routes to this action:
[HttpPost]
public ActionResult SetSelectedContent(int paragraphId)
{
// Here you search for the specific paragraph that you want.
// Ideally this goes in a service call, but here to illustrate.
// The linq query won't materialize every book, but will give an
// optimized query that only gives the paragraph that you want.
// Depending on your model structure, this will work better.
// Paragraph Id's should be unique, yes? so no need for the chapter
// then.
var paragraph = database.Paragraphs
.Single(p => p.paragraphId == paragraphId);
// Note the 'Content' here, not View. This will return just the
// plain text to be replaced by ajax.
return Content(paragraph);
}
}
Here's the fix for that ajax sample:
$.ajax({
type: "POST",
url: "/Books/SetSelectedContent",
// populate the data with whatever the chapter and paragraph id should be.
data: { pargraphId: @paragraphId }
success: function(result) {
// Here you do something with the result.
// This would just replace a specific div with the contents
// of the searched paragraph.
$('#DivToReplace').html(result);
},
error: function(req, status, error) {
alert('error' + error);
}
});
Again, the SetSelectedContent should be able to just filter the database by the params - it shouldn't have to actually materialize the entire table of books, so sessioning or caching just adds an extra layer of complexity.
Upvotes: 1
Reputation: 10509
When you send a View to a user browser, you create an instance of your Model (in your case you call it ViewModel). This is done as a part of some Action that returns a view in your Controller. If you want a modified version of you Model to be reconstructed for Action-procession, you should request it as a parameter in you Action's signature in case of a form POST
submit, or you just create a new Model and initialize View with it.
From what I see, this is the case. Just create a new BooksViewModel
, do a filtering and send a View(myFilteredModel)
to a user.
But you can also try this:
[HttpPost]
public void SetContent(int chapterId, int paragraphId, BooksViewModel booksViewModel)
{
var paragraph = booksViewModel.Books.Where(b =>b.ChapterId == chapterId).First().Chapter.Paragraphs.Where(p => p.Id == paragraphId).First()
model.CurrentParagraph = paragraph;
}
As for DB-access per action execution - this is solved via implementing a cache mechanism.
Upvotes: 0