Как использовать knockout.js с ASP.NET MVC ViewModels?

Bounty

Это было некоторое время, и у меня все еще есть пара нерешенных вопросов. Я надеюсь, что добавив награду, возможно, на эти вопросы ответят.

How do you use html helpers with knockout.js

Why was document ready needed to make it work(see first edit for more information)

How do I do something like this if I am using the knockout mapping with my view models? As I do not have a function due to the mapping.

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

};

I want to use plugins for instance I want to be able to rollback observables as if a user cancels a request I want to be able to go back to the last value. From my research this seems to be achieved by people making plugins like editables

How do I use something like that if I am using mapping? I really don’t want to go to a method where I have in my view manual mapping were I map each MVC viewMode field to a KO model field as I want as little inline javascript as possible and that just seems like double the work and that’s why I like that mapping.

I am concerned that to make this work easy (by using mapping) I will lose a lot of KO power but on the other hand I am concerned that manual mapping will just be a lot of work and will make my views contain too much information and might become in the future harder to maintain(say if I remove a property in the MVC model I have to move it also in the KO viewmodel)

Original Post

Я использую 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; }

}

Я хотел бы иметь Vm, который имеет некоторые основные свойства, такие как CourseName, и поверх него будет простая проверка. Модель Vm может содержать и другие модели представлений, если это необходимо.

Затем я передал бы этот Vm в представление, где бы я использовал помощники HTML, чтобы помочь мне показать его пользователю.

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

У меня могут быть какие-то циклы foreach или что-то еще, чтобы вытащить данные из коллекции моделей просмотра учеников.

Затем, когда я отправлю форму, я буду использовать jquery иserialize array и отправьте его в метод действия контроллера, который связал бы его с моделью представления.

С knockout.js все по-другому, так как теперь у вас есть для него модели представления, и из всех примеров, которые я видел, они не используют помощников html.

Как вы используете эти 2 функции MVC с knockout.js?

я нашел это видео и вкратце (последние несколько минут видео @ 18:48) идет речь о том, как использовать view-модели, в основном имея встроенный скрипт, который имеет view-модель knockout.js, которой присваиваются значения в ViewModel.

Это единственный способ сделать это? Как насчет моего примера с коллекцией моделей в нем? Должен ли я иметь цикл foreach или что-то еще, чтобы извлечь все значения и назначить их в нокаут?

Что касается помощников HTML, видео ничего не говорит о них.

Это две области, которые сбивают меня с толку, поскольку не многие люди, кажется, говорят об этом, и это оставляет меня в замешательстве из-за того, как исходные значения и все остальное попадает в поле зрения, когда пример - это просто какой-то жестко заданный пример значения.

Edit

Я пробую то, что предложил Дарин Димитров, и это, кажется, работает (хотя мне пришлось внести некоторые изменения в его код). Не уверен, почему я должен был использовать готовый документ, но почему-то все было не готово без него.

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

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

Ответы на вопрос(3)

Ваш ответ на вопрос