ASP.NET MVC ViewModels에서 knockout.js를 사용하는 방법은 무엇입니까?




asp.net-mvc asp.net-mvc-3 (2)

하사품

잠시 지났는데 몇 가지 뛰어난 질문이 있습니다. 현상금을 추가하면 이러한 질문에 대한 답변을 얻을 수 있기를 바랍니다.

  1. knockout.js에서 html 헬퍼를 어떻게 사용합니까?
  2. 문서를 작동시키기 위해 준비가 필요한 이유 (자세한 내용은 첫 번째 편집 참조)

  3. 내보기 모델에서 녹아웃 매핑을 사용하는 경우 어떻게해야합니까? 필자는 매핑으로 인해 기능이 없습니다.

    function AppViewModel() {
    
        // ... leave firstName, lastName, and fullName unchanged here ...
    
        this.capitalizeLastName = function() {
    
        var currentVal = this.lastName();        // Read the current value
    
        this.lastName(currentVal.toUpperCase()); // Write back a modified value
    
    };
    
  4. 예를 들어 플러그인을 사용하고 싶습니다. 사용자가 마지막 값으로 되돌리려 고 할 수있는 요청을 취소 한 것처럼 관찰 가능 항목을 롤백 할 수 있기를 원합니다. 내 연구에서 이것은 editables 플러그인을 만드는 사람들이 달성 한 것 같다.

    매핑을 사용하는 경우 어떻게 사용합니까? 난 정말 내보기 수동 매핑을 가지고있는 방법으로 가고 싶지 않아요 가능한 한 작은 인라인 자바 스크립트로 원하는대로 KO 모델 필드에 각 MVC viewMode 필드를 매핑하고 그냥 작업을 두 번 같은 것 그리고 그게 왜 내가 그 매핑을 좋아하는지.

  5. 나는이 작업을 (맵핑을 사용함으로써) 쉽게하기 위해 많은 KO 힘을 잃지 만, 다른 한편으로는 수동 매핑이 많은 작업이 될 것이고 내 견해가 너무 많은 정보를 포함하게 될 것이라고 염려한다. 미래에 유지하기가 더 어려워 질 수도 있습니다 (MVC 모델에서 속성을 제거하면 KO 뷰 모델에서도이 속성을 이동해야합니다)

원본 우편

나는 asp.net mvc 3을 사용하고있다. 그리고 나는 멋지게 보이기 때문에 녹아웃을 들여다 보았다. 그러나 asp.net mvc 특히보기 모델과 어떻게 작동하는지 알아내는 데 어려움을 겪고있다.

나에게 지금은 이런 일을한다.

 public class CourseVM
    {
        public int CourseId { get; set; }
        [Required(ErrorMessage = "Course name is required")]
        [StringLength(40, ErrorMessage = "Course name cannot be this long.")]
        public string CourseName{ get; set; }


        public List<StudentVm> StudentViewModels { get; set; }

}

CourseName과 같은 몇 가지 기본 속성을 가진 Vm을 사용하면 몇 가지 간단한 유효성 검사가 수행됩니다. Vm 모델은 필요할 경우 다른 뷰 모델을 포함 할 수 있습니다.

그런 다음이 HTML을 뷰어에 전달하면 html 헬퍼를 사용하여 사용자에게 표시 할 수 있습니다.

@Html.TextBoxFor(x => x.CourseName)

저는 몇몇의 foreach 루프 나 Student View Models 컬렉션에서 데이터를 가져올 수있는 것이 있습니다.

그런 다음 폼을 제출할 때 jquery를 사용하여 serialize array 하고 컨트롤러 동작 메서드로 보내면 뷰 모델로 다시 바인드됩니다.

knockout.js를 사용하면 viewmodels를 얻었고 다른 예제에서는 html 헬퍼를 사용하지 않는 것으로 나타났습니다.

knockout.js와 함께 MVC의 두 기능을 어떻게 사용합니까?

나는 이 비디오를 찾았고 간단히 ( 비디오의 마지막 몇 분 @ 18:48) ViewModel에서 값을 할당받는 knockout.js 뷰 모델을 가진 인라인 스크립트를 기본적으로 사용하여 뷰 모델을 사용하는 방법으로갑니다.

이것을 할 수있는 유일한 방법입니까? 어떻게 내보기에서 그것에 뷰 모델의 컬렉션을 가지고 어떻습니까? foreach 루프 나 모든 값을 추출하여 녹아웃에 할당해야하는 것이 있습니까?

html 헬퍼에 관해서는 비디오는 그들에 대해 아무 말도하지 않습니다.

이것들은 많은 사람들이 그것에 대해 이야기하는 것처럼 보이지 않으므로 나와 혼란스럽게 만드는 2 가지 영역입니다. 예를 들어 하드 코딩 된 값 예제 일 때 초기 값과 모든 것이 어떻게 보이는지 혼란 스럽습니다.

편집하다

Darin Dimitrov가 제안한 것을 시도하고 있는데, 이것이 효과가있는 것처럼 보입니다. (나는 코드를 약간 수정해야했습니다.) 왜 내가 준비된 문서를 사용해야 만하는지 모르지만 어떻게 든 모든 것이 준비되지 않았다.

@model MvcApplication1.Models.Test

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <title>Index</title>
    <script src="../../Scripts/jquery-1.5.1.js" type="text/javascript"></script>
    <script src="../../Scripts/knockout-2.1.0.js" type="text/javascript"></script>
    <script src="../../Scripts/knockout.mapping-latest.js" type="text/javascript"></script>
   <script type="text/javascript">

   $(function()
   {
      var model = @Html.Raw(Json.Encode(Model));


// Activates knockout.js
ko.applyBindings(model);
   });

</script>

</head>
<body>
    <div>
        <p>First name: <strong data-bind="text: FirstName"></strong></p>
        <p>Last name: <strong data-bind="text: LastName"></strong></p>
        @Model.FirstName , @Model.LastName
    </div>
</body>
</html>

jquery 문서를 둘러 싸서 작동하도록했습니다.

나는 또한이 경고를 받는다. 모든 것이 무엇인지 확실하지 않습니다.

Warning 1   Conditional compilation is turned off   -> @Html.Raw

그래서 나는 좀 더 놀았을 때 그리고 이것이 어떻게 작동하는지 최소한 업데이트 할 것이라고 생각합니다.

나는 대화 형 튜토리얼을 살펴보고 대신 ViewModel을 사용하려고합니다.

이 부분에 아직 어떻게 대처할지 잘 모르겠다.

function AppViewModel() {
    this.firstName = ko.observable("Bert");
    this.lastName = ko.observable("Bertington");
}

또는

function AppViewModel() {
    // ... leave firstName, lastName, and fullName unchanged here ...

    this.capitalizeLastName = function() {
        var currentVal = this.lastName();        // Read the current value
        this.lastName(currentVal.toUpperCase()); // Write back a modified value
    };

편집 2

나는 첫 번째 문제를 파악할 수 있었다. 두 번째 문제에 대한 단서 없음. 그러나. 누구든지 아이디어가있어?

 @model MvcApplication1.Models.Test

    @{
        Layout = null;
    }

    <!DOCTYPE html>

    <html>
    <head>
        <title>Index</title>
        <script src="../../Scripts/jquery-1.5.1.js" type="text/javascript"></script>
        <script src="../../Scripts/knockout-2.1.0.js" type="text/javascript"></script>
        <script src="../../Scripts/knockout.mapping-latest.js" type="text/javascript"></script>
       <script type="text/javascript">

       $(function()
       {
        var model = @Html.Raw(Json.Encode(Model));
        var viewModel = ko.mapping.fromJS(model);
        ko.applyBindings(viewModel);

       });

    </script>

    </head>
    <body>
        <div>
            @*grab values from the view model directly*@
            <p>First name: <strong data-bind="text: FirstName"></strong></p>
            <p>Last name: <strong data-bind="text: LastName"></strong></p>

            @*grab values from my second view model that I made*@
            <p>SomeOtherValue <strong data-bind="text: Test2.SomeOtherValue"></strong></p>
            <p>Another <strong data-bind="text: Test2.Another"></strong></p>

            @*allow changes to all the values that should be then sync the above values.*@
            <p>First name: <input data-bind="value: FirstName" /></p>
            <p>Last name: <input data-bind="value: LastName" /></p>
            <p>SomeOtherValue <input data-bind="value: Test2.SomeOtherValue" /></p>
            <p>Another <input data-bind="value: Test2.Another" /></p>

           @* seeing if I can do it with p tags and see if they all update.*@
            <p data-bind="foreach: Test3">
                <strong data-bind="text: Test3Value"></strong> 
            </p>

     @*took my 3rd view model that is in a collection and output all values as a textbox*@       
    <table>
        <thead><tr>
            <th>Test3</th>
        </tr></thead>
          <tbody data-bind="foreach: Test3">
            <tr>
                <td>    
                    <strong data-bind="text: Test3Value"></strong> 
<input type="text" data-bind="value: Test3Value"/>
                </td>
            </tr>    
        </tbody>
    </table>

제어 장치

  public ActionResult Index()
    {
              Test2 test2 = new Test2
        {
            Another = "test",
            SomeOtherValue = "test2"
        };

        Test vm = new Test
        {
            FirstName = "Bob",
            LastName = "N/A",
             Test2 = test2,

        };
        for (int i = 0; i < 10; i++)
        {
            Test3 test3 = new Test3
            {
                Test3Value = i.ToString()
            };

             vm.Test3.Add(test3);
        }

        return View(vm);
    }

ASP.NET MVC 뷰 모델을 javascript 변수로 직렬화 할 수 있습니다.

@model CourseVM
<script type="text/javascript">
    var model = @Html.Raw(Json.Encode(Model));
    // go ahead and use the model javascript variable to bind with ko
</script>

녹아웃 문서 에는 많은 예제가 있습니다.


나는 내가 당신의 모든 질문을 요약했다고 생각한다. 만약 내가 뭔가를 놓쳤다면 나에게 알려주기 바란다. ( 한 곳에서 모든 질문을 요약 할 수 있다면 = 좋을 것이다. ))

노트. ko.editable 플러그인과의 호환성 추가

전체 코드 Download

knockout.js에서 html 헬퍼를 어떻게 사용합니까?

이것은 쉽다:

@Html.TextBoxFor(model => model.CourseId, new { data_bind = "value: CourseId" })

어디에:

  • value: CourseId 는 모델 및 스크립트 모델의 CourseId 속성을 사용하여 input 컨트롤의 value 속성을 바인딩한다는 것을 나타냅니다 value: CourseId

결과는 다음과 같습니다.

<input data-bind="value: CourseId" data-val="true" data-val-number="The field CourseId must be a number." data-val-required="The CourseId field is required." id="CourseId" name="CourseId" type="text" value="12" />

문서를 작동시키기 위해 준비가 필요한 이유 (자세한 내용은 첫 번째 편집 참조)

아직 모델을 직렬화하기 위해 ready 이벤트를 사용해야하는 이유를 이해하지 못한다.하지만 단순히 필요한 것 같다. (걱정하지 마라.)

내 뷰 모델과 녹아웃 매핑을 사용하는 경우 어떻게해야합니까? 필자는 매핑으로 인해 기능이 없습니다.

제대로 이해한다면 KO 모델에 새로운 방법을 추가해야합니다. 모델을 쉽게 병합 할 수 있습니다.

자세한 정보는 - 다른 출처에서의 매핑 -

function viewModel() {
    this.addStudent = function () {
        alert("de");
    };
};

$(function () {
    var jsonModel = '@Html.Raw(JsonConvert.SerializeObject(this.Model))';
    var mvcModel = ko.mapping.fromJSON(jsonModel);

    var myViewModel = new viewModel();
    var g = ko.mapping.fromJS(myViewModel, mvcModel);

    ko.applyBindings(g);
});

수신중인 경고 정보

경고 1 조건부 컴파일이 해제되어 있습니다 -> @ Html.Raw

따옴표를 사용해야합니다.

ko.editable 플러그인과의 호환성

좀 더 복잡해질 것이라고 생각했지만 모델을 편집 할 수있게하기 위해 통합이 정말 쉽다는 것을 알게되었습니다. (이 경우에는 서버와 서버의 혼합 모델을 사용하고 있습니다. 클라이언트의 확장 기능 추가 및 편집 기능은 간단하게 작동합니다 ...)

    ko.editable(g);
    ko.applyBindings(g);

여기에서 플러그인으로 추가 된 확장 기능을 사용하여 바인딩으로 연주 해야합니다. 예를 들어이 필드 편집을 시작하는 버튼이 있고이 버튼에서 편집 프로세스를 시작합니다.

    this.editMode = function () {
        this.isInEditMode(!this.isInEditMode());
        this.beginEdit();
    };

그런 다음 커밋 및 취소 단추가 다음 코드로 있습니다.

    this.executeCommit = function () {
        this.commit();
        this.isInEditMode(false);
    };
    this.executeRollback = function () {
        if (this.hasChanges()) {
            if (confirm("Are you sure you want to discard the changes?")) {
                this.rollback();
                this.isInEditMode(false);
            }
        }
        else {
            this.rollback();
            this.isInEditMode(false);
        }
    };

마지막으로 필드가 편집 모드인지 여부를 나타내는 하나의 필드가 있습니다.이 필드는 enable 속성을 바인딩하는 것입니다.

this.isInEditMode = ko.observable(false);

배열 질문에 관하여

저는 몇몇의 foreach 루프 나 Student View Models 컬렉션에서 데이터를 가져올 수있는 것이 있습니다.

그런 다음 폼을 제출할 때 jquery를 사용하여 배열을 serialize하고 컨트롤러 동작 메서드로 보내면 뷰 모델로 다시 바인드됩니다.

다음 예제에서 KO로 동일한 작업을 수행 할 수 있습니다. 다음 출력을 만듭니다.

기본적으로 Helpers 사용하여 생성되고 KO로 바인드 된 두 개의 목록이 있습니다.이 목록은 Controller 게시 할 때 현재 목록에서 선택된 항목을 제거하고 다른 목록에 추가하는 dblClick 이벤트 dblClick . 각 목록의 내용은 JSON 데이터로 보내 져서 서버 모델에 다시 첨부됩니다.

너겟 :

외부 scripts .

컨트롤러 코드

    [HttpGet]
    public ActionResult Index()
    {
        var m = new CourseVM { CourseId = 12, CourseName = ".Net" };

        m.StudentViewModels.Add(new StudentVm { ID = 545, Name = "Name from server", Lastname = "last name from server" });

        return View(m);
    }

    [HttpPost]
    public ActionResult Index(CourseVM model)
    {
        if (!string.IsNullOrWhiteSpace(model.StudentsSerialized))
        {
            model.StudentViewModels = JsonConvert.DeserializeObject<List<StudentVm>>(model.StudentsSerialized);
            model.StudentsSerialized = string.Empty;
        }

        if (!string.IsNullOrWhiteSpace(model.SelectedStudentsSerialized))
        {
            model.SelectedStudents = JsonConvert.DeserializeObject<List<StudentVm>>(model.SelectedStudentsSerialized);
            model.SelectedStudentsSerialized = string.Empty;
        }

        return View(model);
    }

모델

public class CourseVM
{
    public CourseVM()
    {
        this.StudentViewModels = new List<StudentVm>();
        this.SelectedStudents = new List<StudentVm>();
    }

    public int CourseId { get; set; }

    [Required(ErrorMessage = "Course name is required")]
    [StringLength(100, ErrorMessage = "Course name cannot be this long.")]
    public string CourseName { get; set; }

    public List<StudentVm> StudentViewModels { get; set; }
    public List<StudentVm> SelectedStudents { get; set; }

    public string StudentsSerialized { get; set; }
    public string SelectedStudentsSerialized { get; set; }
}

public class StudentVm
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Lastname { get; set; }
}

