从视图更新模型

从视图更新模型

问题描述:

我很疑惑如何在MVC3中更新我的视图模型。我正在试图做的按钮点击搜索我的viewmodel特定的列表项。例如:从视图更新模型

BooksViewModel 

public List<Book> Books{get;set;} 

在我看来,当一个用户点击按钮我需要搜索列表的视图模型是这样的:

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; 
} 

我遇到的问题是,我不能访问实例来自控制器的BooksViewModel。如何访问视图正在使用的视图模型实例,该实例已经具有从数据库中检索的数据?或者我对这一切都错了?

由于事先

编辑

格言建议在我的模型通过从视图到二次呼叫到控制器(即筛选模型)

,我会做到这一点的使用@Model这样的关键字:

$.ajax({ 
      type: "POST", 
      url: "/Books/SetSelectedContent?id=" + id + "&paragraphId="+paragraphId+"&model="[email protected], // the URL of the controller action method 
      data: null, // optional data 
      success: function(result) { 

      }, 
      error: function(req, status, error) { 
       alert('error' + error); 
      } 
     }); 

当我试过这似乎ajax调用c在@Model上启用

+0

是的,这会窒息 - 不能只是将整个模型追加到这样的网址。它不知道如何将其转换为url编码的字符串。 – Leniency 2012-03-27 16:37:38

请记住,网页和视图是无状态的。一旦行动执行,它就消失了(除非你会议的事情,但这是一个不同的野兽)。

如果您想在列表传递到视图后搜索列表,请在不同的控制器操作(全新请求,前一个请求中的所有内容都不存在)中进行操作,那么您必须重新创建列表。

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); 
    } 
} 

下面是阿贾克斯样本修正:

$.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); 
     } 
    }); 

再次,SetSelectedContent应该能够仅仅通过PARAMS筛选数据库 - 它不应该有实际兑现的整个表书籍,所以会话或缓存只是增加了一层额外的复杂性。

+0

谢谢你。虽然这确实帮助我理解Web是无状态的,但我无法再从索引访问视图模型,但我真的不想再次调用_service.GetBooks。也许解决方案是真的在_service中实现一些缓存。 – majid 2012-03-27 16:37:54

+0

在这里问一个更好的问题是你在做什么IEnumerable ?你是否一次显示整本书?你只是显示一个书名列表?你对数据做了什么,使得每次请求再次拉动都很昂贵?有几种方法可以减少你在这里从数据库中提取的内容。 – Leniency 2012-03-27 16:45:17

+0

在同一视图中,我显示的是书中的经文,并允许用户在特定的诗句/段落上添加评论,隐藏或显示存储在模型中存储的iEnumerable 列表中的所有评论 – majid 2012-03-27 16:54:53

当您向用户浏览器发送视图时,将创建模型的实例(在您的情况下称为ViewModel)。这是作为某个Action的一部分完成的,该Action在Controller中返回一个视图。如果您希望为您的Action-procession重构您的Model的修改版本,则应该将其作为参数请求,以便在您提交表单POST时使用Action的签名,或者您只需创建一个新模型并使用它初始化View。

从我看到的情况来看。只需创建一个新的BooksViewModel,执行过滤并将View(myFilteredModel)发送给用户。

但你也可以试试这个:

[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; 
    } 

对于每个动作执行DB访问 - 这是通过实现缓存机制来解决。

+0

是在我的控制器创建视图的方法我发送模型到视图,但我如何访问同一模型在将来调用控制器方法 – majid 2012-03-27 16:11:41

+0

我可以这样做,但这将意味着我已拨打数据库和重新填充BooksViewModel新实例中的所有“书籍”。我想避免进行额外的数据库调用,因为它可能会返回大量的数据。 – majid 2012-03-27 16:17:14

+0

相同的型号 - 只有当您将其发回服务器。您可以访问所需的参数'int chapterId,int paragraphId'并创建一个新的参数。如果你想要一个只是做一个过滤器的ajax方法 - 你需要从javascript初始化ajax调用你的动作,并根据响应更新页面。转向不同的行动意味着你正在远离视野。 – 2012-03-27 16:19:23