Como usar o knockout.js com o ASP.NET MVC ViewModels?

Recompensa

Já faz algum tempo e ainda tenho algumas perguntas pendentes. Espero que, adicionando uma recompensa, talvez essas perguntas sejam respondidas.

Como você usa os ajudantes html com o knockout.js

Por que o documento estava pronto para funcionar (veja a primeira edição para mais informações)

Como faço algo assim se estiver usando o mapeamento de eliminação com meus modelos de visualização? Como eu não tenho uma função devido ao mapeamento.

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

};

Eu quero usar plugins, por exemplo, eu quero ser capaz de reverter observables como se um usuário cancela um pedido que eu quero ser capaz de voltar para o último valor. De minha pesquisa, isso parece ser alcançado por pessoas fazendo plugins comoeditáveis

Como faço para usar algo assim se estiver usando mapeamento? Eu realmente não quero ir para um método onde eu tenho na minha opinião mapeamento manual foram mapear cada campo viewMode MVC para um campo de modelo KO como eu quero o menor javascript inline possível e que apenas parece que o dobro do trabalho e que é porque eu gosto desse mapeamento.

Preocupa-me que, para facilitar este trabalho (usando o mapeamento), perderei muito poder de KO, mas, por outro lado, estou preocupado com o facto de o mapeamento manual ser muito trabalhoso e fazer com que as minhas visualizações contenham demasiada informação. pode se tornar no futuro mais difícil de manter (digamos que se eu remover uma propriedade no modelo MVC eu tenho que movê-lo também no modelo de view KO)

Post original

Eu estou usando o asp.net mvc 3 e estou olhando para nocaute como parece muito legal, mas eu estou tendo dificuldade em descobrir como ele funciona com o asp.net mvc especialmente ver modelos.

Para mim agora eu faço algo assim

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

}

Eu teria um Vm que tem algumas propriedades básicas como CourseName e terá alguma validação simples em cima dele. O modelo Vm também pode conter outros modelos de visualização, se necessário.

Eu passaria este Vm para o View se eu usasse helpers html para me ajudar a mostrá-lo ao usuário.

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

Eu poderia ter alguns loops foreach ou algo para obter os dados da coleção de modelos de visão de estudante.

Então, quando eu enviaria o formulário, usaria jquery eserialize array e enviá-lo para um método de ação do controlador que o ligaria de volta ao viewmodel.

Com o knockout.js é tudo diferente, já que agora você tem modelos de visualização para ele e, de todos os exemplos que vi, eles não usam helpers html.

Como você usa esses dois recursos do MVC com o knockout.js?

eu encontreiesse vídeo e brevemente (últimos minutos do vídeo @ 18: 48) entra em uma maneira de usar viewmodels basicamente tendo um script in-line que possui o viewmodel knockout.js que é atribuído aos valores no ViewModel.

Esta é a única maneira de fazer isso? Que tal no meu exemplo ter uma coleção de modelos de visão? Eu tenho que ter um loop foreach ou algo para extrair todos os valores e atribuí-lo em nocaute?

Quanto aos ajudantes html, o vídeo não diz nada sobre eles.

Essas são as duas áreas que me confundem, já que muitas pessoas não parecem falar sobre isso e me deixa confuso sobre como os valores iniciais e tudo estão chegando à visão quando o exemplo é apenas um exemplo de valor codificado.

Editar

Eu estou tentando o que Darin Dimitrov sugeriu e isso parece funcionar (eu tive que fazer algumas mudanças em seu código). Não tenho certeza porque eu tive que usar o documento pronto, mas de alguma forma tudo não estava pronto sem ele.

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

Eu tive que envolvê-lo em torno de um documento de jquery pronto para fazer o trabalho.

Eu também recebo este aviso. Não tenho certeza do que se trata.

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

Então eu tenho um ponto de partida que eu acho que pelo menos atualizarei quando eu fizer mais algumas coisas e como isso funciona.

Eu estou tentando percorrer os tutoriais interativos, mas use o ViewModel em vez disso.

Não tenho certeza de como lidar com essas partes ainda

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

ou

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

Editar 2

Eu fui capaz de descobrir o primeiro problema. Nenhuma pista sobre o segundo problema. Ainda assim. Alguém tem alguma ideia?

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

Controlador

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

questionAnswers(3)

yourAnswerToTheQuestion