CSHTML 페이지

@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>CourseVM</legend>

        <div>
            <div class="editor-label">
                @Html.LabelFor(model => model.CourseId)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(model => model.CourseId, new { data_bind = "enable: isInEditMode, value: CourseId" })
                @Html.ValidationMessageFor(model => model.CourseId)
            </div>

            <div class="editor-label">
                @Html.LabelFor(model => model.CourseName)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(model => model.CourseName, new { data_bind = "enable: isInEditMode, value: CourseName" })
                @Html.ValidationMessageFor(model => model.CourseName)
            </div>
            <div class="editor-label">
                @Html.LabelFor(model => model.StudentViewModels);
            </div>
            <div class="editor-field">

                @Html.ListBoxFor(
                    model => model.StudentViewModels,
                    new SelectList(this.Model.StudentViewModels, "ID", "Name"),
                    new
                    {
                        style = "width: 37%;",
                        data_bind = "enable: isInEditMode, options: StudentViewModels, optionsText: 'Name', value: leftStudentSelected, event: { dblclick: moveFromLeftToRight }"
                    }
                )
                @Html.ListBoxFor(
                    model => model.SelectedStudents,
                    new SelectList(this.Model.SelectedStudents, "ID", "Name"),
                    new
                    {
                        style = "width: 37%;",
                        data_bind = "enable: isInEditMode, options: SelectedStudents, optionsText: 'Name', value: rightStudentSelected, event: { dblclick: moveFromRightToLeft }"
                    }
                )
            </div>

            @Html.HiddenFor(model => model.CourseId, new { data_bind="value: CourseId" })
            @Html.HiddenFor(model => model.CourseName, new { data_bind="value: CourseName" })
            @Html.HiddenFor(model => model.StudentsSerialized, new { data_bind = "value: StudentsSerialized" })
            @Html.HiddenFor(model => model.SelectedStudentsSerialized, new { data_bind = "value: SelectedStudentsSerialized" })
        </div>

        <p>
            <input type="submit" value="Save" data-bind="enable: !isInEditMode()" /> 
            <button data-bind="enable: !isInEditMode(), click: editMode">Edit mode</button><br />
            <div>
                <button data-bind="enable: isInEditMode, click: addStudent">Add Student</button>
                <button data-bind="enable: hasChanges, click: executeCommit">Commit</button>
                <button data-bind="enable: isInEditMode, click: executeRollback">Cancel</button>
            </div>
        </p>
    </fieldset>
}

