2013-09-06 4 views
13

기존 앱에 KnockoutJS를 도입했습니다. 제 계획은 이미 생성 한 기존 부분 뷰를 수정/활용하고 Knockout의 선언적 속성을 사용하여 JS 뷰 모델에 바인딩하는 것입니다. 액션에 대한 AJAX 호출을 만들면 이상적인 부분 뷰의 HTML과 JSON 객체를 모두 반환하는 동작을 원합니다. 그런 다음 HTML로 div를 채우고 JSON을 Knockout 객체로 변환 한 다음 HTML에 바인딩 할 수 있습니다. 하지만 나는 그 행동에서 두 가지를 모두 돌려 보내는 방법을 알아낼 수 없다.부분 뷰 및 JSON (ASP.NET MVC 액션)

전체 뷰 모델이 필요하므로이를 업데이트하여 결국 서버로 다시 보냅니다.

부분 뷰 (이미 모델에 바인딩되어 있음)를 반환하고 부분 뷰 내에서 .Net 모델을 넉 아웃 개체로 변환하는 자바 스크립트를 포함하는 것으로 생각했습니다. 하지만 나는 JS가 주위에 흩어져있는 것이 지저분하고 유지가 어렵다고 느낍니다. 차라리 원래의 아약스 전화에 가깝게 모든 것을 가지고 싶습니다.

또 다른 대안은 두 번의 동작 호출을하는 것입니다. 하나는 JSON 용이고 다른 하나는 부분보기 용입니다. 그러나 더 매끄러운 방법이 있어야합니다.

가장 좋은 방법에 대한 아이디어가 있으십니까?

답변

21

여기에는 다양한 방법이 있습니다. 컨트롤러에서 뷰를 수동으로 렌더링 한 다음 렌더링 된 뷰를 JSON 응답의 일부로 다시 전달합니다.

이것은 각 엔티티의 책임을 보존합니다. 뷰는 여전히 뷰 엔진을 사용하여 위치하며 재사용 할 수 있습니다. 컨트롤러는 뷰의 이름과 모델 유형 외에는 거의 또는 전혀 알지 못합니다.

수동 액션 방법에

public static class RenderHelper 
{ 
    public static string PartialView(Controller controller, string viewName, object model) 
    { 
     controller.ViewData.Model = model; 

     using(var sw = new StringWriter()) 
     { 
      var viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName); 
      var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw); 

      viewResult.View.Render(viewContext, sw); 
      viewResult.ViewEngine.ReleaseView(controller.ControllerContext, viewResult.View); 

      return sw.ToString(); 
     } 
    } 
} 

렌더링 : 나는 익명의 유형을 반환하고있어

object model = null; // whatever you want 
var obj = new { 
    someOtherProperty = "hello", 
    view = RenderHelper.PartialView(this, "_PartialName", model) 
}; 

return Json(obj); 

참고. 렌더링 된 뷰에 문자열 속성이있는 한 원하는 모든 (직렬화 가능) 유형을 반환 할 수 있습니다.

테스트

수동 렌더링을 사용하는 동작을 테스트하려면 약간의 수정이 필요합니다. 이는 MVC 파이프 라인에서 렌더링되는 것보다 조금 더 빨리 뷰를 렌더링하기 때문입니다.

  1. 는 액션 메소드를 입력 렌더링 수동

  2. 보기가 명시 적으로 < 렌더링 -이 어려운
  3. 종료 액션 메소드

자동 호출 조치를 테스트 할 수 있도록한다 렌더링

  1. 은 즉

(따라서 뷰 렌더링)

  • 종료 액션 메소드
  • 프로세스 뷰 결과를 뷰 결과를 작성 액션 메소드
  • 를 입력, 우리의 수동 렌더링 프로세스가 개막 테스트를 어렵게 만드는 다양한 작업 (예 :보기를 컴파일하기 위해 빌드 관리자와 상호 작용).

    보기의 실제 내용이 아닌 동작 방법을 테스트하려는 경우 호스트 된 환경에서 코드가 실행 중인지 확인할 수 있습니다.

    public static string PartialView(Controller controller, string viewName, object model) 
        { 
         // returns false from a VS 2013 unit test, true from IIS 
         if(!HostingEnvironment.IsHosted) 
         { 
          // return whatever you want here 
          return string.Empty; 
         } 
    
         // continue as usual 
        } 
    

    (후드, 그것은 단순히 널 검사) HostingEnvironment.IsHosted이 저렴 확인.

  • +0

    +1 도우미 클래스에 대해 생각하지 마십시오. 이것은 가장 우아한 해결책 일 것입니다. 나는 그것을 시도 할 것이다. 감사. – nthpixel

    +0

    당신은 다음과 같이하고 싶지 않습니다 :'var obj = new {view = RenderHelper.PartialView (this, "_PartialName", viewModel), model = koViewModel}; 아니면 'foo'가 무엇입니까? 또는 나는 무엇인가 놓치고 있냐? – nwayve

    +0

    @Dennis - 예, "foo"는 반환해야하는 다른 모든 데이터를 나타냅니다. 정확히 Knockout이 클라이언트에서 필요로하는 것은 확실하지 않지만보기에는 모델이 필요합니다 (null 인 경우에도). –

    1

    ViewModel의 JSON 문자열로 설정된 값으로 부분에 숨겨진 <input>을 만들 수 있습니다. 그런 다음 부분 뷰를 렌더링하기 전에 해당 필드에서 JSON 값을 가져 와서 파싱합니다. 그런 다음 부분보기에서 제거하고 페이지에 삽입하고 수행하십시오. ko.applyBindingsToDescendants(viewModel, $("#parentElement")[0])

    이 접근 방식에 대해 어떻게 생각하는지 모르겠으며 이는 단지 이론 일뿐입니다. 나는 이것을 시험하지 않았지만 그것이 효과가있을 것이라고 생각합니다. 하나는 booty trap 당신은 GET 요청을 캐시하려고하는 브라우저를 찾아야 할 것입니다. 아약스 요청에서 다음을 원합니다.

    $.ajax({ 
        url: "/", 
        type: 'GET', 
        cache: 'false' 
    }); 
    

    또는 $.post 요청 만하면됩니다. (reference)

    그래서 하나의 옵션입니다.

    +0

    +1 ... 그러나 나는 그것에 대해 어떻게 생각하는지 잘 모르겠습니다. – nthpixel

    관련 문제