스크립트

<script src="@Url.Content("~/Scripts/jquery-1.7.2.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/knockout-2.1.0.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/knockout.mapping-latest.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/ko.editables.js")" type="text/javascript"></script>

<script type="text/javascript">
    var g = null;
    function ViewModel() {
        this.addStudent = function () {
            this.StudentViewModels.push(new Student(25, "my name" + new Date(), "my last name"));
            this.serializeLists();
        };
        this.serializeLists = function () {
            this.StudentsSerialized(ko.toJSON(this.StudentViewModels));
            this.SelectedStudentsSerialized(ko.toJSON(this.SelectedStudents));
        };
        this.leftStudentSelected = ko.observable();
        this.rightStudentSelected = ko.observable();
        this.moveFromLeftToRight = function () {
            this.SelectedStudents.push(this.leftStudentSelected());
            this.StudentViewModels.remove(this.leftStudentSelected());
            this.serializeLists();
        };
        this.moveFromRightToLeft = function () {
            this.StudentViewModels.push(this.rightStudentSelected());
            this.SelectedStudents.remove(this.rightStudentSelected());
            this.serializeLists();
        };
        this.isInEditMode = ko.observable(false);
        this.executeCommit = function () {
            this.commit();
            this.isInEditMode(false);
        };
        this.executeRollback = function () {
            if (this.hasChanges()) {
                if (confirm("Are you sure you want to discard the changes?")) {
                    this.rollback();
                    this.isInEditMode(false);
                }
            }
            else {
                this.rollback();
                this.isInEditMode(false);
            }
        };
        this.editMode = function () {
            this.isInEditMode(!this.isInEditMode());
            this.beginEdit();
        };
    }

    function Student(id, name, lastName) {
        this.ID = id;
        this.Name = name;
        this.LastName = lastName;
    }

    $(function () {
        var jsonModel = '@Html.Raw(JsonConvert.SerializeObject(this.Model))';
        var mvcModel = ko.mapping.fromJSON(jsonModel);

        var myViewModel = new ViewModel();
        g = ko.mapping.fromJS(myViewModel, mvcModel);

        g.StudentsSerialized(ko.toJSON(g.StudentViewModels));
        g.SelectedStudentsSerialized(ko.toJSON(g.SelectedStudents));

        ko.editable(g);
        ko.applyBindings(g);
    });
</script>

참고 : 방금 추가 한 행은 다음과 같습니다.

        @Html.HiddenFor(model => model.CourseId, new { data_bind="value: CourseId" })
        @Html.HiddenFor(model => model.CourseName, new { data_bind="value: CourseName" })

필드를 사용할 수없는 양식을 제출할 때 값이 서버로 전송되지 않았기 때문에 숨겨진 필드를 추가하여 트릭을 수행했습니다.





knockout.js